А. В. Комаров цифровые сигнальные процессоры

Вид материалаДокументы
Б) вычисления с пересылкой регистр-регистр
Флаги состояния
Флаги состояния SSTAT
Б) управление режимом работы процессора
Флаги состояния
Флаги состояния
1.18. Инструментальные средства разработки программного обеспечения
1.18.1. Инструментальные средства для DOS
1.18.2. Инструментальные средства для WINDOWS
1.18.3. Создание проекта в VisualDSP
1.18.4. Загрузка программы в EZ-KIT Lite
1.19. Примеры программирования в среде VisualDSP
Подобный материал:
1   ...   16   17   18   19   20   21   22   23   ...   26

Флаги состояния: флаги устанавливаются арифметическими командами, как они устанавливаются в не многофункциональных командах (см. пп. 1.17.5-1.17.7).


Б) ВЫЧИСЛЕНИЯ С ПЕРЕСЫЛКОЙ РЕГИСТР-РЕГИСТР




, dreg = dreg

;






















Синтаксис:


Допустимые регистры dreg см. п. 1.17.9.А.


Пример: AR = AX0 + AY0, AX0 = MR1;


Описание: Процессор выполняет означенную арифметическую операцию одновременно с пересылкой данного. Содержимое источника записывается в регистр назначения всегда с правым выравниванием. Справедливы все положения п. 1.17.9.А.


Флаги состояния: флаги устанавливаются арифметическими командами, как они устанавливаются в не многофункциональных командах (см. пп. 1.17.5-1.17.7).


В) ВЫЧИСЛЕНИЯ С ЗАПИСЬЮ В ПАМЯТЬ


DM(




I0

,

M0




)

= dreg,



;







I1




M1





















I2




M2





















I3




M3




















































I4




M4






















I5




M5






















I6




M6






















I7




M7














































PM(




I4

,

M4




)
















I5




M5






















I6




M6






















I7




M7





















Синтаксис:


Допустимые dreg см. п. 1.17.9.А.


Описание: Команда выполняет означенную арифметическую операцию одновременно с пересылкой данного. Операция записи пересылает содержимое регистра источника в память назначения. Метод адресации только регистровый косвенный с последующей модификацией содержимого I регистра. Для линейной (не кольцевой) адресации L регистр, соответствующий I регистру, должен быть обнулен. Содержимое источника записывается в регистр назначения всегда с правым выравниванием.

Операция вычисления должна быть безусловной. Допустимы все команды ALU, MAC и SHIFTER кроме команд непосредственных сдвигов, а также команд DIVS и DIVQ.

Фундаментальным принципом выполнения многофункциональных команд является то, что регистры (и память) считываются в начале цикла выполнения команда, а записываются в конце. Для реализации этого принят обычный (слева направо) порядок записи составляющих элементов команды: сначала операция записи памяти, а затем арифметическая операция. Программист может нарушить этот порядок записи, но ассемблер, выдав предупреждение, сгенерирует одинаковый машинный код. Выдачу предупреждения можно подавить, отключив проверку семантики с помощью ключа s.

Принятый порядок доступа к регистрам данных вычислительных устройств (сначала считывание, потом запись) позволяет использовать один и тот же регистр в качестве источника для одной операции и приемника для другой. Например, команда


DM(I0, M0) = AR, AR = AX0 + AY0;


является правильной, причем содержимое АR сначала считывается для записи в память, а затем записывается (загружается) в ходе выполнения арифметической операции. Можно эту команду записать в обратном порядке


AR = AX0 + AY0, DM(I0, M0) = AR;


но ассемблер, выдав предупреждение, сформирует такой же машинный код команды как в первом примере.


Флаги состояния: флаги устанавливаются арифметическими командами, как они устанавливаются в не многофункциональных командах (см. пп. 1.17.5-1.17.7).


Г) ЧТЕНИЕ ПД И ПП


Синтаксис:

AX0

= DM (

I0

,

M0

),

AY0

= PM (

I4

,

M4

);

AX1




I1




M1




AY1




I5




M5




MX0




I2




M2




MY0




I6




M6




MX1




I3




M3




MY1




I7




M7





Описание: Команда производит одновременно две операции чтения памяти: чтение ПД и чтение ПП. Каждая из этих операций пересылает содержимое ячеек памяти ПД и ПП в регистры назначения, заданные в команде. При этом содержимое ПД пересылается в Х регистры ALU и МАС, а содержимое ПП – в Y регистры ALU и МАС.

Метод адресации только регистровый косвенный с последующей модификацией содержимого I регистра. Для линейной (не кольцевой) адресации L регистр, соответствующий I регистру, должен быть обнулен. Содержимое источника записывается в регистр назначения всегда с правым выравниванием.

На самом деле необходимо считать три слова: два операнда и саму команду. Если не используется внешняя память, то такое считывание происходит за один машинный цикл.

Если из внешней памяти необходимо считать два слова, например, команду и данное или два слова данных из ПД и ПП, то для выполнения команды необходим еще один дополнительный цикл. Если из внешней памяти необходимо считать три слова (команда и два слова данных), то требуется два дополнительных цикла.


Флаги состояния: не изменяются.


Д) ВЫЧИСЛЕНИЯ С ЧТЕНИЕМ ПД И ПП


Синтаксис:



,

AX0

= DM (

I0

,

M0

),

AY0

= PM (

I4

,

M4

);






AX1




I1




M1




AY1




I5




M5










MX0




I2




M2




MY0




I6




M6










MX1




I3




M3




MY1




I7




M7





Описание: Команда одновременно производит операцию вычисления в ALU или MAC и две операции чтения памяти: чтение ПД и чтение ПП. Каждая из пересылочных операций пересылает содержимое ячеек памяти ПД и ПП в регистры назначения, заданные в команде. При этом содержимое ПД пересылается в Х регистры ALU и МАС, а содержимое ПП – в Y регистры ALU и МАС.

Метод адресации только регистровый косвенный с последующей модификацией содержимого I регистра. Для линейной (не кольцевой) адресации L регистр, соответствующий I регистру, должен быть обнулен. Содержимое источника записывается в регистр назначения всегда с правым выравниванием.

На самом деле необходимо считать три слова: два операнда и саму команду. Если не используется внешняя память, то такое считывание происходит за один машинный цикл.

Если из внешней памяти необходимо считать два слова, например, команду и данное или два слова данных из ПД и ПП, то для выполнения команды необходим еще один дополнительный цикл. Если из внешней памяти необходимо считать три слова (команда и два слова данных), то требуется два дополнительных цикла.

Операция вычисления должна быть безусловной. Допустимы все команды ALU, MAC кроме команд непосредственных сдвигов, а также команд DIVS и DIVQ. Результаты вычислений должны быть записаны в регистры результатов вычислительных блоков: результаты ALU в AR, результаты МАС в MR.

Фундаментальным принципом выполнения многофункциональных команд является то, что регистры (и память) считываются в начале цикла выполнения команда, а записываются в конце. Для реализации этого принят обычный (слева направо) порядок записи составляющих элементов команды: сначала арифметическая операция, а затем операции чтения. Программист может нарушить этот порядок записи, но ассемблер, выдав предупреждение, сгенерирует одинаковый машинный код. Выдачу предупреждения можно подавить, отключив проверку семантики с помощью ключа s.

Принятый порядок доступа к регистрам данных вычислительных устройств (сначала считывание, потом запись) позволяет использовать один и тот же регистр в качестве источника для одной операции и приемника для другой. Например, команда


MR=MR+MX0*MY0(UU), MX0 = DM(I0, M0), MY0 = DM(I4, M4);


является правильной, причем содержимое регистров MХ0 и MY0 сначала считывается для выполнения арифметической операции, а затем записывается операциями пересылки. Можно эту команду записать в обратном порядке


MX0 = DM(I0, M0), MY0 = DM(I4, M4), MR=MR+MX0*MY0(UU);


но ассемблер, выдав предупреждение, сформирует такой же машинный код команды как в первом примере.


Флаги состояния: флаги устанавливаются арифметическими командами, как они устанавливаются в не многофункциональных командах (см. пп. 1.17.5-1.17.7).


1.17.10. Прочие команды


А) УПРАВЛЕНИЕ СТЕКАМИ


[

PUSH

STS][, POP CNTR][, POP PC][, POP LOOP];




POP









Синтаксис:


Пример: POP CNTR, POP PC, POP LOOP;


Описание: Команда управления стеками производит запись и считывание стеков с соответствующей коррекцией указателей стеков. Команда выполняется за один машинной цикл, не смотря на количество указанных в ней стеков

Команда PUSH STS инкрементирует указатель STATUS стека, а затем по новому адресу записывает в стек содержимое следующих регистров: ASTAT, MSTAT и IMASK. Эта команда выполняется автоматически, когда происходит вход в обработчик прерывания.

Все команды POP производят считывание с вершины означенного стека с последующим декрементированием указателя стека. Отличие команды POP STS заключается в том, что она считывает сразу три стека с загрузкой следующих регистров: ASTAT, MSTAT и IMASK. Эта команда выполняется автоматически, когда происходит выход из обработчика прерывания (выполняется команда RTI).

РС стек автоматически считывается при выполнении команд RTI и RTS.


Флаги состояния SSTAT:

SSTAT:

7

6

5

4

3

2

1

0




LSO

LSE

SSO

SSE

CSO

CSE

PSO

PSE




-

*

*

*

-

*

-

*

PSE – РС стек пуст: устанавливается, если после очередной операции POP стек РС становится пустым, в противном случае сбрасывается.

CSE – стек счетчика циклов пуст: устанавливается, если после очередной операции POP стек счетчика циклов становится пустым, в противном случае сбрасывается.

SSE – STATUS стек пуст: для PUSH STS этот бит всегда сбрасывается (что говорит о не пустом стеке); для POP STS этот бит устанавливается, если после очередной POP операции STATUS стек становится пустым, в противном случае сбрасывается.

SSO – переполнение STATUS стека: для PUSH STS устанавливается при переполнении STATUS стека, а противном случае не изменяется.

LSE – LOOP стек пуст: устанавливается, если после очередной POP операции LOOP стек становится пустым, в противном случае сбрасывается.

Примечание: если происходит переполнение стека, то устанавливается соответствующий ххО бит в регистре SSTAT, как сигнал о потере информации. Сброс этого бита возможен только сбросом процессора.


Процессор поддерживает специальную версию команды пересылки регистр-регистр – TOPPCSTACK. Она позволяет при операциях с РС стеком быть назначением не только РС (как в стандартной команде POP РС), но множеству других регистров. Для считывания с вершины РС стека (с соответствующей коррекцией указателя стека) можно написать:


reg = TOPPCSTACK; {РС стек считывается в регистр reg}

NOP; {необходима для корректного завершения считывания }


Кроме того, нет стандартной команды PUSH PC. Чтобы записать в РС стек определенное значение, можно выполнить следующее:


TOPPCSTACK = reg;


При этом стек загрузится (с соответствующей коррекцией указателя стека) содержимым reg за один цикл (не надо давать NOP;).


Примечание: в других контекстах использовать TOPPCSTACK запрещается.


Примеры: АХ0 = TOPPCSTACK; {считывание РС в АХ0}

NOP;


TOPPCSTACK = I7; {запись содержимого I7 в РС стек}


Для команды TOPPCSTACK доступны только следующие регистры: AX0, AX1, AY0, AY1, AR, MX0, MX1, MY0, MY1, MR0, MR1, MR2, SI, SE, SR0, SR1, I0-I7, M0-M7, L0-L7. Необходимо учитывать также следующие ограничения:
  • Команда TOPPCSTACK не может быть размещена непосредственно перед командой RTI, они должны разделяться хотя бы одной командой NOP;
  • Команда TOPPCSTACK не может быть последней (и даже предпоследней) командой в теле цикла DO UNTIL;
  • Внутри цикла DO UNTIL должно быть одинаковое число записей/чтений РС стека с учетом использования как обычных команд доступа к РС стеку, так и команды TOPPCSTACK.



Б) УПРАВЛЕНИЕ РЕЖИМОМ РАБОТЫ ПРОЦЕССОРА


ENA




BIT_REV

[, …];

DIS




AV_LATCH










AR_SAT










SEC_REG










G_MODE










M_MODE










TIMER









Синтаксис:


Пример: DIS AR_SAT, ENA M_MODE;


Описание: Команда устанавливает (ENA) или (DIS) запрещает означенный режим работы процессора. При этом соответствующий бит режима в регистре состояния режима процессора (MSTAT) устанавливается командой ENA или сбрасывается командой DIS. После сброса процессора регистр MSTAT обнулен, поэтому все режимы работы процессора запрещены. Командой можно изменить любое число режимов за один машинный цикл. При этом команды ENA и DIS должны разделяться запятыми.

Названия битов команды являются синонимами названий битов регистра MSTAT (см. табл. 1.12): BIT_REV – RME; AV_LATCH –OLME; AR_SAT – SME; SEG_REG – DRBS; G_MODE – GME; M_MODE – MRP; TIMER – TE. Функциональное назначение этих битов описано в п. 1.10.


В) МОДИФИКАЦИЯ АДРЕСНЫХ РЕГИСТРОВ


MODIFY(




I0

,

M0




);







I1




M1













I2




M2













I3




M3


































I4




M4













I5




M5













I6




M6













I7




M7












Синтаксис:


Пример: MODIFY (I1, M1);


Описание: Команда производит сложение содержимого выбранного I регистра с содержимым выбранного М регистра. Между суммой и содержимым L регистра производится операция модуля, результат этой опе­рации сохраняется в I регистре. Для линейной (не кольцевой) адресации L регистр, соответствующий I регистру, должен быть обнулен. Допускается комбинировать I и М регистры, принадлежащие одному и тому же DAG.


Флаги состояния: не изменяются.


Г) НЕТ ОПЕРАЦИИ


Синтаксис: NOP;


Описание: При выполнении команды никакой операции не производится. Команда выполняется за один машинный цикл.


Флаги состояния: не изменяются.


Д) РАЗРЕШЕНИЕ/ЗАПРЕЩЕНИЕ ПРЕРЫВАНИЙ


Синтаксис: ENA INTS;

DIS INTS;


Описание: После сброса процессора все прерывания по умолчанию разрешены. После выполнения команды DIS INTS все прерывания замаскированы (включая прерывание powerdown) без изменения содержимого регистра IMASK.

Команда ENA INTS разрешает обслуживание всех незамаскированных прерываний.

Примечание: запрет прерываний не влияет на автобуферицацию последовательных портов и BDMA, IDMA пересылки.


Флаги состояния: не изменяются.


1.18. Инструментальные средства разработки программного обеспечения


К инструментальным средствам разработки программного обеспечения ADSP-2181 относятся: компиляторы языка высокого уровня (обычно СИ), ассемблер, линкер и сплиттер (утилита, позволяющая готовить программу для ее загрузки из БП (см. п. 1.15.4)). Такие средства разработаны как для операционной среды DOS, так и для операционной среды WINDOWS.


1.18.1. Инструментальные средства для DOS


К этим средствам относятся: компилятор языка СИ – G21.exe, ассемблер – asm21.exe, симулятор – sym2181.exe, линкер – ld21.exe, сплиттер – spl21.exe и EzKitapp.exe – загрузчик программ в EZ-KIT Lite. Установка этих программных продуктов, а также описание ключей для их запуска из командной строки DOS (кроме СИ) приводится в [2].

Кроме этого, в директории d:\Adi_Dsp\21xx\Ezkitl (где d – символ диска, на котором расположены инструментальные средства для DOS) приводится множество примеров использования перечисленных инструментальных средств, а в директории d:\Adi_Dsp\21xx\Lib расположен файл архитектуры Adsp2181.ach отладочного стенда EZ-KIT Lite. Имеются примеры программирования также в [2].

В настоящем пособии также приводятся примеры программирования с использованием инструментальных средств для DOS (см. пп. 1.8, 1.11.1, 1.12.3, 1.12.6). Всех этих примеров достаточно для успешного программирования ADSP-2181 в операционной среде DOS.


1.18.2. Инструментальные средства для WINDOWS


Инструментальным средством для WINDOWS является среда программирования [4] под названием VusualDSP. Компилятор СИ, ассемблер, линкер, симулятор и сплиттер инкапсулированы (внедрены) в эту среду вместе с редактором текста, с помощью которого можно создавать программы.

Среда кроме меню содержит три окна: левое, правое и нижнее. Левое окно (окно проекта) отражает состав проекта (перечень всех файлов, включенных в проект). Правое окно (окно редактирования) является окном редактора текста, в котором находится выбранный файл, входящий в состав проекта. Нижнее окно (окно статуса программы) отражает протокол компилирования файлов проекта. Если есть ошибки (синтаксические, отсутствие определенных программой файлов и т.п.), то их перечень появляется именно в этом окне.


1.18.3. Создание проекта в VisualDSP


Любая программа для ADSP-2181 должна быть частью проекта. Создание проекта осуществляется за несколько шагов:
  • В меню выбрать File | New, появится форма с заголовком Новый документ;
  • Из списка выбрать Project, появится форма с заголовком Сохранение;
  • В этой форме указать директорию, в которой будет сохранен проект;
  • В окне редактирования Имя файла ввести имя файла проекта, например, Async (это имя появится в окне проекта рядом с фирменным голубым треугольником). Появится форма с заголовком Project Option. Форма содержит несколько закладок, на каждой из которых можно задать ту или иную опцию проекта. Существенно задать тип процессора ADSP-2181, что можно сделать на закладке Pro­ject. На этой же закладке следует выбрать тип генерируемого компилятором файла – DSP executable file. Все остальные опции можно оставить без изменения.

Все файлы проекта можно создать выбором File | New. При этом будет появляться форма с заголовком Новый документ, в которой необходимо выбрать Editor File. Окно редактора очистится (или останется пустым) и ему будет присвоено имя Untitled Edit1. Это имя следует заменить на значимое с помощью выбора File | Save As. Новое имя будет фигурировать в заголовке формы VisualDSP.

Далее вновь образованный файл следует подключить к проекту. Это осуществляется с помощью выбора Project | Add to Project | File(s). Вновь созданный файл подключится к проекту, а его имя появится в окне проекта. Каждому вновь подключенному файлу можно назначить уникальные опции. Для этого его надо отметить щелчком мыши в окне проекта, а затем выбрать Project | File Option. Новые опции назначаются на появившейся форме. Для установки/назначения опций всего проекта необходимо в окне проекта щелчком мыши отметить имя проекта, а затем сделать выбор Project | Project Option. Новые опции назначаются на появившейся форме, которая имеет вид совокупности закладок (см. выше).

Таким же образом к проекту можно подключить уже существующий файл. Для этого необходимо использовать выбор File | Open. Если подключенный файл пуст (новый), то, используя встроенный редактор, в него можно записать программу (на языке СИ или ассемблере) или директивы линкерного файла. Далее проект компилируется с помощью выбора Project | Build Project или Project | Rebuild All. Созданный файл исполняемой программы загружается в EZ-KIT Lite на исполнение.

Следует помнить, что в файле autoexec.bat должны быть записи:
  • SET PATH=”d:\VisualDSP”;%PATH%
  • SET PATH=”d:\VisualDSP\System”;%PATH%

где d – обозначение диска со средой VisualDSP.


1.18.4. Загрузка программы в EZ-KIT Lite


Загрузчиком в EZ-KIT Lite является приложение EzKitapp.exe, которое входит в состав инструментальных средств для DOS (см. п. 1.18.1). Особенностью загрузчика является то, что он загружает исполняемые файлы с расширением ехе. Такие файлы формирует линкер ld21.exe, входящий в состав инструментальных средств для DOS (см. п. 1.18.1).

Среда VisualDSP формирует исполняемые файлы с расширением dxe, формат которых отличается от формата файлов ехе. Это делает невозможным загрузку dxe файлов приложением EzKitapp.exe. Проблема может быть решена с помощью конвертера elf2aexe.exe, который входит в состав модернизированной библиотеки elf2aexe.dll.

Для упрощения использования конвертора можно создать bat-файл с именем dxe2exe.bat, в который поместить следующую строку текста:

elf2aexe -x debug\%1

Это справедливо, если на закладке Project опций проекта в разделе Setting for configuration определена директория debug. Сам bat-файл следует поместить в директорию d:\VisualDSP\System. Далее на закладке Post Build опций проекта следует определить строку dxe2exe.bat dxe_name, где dxe_name – имя файла с расширением dxe (само расширение не писать).

Теперь после каждой компиляции в директории debug будут находиться файлы с расширением dxe и ехе. Это дает возможность воспользоваться приложением EzKitapp.exe для загрузки в EZ-KIT Lite вновь созданной программы.


1.19. Примеры программирования в среде VisualDSP


1.19.1. Формирование эхо-сигнала


Задание: с помощью EZ-KIT Lite на выходе кодека AD1847 [5] (далее просто – кодек) сформировать эхо-сигнал от микрофона, подключенного ко входу кодека.

Метод решения: адаптировать для VisualDSP программу, которая приведена в [2].

Пример иллюстрирует приемы работы с кодеком: инициализацию, прием и выдачу данных. Приведенная программа может служить основой для множества приложений, связанных с формированием и обработкой звуковых сигналов.

Создадим проект с именем echo, в который входят два файла: echo.asm и echo.ldf. Первый из них является файлом программы, а второй – линкерным файлом. К файлу программы подключается файл (Reg2181.inc) определений адресов регистров процессора ADSP-2181. Этот файл может подключаться к любой программе для указанного процессора. Его текст приводится на рис. 1.14. Важное примечание: VisualDSP не допускает использование символов русского алфавита, поэтому комментарии на русском языке приведены условно.


//---------- Содержимое файла Reg2181.inc


// Объявление констант

#define IDMA 0x3fe0

#define BDMA_BIAD 0x3fe1

#define BDMA_BEAD 0x3fe2

#define BDMA_BDMA_Ctrl 0x3fe3

#define BDMA_BWCOUNT 0x3fe4

#define PFDATA 0x3fe5

#define PFTYPE 0x3fe6

#define SPORT1_Autobuf 0x3fef

#define SPORT1_RFSDIV 0x3ff0

#define SPORT1_SCLKDIV 0x3ff1

#define SPORT1_Control_Reg 0x3ff2

#define SPORT0_Autobuf 0x3ff3

#define SPORT0_RFSDIV 0x3ff4

#define SPORT0_SCLKDIV 0x3ff5

#define SPORT0_Control_Reg 0x3ff6

#define SPORT0_TX_Channels0 0x3ff7

#define SPORT0_TX_Channels1 0x3ff8

#define SPORT0_RX_Channels0 0x3ff9

#define SPORT0_RX_Channels1 0x3ffa

#define TSCALE 0x3ffb

#define TCOUNT 0x3ffc

#define TPERIOD 0x3ffd

#define DM_Wait_Reg 0x3ffe

#define System_Control_Reg 0x3fff


Рис. 1.14. Содержимое файла определений адресов регистров процессора ADSP-2181


Содержимое файла Reg2181.inc показывает, что встроенный ассемблер VisualDSP поддерживает директиву define и отделение комментариев двумя прямыми слешами. Программа приведена на рис. 1.15.


//---------- Содержимое файла echo.asm


#include "Reg2181.inc"

// Объявление переменных и буферов предваряется именованием секции,

// в которых они будут располагаться физически

.SECTION/DM data_sect;

// Директива ALIGN выравнивает адрес rx_buf[0] на границе кратной

// 4-ем. Это необходимо сделать потому, что буфер rx_buf является

// циклическим, а директива CIRC прежнего ассемблера не

// поддерживается. Кратность выбирается из следующих соображений -

// это ближайшее сверху к размерности буфера число, кратное целой

// степени двойки. Это применимо и к буферам tx_buf и init_cmds.

.ALIGN 4;

.VAR rx_buf[3]; // циклический буфер, принимаемых из кодека

// данных (всегда три слова, первое является

// словом состояния кодека, второе – выходом

// левого АЦП, третье – выходом правого АЦП)

.ALIGN 4;

// Циклический буфер, передаваемых в кодек данных (также три слова,

// первое является кодом команды, второе – выводимые данные через

// левый ЦАП, третье – выводимые данные через правый ЦАП)

.VAR tx_buf[3] = 0xc000, 0x0000, 0x0000;

.ALIGN 16;

// Команды инициализации кодека, первая цифра (с) всех команд

// разрешает изменение управляющих регистров, а также конфигурирует

// кодек на обновление битов переполнения в слове состояния после

// выполнения очередного отсчета

.VAR init_cmds[13] = 0xc003, // усиление по левому входу 1 – 4,5 dB

0xc103, // усиление по правому входу 1 – 4,5 dB

0xc288, // запрет левого дополнительного входа 1

0xc388, // запрет правого дополнительного входа 1

0xc488, // запрет левого дополнительного входа 2

0xc588, // запрет правого дополнительного входа 2

0xc680, // выключение левого ЦАП

0xc780, // выключение правого ЦАП

0xc85b, // частота синхронизации 16,9344 МГц,

// частота отсчетов 44,1 КГц, стерео,

// линейное представление отсчетов, 16 бит

0xc909, // запуск автокалибровки с возможностью

// получения данных из кодека

0xca00,

0xcc40, // разрешение двухпроводной связи

0xcd00; // запрет цифрового смешивания сигналов

// Признак окончания инициализации кодека (если stat_flag = 0)

.VAR stat_flag;

// Объявление (именование) программной секции

.SECTION/PM program_sect;


jump start; // обход области векторов прерываний

rti; rti; rti;


rti; // вектор прерывания - IRQ2

rti; rti; rti;


rti; // вектор прерывания - IRQL1

rti; rti; rti;


rti; // вектор прерывания - IRQL0

rti; rti; rti;

// Вектор прерывания SPORT0 tx, сюда процесс приходит перед

// выдачей очередной команды инициализации кодека

ar = dm(stat_flag); // проверка флага stat_flag, если он равен

ar = pass ar; // нулю, то выход из обработчика;

if eq rti; // в противном случае – выдача очередной

jump next_cmd; // команды в кодек (переход на метку next_cmd)


// Вектор прерывания SPORT0 rx, сюда процесс приходит после

// получения данных из кодека

jump input_samples;

rti; rti; rti;


rti; // вектор прерывания - IRQE

rti; rti; rti;


rti; // вектор прерывания - BDMA

rti; rti; rti;


rti; // вектор прерывания - SPORT1 tx или IRQ1

rti; rti; rti;


rti; // вектор прерывания - SPORT1 rx или IRQ0

rti; rti; rti;


rti; // вектор прерывания - timer

rti; rti; rti;


rti; // вектор прерывания - down

rti; rti; rti;


// Это начало программы, сюда процесс приходит после ее загрузки

start:

i0 = rx_buf; // инициализация индексного регистра i0 на

// начало приемного буфера, в отличие от

// прежнего ассемблера, символ  опускается

l0 = length(rx_buf);//объявление кольцевого буфера, в отличие

// от прежнего ассемблера, символ %

// заменен директивой "length"

i1 = tx_buf; // инициализация индексного регистра i1 на

// начало передающего буфера

l1 = length(tx_buf);// передающий буфер – кольцевой

i3 = init_cmds; // инициализация индексного регистра i3 на

// начало буфера команд кодека

l3 = length(init_cmds);// этот буфер тоже кольцевой

m1 = 1;

//---------- Инициализация последовательного порта 0 (SPORT0)

// Разрешение автобуферизации (см. пп. 1.12.5, П1.3) по приему и

// передаче (RBUF = TBUF = 1), приемный буфер ассоциируется с i0

// (RIREG = 0), передающий буфер ассоциируется с i1 (TIREG = 1), оба

// буфера модифицируются значением 1 (RMREG = TMREG = 1)

ax0 = b#0000001010000111;

dm (SPORT0_Autobuf) = ax0;

ax0 = 0;

dm(SPORT0_RFSDIV) = ax0;

dm (SPORT0_SCLKDIV) = ax0;

// Длина данных – 16 бит, разрешение многоканального режима

// (см. п. 1.12.7) приема/передачи (см. п. П1.4)

ax0 = b#1000011000001111;

dm (SPORT0_Control_Reg) = ax0;

// Для передачи разрешены каналы 2, 1, 0

ax0 = b#0000000000000111;

dm (SPORT0_TX_Channels0) = ax0;

// Для передачи разрешены каналы 18, 17, 16

ax0 = b#0000000000000111;

dm (SPORT0_TX_Channels1) = ax0;

// Для приема разрешены каналы 2, 1, 0

ax0 = b#0000000000000111;

dm (SPORT0_RX_Channels0) = ax0;

// Для приема разрешены каналы 18, 17, 16

ax0 = b#0000000000000111;

dm (SPORT0_RX_Channels1) = ax0;


//---------- Инициализация последовательного порта 1 (SPORT1)

ax0 = 0;

dm (SPORT1_Autobuf) = ax0; // автобуферизация запрещена

dm (SPORT1_RFSDIV) = ax0; // RFSDIV не используется

dm (SPORT1_SCLKDIV) = ax0; // SCKDIV не используется

dm (SPORT1_Control_Reg) = ax0;// управляющие функции

// запрещены


//---------- Инициализация таймера

ax0 = 0; // таймер не используется

dm (TSCALE) = ax0;

dm (TCOUNT) = ax0;

dm (TPERIOD) = ax0;


//---------- Инициализация системы и памяти

ax0 = b#0000000000000000; // запрет тактов ожидания

dm (DM_Wait_Reg) = ax0;


ax0 = b#0001000000000000; // разрешение SPORT0

dm (System_Control_Reg) = ax0;


ifc = b#00000011111111; // очистка необработанных

// прерываний

nop; // выполнение предыдущей

// команды


icntl = b#00000; // запрет вложенных прерываний

mstat = b#0000000;


//---------- Инициализация кодека AD1847

ax0 = 1; // очистка флага окончания

dm (stat_flag) = ax0; // инициализации кодека

imask = b#0001000000; // разрешение прерываний

// SPORT0 tx

ax0 = dm (i1, m1); // запуск прерываний (выдача

tx0 = ax0; // первой команды)


check_init:

ax0 = dm (stat_flag); // ожидание окончания

af = pass ax0; // инициализации кодека, т.е.

if ne jump check_init; // выполнения условия stat_flag=0


ay0 = 2;


check_acih:

ax0 = dm (rx_buf); // после инициализации ожидание

ar = ax0 and ay0; // входа кодека в автокалибровку,

if eq jump check_acih; // т.е. выполнения условия ACI=1

check_acil:

ax0 = dm (rx_buf); // ожидание выхода кодека из

ar = ax0 and ay0; // автокалибровки, т.е.

if ne jump check_acil; // выполнения условия ACI=0

idle;


ay0 = 0xbf3f; // включение левого ЦАП

ax0 = dm (init_cmds + 6);

ar = ax0 AND ay0;

dm (tx_buf) = ar;

idle;


ax0 = dm (init_cmds + 7); // включение правого ЦАП

ar = ax0 AND ay0;

dm (tx_buf) = ar;


ax0 = 0xc901; // очистка запроса на

dm (tx_buf) = ax0; // автокалибровку

idle;


ax1 = 0x8000; // очистка битов переполнения

dm (tx_buf) = ax1;


ifc = b#00000011111111; // очистка не обработанных

// прерываний

nop; // выполнение предыдущей

// команды


imask = b#0000100000; // разрешение прерываний

// SPORT0 rx


//---------- Вход в бесконечный цикл для ожидания прерываний

talkthru:

idle;

jump talkthru;


//---------- ОБРАБОТЧИКИ ПРЕРЫВАНИЙ


//---------- Прием данных (SPORT0 rx)

input_samples:

ena sec_reg; // использование вторичного

// банка регистров

ax1 = dm (rx_buf + 1); // прием данных из кодека

mx1 = dm (rx_buf + 2);


// Здесь можно поместить программу обработки данных от кодека,

// например, фильтрацию. Следует учитывать, что данные от АЦП левого

// канала находятся в ах1, а данные от АЦП правого канала – в mx1.


dm (tx_buf + 1) = ax1; // выдача данных обратно в кодек

dm (tx_buf + 2) = mx1;

rti;


//---------- Инициализация кодека (SPORT0 tx)

next_cmd:

ena sec_reg;

ax0 = dm (i3,m1); // очередной управляющий код

dm (tx_buf) = ax0; // помещаем первым словом

// команды кодека

// Проверка окончания инициализации. Если i3 > init_cmds, то

// инициализация не завершена и следует выход из обработчика. Если

// i3 = init_cmds, то инициализация завершается выдачей последней

// команды кодеку с битом МСЕ = 0 (что запрещает изменение

// содержимого управляющих регистров) и сбросом флага stat_flag.

ax0 = i3;

ay0 = init_cmds;

ar = ax0 - ay0;

if gt rti;

ax0 = 0x8000; // МСЕ = 0

dm (tx_buf) = ax0;

ax0 = 0; // stat_flag = 0

dm (stat_flag) = ax0;

rti;


Рис. 1.15. Программа формирования эхо-сигнала кодека AD1847


Работа программы рис. 1.15 протекает в два этапа. На первом этапе происходит инициализация кодека (в обработчике прерываний по передаче next_cmd). Это достигается выдачей трехсловной команды, причем первое слово этой команды каждый раз берется из буфера (массива) init_cmds. Последующие два слова нулевые.

Инициализация является сложным процессом не только потому, что приходиться выдавать в кодек множество команд, но еще и потому, что приходиться ожидать окончание процесса автокалибровки каналов кодека. Все команды кроме последней имеют старшим байтом значение 0хс0, что, среди прочего, определяет единичное значение бита МСЕ. Это значение разрешает изменение многих конфигурационных регистров кодека, что, собственно, и позволяет производить инициализацию. Последняя команда имеет старшим байтом значение 0х80, что определяет нулевое значение бита МСЕ, что запрещает изменение многих конфигурационных регистров кодека, защищая их содержимое от случайных изменений.

Программа echo.asm достаточно закомментирована и не нуждается в дополнительном описании. Содержимое линкерного файла приведено на рис. 1.16. Важное примечание: линкер VisualDSP чувствителен к регистру клавиатуры. Это означает, что названия секций в линкерном файле должны точно совпадать по написанию с названиями секций в ассемблерном файле.


//---------- Содержимое файла echo.ldf