А. В. Комаров цифровые сигнальные процессоры
Вид материала | Документы |
- Архитектура процессов и ее оптимизация, 98.67kb.
- Обзор аппаратных и программных средств реализации параллельной обработки, 211.84kb.
- Темы Лекции Практика, 13.65kb.
- Лекция: графические процессоры и редакторы, 204.53kb.
- Реферат по дисциплине «Аппаратные средства» на тему: «Процессоры эвм», 333.09kb.
- ru/computers/classes html, 11.94kb.
- Методические указания му 2568 09 Издание официальное Москва 2009 Контроль численности, 527.33kb.
- Первая помощь при укусах насекомых и змей помощь при укусах комаров, 30.72kb.
- Фестиваль «Цифровые каникулы» – музей, образование, бизнес, 48.15kb.
- Неоднородный полупроводниковый носитель информации в переменном магнитном поле, 107.68kb.
ARCHITECTURE(ADSP-2181) // определение типа процессора
SEARCH_DIR( $ADI_DSP\218x\lib ) // определение пути к библиотекам
// Имена файлов, библиотек, ключей берутся из командной строки
$OBJECTS = $COMMAND_LINE_OBJECTS;
// 2181 имеет 16K слов (24-bit) ПП и 16K слов (16-bit) ПД
MEMORY {
// Используется вся доступная область ПП и ПД
prg_area {TYPE(PM RAM) START(0x0000) END(0x37fe) WIDTH(24)}
data_area {TYPE(DM RAM) START(0x0000) END(0x3dfe) WIDTH(16)}
}
PROCESSOR p0 {
LINK_AGAINST( $COMMAND_LINE_LINK_AGAINST )
// Имя выходного файла берется из командной строки
OUTPUT( $COMMAND_LINE_OUTPUT_FILE )
SECTIONS {
// Определение программной секции
sec_code {
// "program_sect" – имя программной секции в файле echo.asm
INPUT_SECTIONS( $OBJECTS(program_sect) )
} >prg_area // см. выше MEMORY
// Определение секции данных
sec_data {
// "data_sect" – имя секции данных в файле echo.asm
INPUT_SECTIONS( $OBJECTS(data_sect))
} >data_area // см. выше MEMORY
}// Здесь заканчивается область действия SECTIONS
}// Здесь заканчивается область действия PROCESSOR p0
Рис. 1.16. Содержимое линкерного файла echo.ldf, входящего в проект echo
Существенными для программиста в линкерном файле являются разделы MEMORY и PROCESSOR. Первый – позволяет обозначить символическими именами различные области физической ПП или ПД. В нашем случае области физической ПП с адресами 0x0000…0x37fe присвоено имя prg_area, а области физической ПП с адресами 0x0000…0x3dfe присвоено имя data_area.
Второй – позволяет располагать (с помощью директивы SECTION) в различных областях физической ПП или ПД различные программные секции и секции данных. В нашем случае программная секция program_sect будет отнесена с области памяти prg_area, т. е. начинаться с нулевого адреса в ПП, а секция данных data_sect будет отнесена с области памяти data_area, т. е. начинаться с нулевого адреса в ПД.
1.19.2. Эмуляция интерфейса RS-232
Задание: с помощью EZ-KIT Lite программно эмулировать работу коммуникационного интерфейса RS-232 в двух вариантах: с использованием флагов FLAG_IN, FLAG_OUT; с использованием битов PF[1], PF[2].
Метод решения: адаптировать для VisualDSP программу uart.dsp, которая входит в состав монитора EZ-KIT Lite (программные средства для DOS (см. п. 1.18.1)).
Задача актуальна тем, что процессор ADSP-2181 не содержит асинхронного коммуникационного порта, который мог бы поддерживать очень распространенный интерфейс типа RS-232. Приведенная программа позволяет устранить этот недостаток.
Создадим проект с именем async, в который входят два файла: async.asm и async.ldf. Первый из них является файлом программы, а второй – линкерным файлом. К файлу программы подключается файл (Reg2181.inc) определений адресов регистров процессора ADSP-2181. Эмулируемое устройство назовем UART. Программа (async.asm) поддержки UART приведена на рис. 1.17.
//---------- Содержимое файла async.asm
#include
// Частота кварцевого резонатора в КГц
#define CRYSTAL_FREQ_IN_kHZ 16667
{
Для поддержки интерфейса RS-232 ADSP-2181 в составе EZ-KIT Lite использует ресурсы FLAG_IN, FLAG_OUT и TIMER следующим образом:
ADSP-2181 FLAG_OUT ----------> AD233 ----------> RS-232 TX
ADSP-2181 FLAG_IN <----------- AD233 <---------- RS-232 RX
(TIMER определяет скорость обмена)
Или (в зависимости от определения HOST):
ADSP-2181 PF[2] ----------> AD233 ----------> RS-232 TX
ADSP-2181 PF[1] <---------- AD233 <---------- RS-232 RX
Формат посылки (число информационных бит, число стоп бит, наличие/отсутствие контроля по четности) и скорость обмена задаются программно. Преобразование логических уровней сигналов RxD и TxD в уровни интерфейса RS-232 производится микросхемой AD233.
Подпрограммы инициализации передатчика и приемника функционируют независимо друг от друга. Передача и прием данных синхронизируются сигналами таймера. Это не мешает производить одновременный асинхронный (по отношению друг к другу) прием/передачу. По умолчанию приемник заблокирован (выключен), поэтому перед его использованием необходимо вызвать подпрограмму "turn_rx_on".
Используемые подпрограммы:
init_uart Должна быть вызвана после сброса системы.
get_char_ax1 Ожидание приема байта с линии RX и возврат
его через ax1.
out_char_ax1 Ожидание текущей выдачи байта через линию
TX и выдача следующего байта из ax1.
turn_rx_on Разрешение работы приемника.
turn_rx_off Запрет работы приемника.
Используемый флаг: DM(flag_rx_ready)
Если flag_rx_ready содержит все единицы, то это означает, что UART готов получать данные. Если flag_rx_ready содержит все нули, то это означает, что UART уже получает данные. Может использоваться для управления потоком данных по протоколу xon, xoff.
}
// Если определено символическое имя HOST, то используются флаги
// FLAG_IN, FLAG_OUT, в противном случае биты PF[1], PF[2]
#define HOST
// Следующие константы могут быть изменены для установки новых
// параметров UART
#define tx_num_of_bits 10 // старт бит + информ. биты + стоп биты
#define rx_num_of_bits 8 // информ. биты (старт&стоп биты не
// считаются)
#define RX_BIT_ADD 0x0100 // = 1<
#define TX_BIT_ADD 0xfe00 // = 0xffff<<(информационные биты + 1)
#define Baud 9600 // скорость обмена в Бод
// PERIOD == 1144
{
PERIOD - период прерываний таймера (в 3 раза меньше битового интервала). Коэффициент 2000 переводит частоту кварцевого резонатора в КГц в частоту внутренней синхронизации ADSP-2181 в Гц.
}
#define PERIOD (CRYSTAL_FREQ_IN_kHZ * 2000 / (3 * Baud)) – 1
// Объявление секции данных
.SECTION/DM UART_DATA;
.VAR flag_rx_off; // индицирует выключенное состояние приемника
.VAR flag_tx_ready; // 1 - передачи нет, 0 - передача есть
.VAR flag_rx_ready; // 1 - приема нет, 0 - прием есть
.VAR flag_rx_stop_yet; // 1 - стоп бит не достигнут, 0 - достигнут
.VAR flag_rx_no_word; // 0 - принятый символ находится в user_rx_buffer,
// в противном случае - 1
.VAR timer_tx_ctr; // делитель на 3 передатчика, таймер работает
// на частоте 3 x скорость обмена
.VAR timer_rx_ctr; // делитель на 3 приемника, таймер работает
// на частоте 3 x скорость обмена
.VAR user_tx_buffer; // регистр данных передатчика UART
.VAR user_rx_buffer; // регистр данных приемника UART
.VAR internal_tx_buffer; // сдвиговый регистр передатчика, именно в нем
// форматируется посылка (добавляются старт и
// стоп биты), в него перед отправкой
// копируется содержимое user_tx_buffer
.VAR internal_rx_buffer; // сдвиговый регистр приемника
.VAR bits_left_in_tx; // число оставшихся для передачи битов
.VAR bits_left_in_rx; // число оставшихся для приема битов
// Объявление программной секции
.SECTION/PM UART_CODE;
jump start;
rti; rti; rti;
rti; // вектор прерывания - IRQ2
rti; rti; rti;
rti; // вектор прерывания - IRQL1
rti; rti; rti;
rti; // вектор прерывания - IRQL0
rti; rti; rti;
rti; // вектор прерывания - SPORT0 tx
rti; rti; rti;
rti; // вектор прерывания - SPORT0 rx
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;
jump process_a_bit; // вектор прерывания - timer
rti; rti; rti;
rti; // вектор прерывания - power down
rti; rti; rti;
start:
call init_uart; // инициализация UART
call turn_rx_on; // разрешение приема данных
next_byte:
call get_char_ax1; // ожидание и прием символа из UART
call out_char_ax1; // выдача принятого символа в UART
jump next_byte;
//---------- Подпрограмма инициализации
{
Использование регистров:
вход: нет
обновленные: imask
выход: нет
измененные: ar, ax0, ay0
сохраняемые: нет
память: dm (TSCALE)=0, dm(flag_tx_ready)=1,
dm(flag_rx_ready)=1, dm(flag_rx_stop_yet)=1,
dm(flag_rx_no_word)=1, dm(flag_rx_off)=1
flag_out/PF[2]
вызовы: нет
}
init_uart:
ax0=0;
dm(TSCALE)=ax0; // декремент TCOUNT каждый
// машинный цикл
ax0=PERIOD; // установка скорости обмена (9600 Бод)
dm(TCOUNT)=ax0;
dm(TPERIOD)=ax0; // прерывания генерируются с тройной
// частотой
ax0=1;
dm(flag_tx_ready)=ax0; // передачи нет
dm(flag_rx_ready)=ax0; // установки режима по умолчанию
// (UART занят)
dm(flag_rx_stop_yet)=ax0;
dm(flag_rx_no_word)=ax0;
dm(flag_rx_off)=ax0; // приемник выключен
#ifdef HOST
set flag_out; // TxD = 1
#else
ax0 = dm(PFTYPE); // PF[2] - TxD
ar = setbit 2 of ax0;
dm(PFTYPE) = ar;
ax0 = dm(PFDATA); // TxD = 1
ar = setbit 2 of ax0;
dm(PFDATA) = ar;
#endif
ifc = b#00000011111111; // очистка запросов прерываний
nop; // ожидание очистки
ax0 = b#0000100000000000;
ay0 = dm (System_Control_Reg);
ar = ax0 or ay0; // разрешение SPORT1
ay0 = b#1111101111111111;
ar = ar and ay0; // очистка для разрешения FI, и т.д.
dm (System_Control_Reg) = ar;
ax0=imask;
ay0=b#0000000001;
ar=ax0 or ay0;
imask=ar; // разрешение прерываний TIMER
ena timer; // запуск TIMER
rts;
//---------- Подпрограмма останова UART
{
Использование регистров:
вход: нет
обновленные: imask
выход: нет
измененные: ar, ay0
сохраняемые: нет
память: нет
flag_out/PF[2]
вызовы: нет
}
stop_uart:
dis timer; // останов TIMER
#ifdef HOST
set flag_out; // TxD = 1
#else
ax0 = dm(PFDATA); // TxD = 1
ar = setbit 2 of ax0;
dm(PFDATA) = ar;
#endif
ifc = b#00000011111111; // очистка запросов на прерывания
nop; // ожидание очистки
ar=imask;
ay0=b#1111111110;
ar=ar and ay0;
imask=ar; // запрет прерываний TIMER
rts;
//---------- Обработчик прерываний TIMER
{
Эта подпрограмма является основной частью UART. Она вызывается запросом на прерывание TIMER, т.е. с частотой в три раза большей частоты обмена. Подпрограмма формирует выходной бит данных установкой/сбросом сигнала на выходе FLAG_OUT/PF[2] ADSP-2181.
Далее проверяет наличие режима приема данных. Если таковой присутствует, то к принимаемому данному пристыковывается очередной бит с входа FLAG_IN/PF[1] ADSP-2181, после чего входные данные сдвигаются на один разряд вправо.
Если режим приема данных отсутствует, то проверяется старт бит. Поскольку интервальный таймер работает на тройной частоте скорости обмена, то прием/ передача возможны в каждое третье прерывание.
}
{
Использование регистров:
вход: нет
обновленные: нет
выход: нет (вторичный банк регистров)
измененные: нет
сохраненные: нет
память: dm(flag_tx_ready), dm(timer_tx_ctr), dm(internal_tx_buffer),
dm(bits_left_in_tx), dm(flag_rx_off), dm(flag_rx_stop_yet),
dm(timer_rx_ctr), dm(flag_rx_ready), dm(internal_rx_buffer),
dm(flag_rx_no_word), dm(bits_left_in_rx)
flag_out/PF[2]
вызовы: нет
}
process_a_bit:
ena sec_reg; // подключение вторичного банка регистров
ax0=dm(flag_tx_ready); // если не передача, то переход на прием
none=pass ax0;
if ne jump receiver;
// Передающая секция
ay0=dm(timer_tx_ctr); // проверка timer_tx_ctr на 0,
ar=ay0-1; // если не 0, то декремент, сохранение
dm(timer_tx_ctr)=ar; // и переход на прием, в противном
if ne jump receiver; // случае передача
sr1=dm(internal_tx_buffer);
// Сдвиг вправо младшего значащего разряда internal_tx_buffer в SR1.
// В SR0 этот бит является знаковым, в соответствии с ним
// FLAG_OUT/PF[2] сбрасывается или устанавливается
sr=lshift sr1 by -1 (hi);
dm(internal_tx_buffer)=sr1;
ar=pass sr0;
#ifdef HOST
if ge reset flag_out;
if lt set flag_out;
#else
ax0 = dm(PFDATA);
if ge ar = clrbit 2 of ax0;
if lt ar = setbit 2 of ax0;
dm(PFDATA) = ar;
#endif
ay0=3; // восстановление timer_tx_ctr, т.е.
dm(timer_tx_ctr)=ay0; // следующий бит будет передан
// через три прерывания
ay0=dm(bits_left_in_tx); // декремент оставшихся для передачи
ar=ay0-1; // битов
dm(bits_left_in_tx)=ar;
if gt jump receiver; // если биты остались, то переход на прием
ax0=1; // в противном случае - сброс флага
dm(flag_tx_ready)=ax0; // необходимости передачи
// Приемная секция
receiver:
ax0=dm(flag_rx_off); // приемник включен?
none=pass ax0;
if ne rti; // если нет, то выход
ax0=dm(flag_rx_stop_yet);// проверка приема стоп бита,
none=pass ax0; // если нет, то переход на прием
if ne jump rx_test_busy; // предыдущих битов
ay0=dm(timer_rx_ctr); // стоп бит достигнут, декремент
ar=ay0-1; // timer_rx_ctr, если не 0, то выход
dm(timer_rx_ctr)=ar; // (выдержка битового интервала)
if ne rti;
ax0=1; // битовый интервал стоп бита выдержан,
dm(flag_rx_stop_yet)=ax0;// восстановление flag_rx_stop_yet,
dm(flag_rx_ready)=ax0; // сброс flag_rx_ready,
ax0=dm(internal_rx_buffer);// копирование принятого символа из
dm(user_rx_buffer)=ax0; // internal_rx_buffer в user_rx_buffer
ax0=0; // индикация нахождения принятого слова
dm(flag_rx_no_word)=ax0;// в user_rx_buffer
rti;
rx_test_busy:
ax0=dm(flag_rx_ready); // проверка наличия режима приема,
ar=pass ax0; // если прием идет, то переход на прием
if eq jump rx_busy; // очередного бита, в противном случае -
// проверка старт бита
#ifdef HOST
if flag_in jump rx_exit; // если flag_in=1, то старт бита нет –
// выход
#else
ax0=dm(PFDATA); // если PF[1]=1, то старт бита нет –
ay0 = 2; // выход
ar = ax0 and ay0;
if ne jump rx_exit;
#endif
ax0=0;
dm(flag_rx_ready)=ax0 // в противном случае, устанавливаем
dm(internal_rx_buffer)=ax0; // флаг режима приема и очищаем
// приемный регистр
ax0=4; // первый бит необходимо проверить через
dm(timer_rx_ctr)=ax0; // 4 прерывания, чтобы проверка
// пришлась на середину его битового
// интервала
ax0=rx_num_of_bits; // инициализация числа оставшихся
dm(bits_left_in_rx)=ax0; // для приема битов
rx_exit:
rti;
rx_busy:
ay0=dm(timer_rx_ctr);// декремент timer_rx_ ctr и проверка его
ar=ay0-1; // на 0, если не 0, то битовый интервал
dm(timer_rx_ctr)=ar; // не выдержан - выход
if ne rti;
rcv:
// Битовый интервал выдержан, прием очередного бита
ax0=3; // восстановление счетчика бит. интервала
dm(timer_rx_ctr)=ax0; // проверка следующего бита
// произойдет через три прерывания
ay0=RX_BIT_ADD;
ar=dm(internal_rx_buffer);
#ifdef HOST
// Если flag_in=0, то переход на сдвиг
if not flag_in jump pad_zero;
#else
ax0 = dm(PFDATA); // если PF[1] =0, то переход на сдвиг
ay1 = 2;
af = ax0 and ay1;
if eq jump pad_zero;
#endif
// подстыковка 1
ar=ar+ay0;
pad_zero:
sr=lshift ar by -1 (lo); // сдвиг вправо результата для
dm(internal_rx_buffer)=sr0; // подготовки к приему следующего
// бита
ay0=dm(bits_left_in_rx); // декремент счетчика оставшихся
ar=ay0-1; // битов, если осталось один или
dm(bits_left_in_rx)=ar; // более битов, то выход (остаемся в
if gt rti; // режиме приема), в противном
// случае – осталось сформировать
// стоп бит
ax0=3; // восстановление счетчика битового интервала
dm(timer_rx_ctr)=ax0;
ax0=0; // установка флага стоп бита
dm(flag_rx_stop_yet)=ax0;
rti;
//---------- Выдача содержимого user_tx_buffer в канал UART
{
Использование регистров:
вход: нет
обновленные: нет
выход: нет
измененные: ar, ax0, sr
сохраненные: нет
память: dm(timer_tx_ctr), dm(bits_left_in_tx), dm(user_tx_buffer),
dm(internal_tx_buffer), dm(flag_tx_ready)
вызовы: нет
}
invoke_UART_transmit:
ax0=3; // инициализация делителя частоты
dm(timer_tx_ctr)=ax0; // прерываний, это необходимо из-за
// того, что частота прерываний в 3 раза
// больше частоты обмена
ax0=tx_num_of_bits; // инициализация числа передаваемых
dm(bits_left_in_tx)=ax0;// битов, включая стоп бит и бит
// четности, определяется программистом
{
Формирование кода в internal_tx_buffer в следующем формате:
15 | 14 | 13 | 12 | 11 | 10 | 09 | 08 | 07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | d7 | d6 | d5 | d4 | d3 | d2 | d1 | d0 | 0 |
| | | | | | T | Передаваемый байт | S |