Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
KOMAROV.DOC
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
1.32 Mб
Скачать

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]