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

Вид материалаДокументы
ARCHITECTURE(ADSP-2181) // определение типа процессора SEARCH_DIR( $ADI_DSP\218x\lib ) // определение пути к библиотекам
Objects = $command_line_objects
Link_against( $command_line_link_against )
Метод решения
Adsp-2181 flag_in
Section/dm uart_data
Section/pm uart_code
Подобный материал:
1   ...   18   19   20   21   22   23   24   25   26
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