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

Вид материалаДокументы
I6 = i4; m5 = 1; modify(i6, m5)
ARCHITECTURE(ADSP-2181) // определение типа процессора SEARCH_DIR( $ADI_DSP\218x\lib ) // определение пути к библиотекам
Link_against( $command_line_link_against )
Input_sections( $objects(uart_code) )
Input_sections( $objects(uart_data))
2. Архитектура системы на основе adsp-2181
2.2. Цепи синхронизации и запуска процессора
П1.1. System control register
Подобный материал:
1   ...   18   19   20   21   22   23   24   25   26

где: Т - стоп бит, S - старт бит.

}

sr1=0;

sr0=TX_BIT_ADD;

ar=dm(user_tx_buffer);

sr=sr or lshift ar by 1 (lo);

dm(internal_tx_buffer)=sr0;


ax0=0; // поднимаем флаг передачи

dm(flag_tx_ready)=ax0;

rts;


//---------- Прием символа из UART

{

Использование регистров:

вход: нет

обновленные: нет

выход: ах1 (старшие 8 бит всегда сброшены)

измененные: ax0

сохраненные: нет

память: dm(flag_rx_no_word), dm(user_rx_buffer),

dm(flag_rx_no_word)

вызовы: нет

}

get_char_ax1:

ax0=dm(flag_rx_no_word); // ожидание приема символа,

none=pass ax0; // должно выполниться условие

// flag_rx_no_word = 0

if ne jump get_char_ax1;

get_char_ax1x:

ax1=dm(user_rx_buffer); // принятый символ пересылаем в ах1

ax0=1;

dm(flag_rx_no_word)=ax0; // дезактивируем flag_rx_no_word

rts;


//---------- Прием символа из UART с тайм-аутом

{

Тайм-аут и возврат 0xffff после 500 mS.

(15000 ticks / 3 == 5000 bps ~= 5000 / 9600 ~= .5 S)

}

{

Использование регистров:

вход: нет

обновленные: нет

выход: ах1 (все 16 бит установлены, если тайм-аут)

измененные: ax0

сохраненные: нет

память: dm(flag_rx_no_word), dm(user_rx_buffer)

вызовы: нет

}

get_char_ax1_to:

ax1 = ar; // сохраняем ar

ar = 30000; // 3 тика на бит; 9600 bps, тайм-аут

// в 1 sec ==> 9600 * 3 == 30000

get_char_ax1_to1:

idle; // ожидание прерываний таймера

ar = ar - 1;

if eq jump get_char_ax1_to2; // тайм-аут достигнут, выход


ax0=dm(flag_rx_no_word);

none=pass ax0;

if ne jump get_char_ax1_to1; // ожидание приема символа

ar = ax1; // символ принят, восстановление ar

jump get_char_ax1x; // чтение принятого символа


get_char_ax1_to2:

ar = ax1; // восстановление ar

ax1 = 0xffff; // установка признака тайм-аута

rts;


//---------- Вывод символа через UART

{

Использование регистров:

вход: ах1 (сохраняется)

обновленные: нет

выход: нет

измененные: ax0, (ar, sr)

сохраненные: нет

память: dm(flag_tx_ready), dm(user_tx_buffer), (dm(timer_tx_ctr),

dm(bits_left_in_tx), dm(internal_tx_buffer))

вызовы: invoke_UART_transmit

}

out_char_ax1:

ax0=dm(flag_tx_ready);

none=pass ax0;

if eq jump out_char_ax1; // ожидание выдачи предыдущего

// символа

dm(user_tx_buffer)=ax1;

call invoke_UART_transmit; // выдача нового символа

rts;


//---------- Разрешение приема

{

Использование регистров:

вход: нет

обновленные: нет

выход: нет

измененные: ax0 = 0

сохраненные: нет

память: dm(flag_rx_off)

вызовы: нет

}

turn_rx_on:

ax0=0;

dm(flag_rx_off)=ax0;

rts;


//---------- Запрет приема

{

Использование регистров:

вход: нет

обновленные: нет

выход: нет

измененные: ax0 = 1

сохраненные: нет

память: dm(flag_rx_off)

вызовы: нет

}

turn_rx_off:

ax0=1;

dm(flag_rx_off)=ax0;

rts;


Рис. 1.17. Программа поддержки UART


Программа поддержки UART принимает символы из коммуникационного канала, а затем возвращает их обратно (см. бесконечный цикл, тело которого начинается с метки next_byte). Прием осуществляется подпрограммой get_char_ax1 (принятый символ возвращается через регистр ах1), а выдача – подпрограммой out_char_ax1 (выдаваемый символ берется из регистра ах1).

Перед использованием подпрограмм get_char_ax1 и out_char_ax1 UART необходимо проинициализировать подпрограммой init_uart, а также разрешить прием данных подпрограммой turn_rx_on. Для приема данных из коммуникационного канала связи кроме подпрограммы get_char_ax1 можно использовать подпрограмму get_char_ax1_to, которая отличается наличием тайм-аута. Тайм-аут длится 30000 тиков таймера, что составляет 10000 битовых интервалов. Для частоты связи в 9600 Бод длительность битового интервала составляет 104 мкс, поэтому длительность тайм-аута составляет 1,04 с. Для деинициализации UART определена подпрограмма stop_uart.

Программа содержит также две внутренние подпрограммы: process_a_bit и invoke_UART_transmit. Первая из них является обработчиком прерываний таймера и осуществляет все действия для побитной выдачи (приема) данных в коммуникационный канал связи. После выдачи/приема очередного байта данных устанавливает соответствующие флаги. Вторая – подготавливает байт данных для вывода.

Все перечисленные подпрограммы достаточно закомментированы, чтобы понять их работу без дополнительных разъяснений. Файл async.ldf может быть получен из файла echo.ldf (см. рис. 1.16) путем замен:

program_sect – UART_CODE, data_sect – UART_DATA.


1.19.3. Эмуляция интерфейса RS-232 (смешанный вариант)


Задание: см. задание в п. 1.19.2. Главную часть программы рис. 1.17 (от метки start до метки init_uart) написать на языке С. Вызываемые подпрограммы написать на языке ассемблера.

Метод решения: использовать в качестве основы программу рис. 1.17.

Актуальность смешанного программирования объясняется тем, что сложные проекты проще реализовывать на языке высокого уровня, например, СИ. Но полностью выполненный на языке высокого уровня проект обладает большим объемом программы и относительно низким ее быстродействием. Эти недостатки можно существенно уменьшить, если функции (подпрограммы) писать на языке ассемблера, а их вызовы производить из программы, написанной на языке высокого уровня. Рассматриваемые ниже программы иллюстрируют такой подход.

Проект имеет имя AsyncMix и содержит шесть файлов: 218x_int_tab.asm – ASM файл векторов прерываний программы; 218x_hdr.asm – ASM файл пролога программы; 218x_exit.asm – ASM файл эпилога программы; async.c – СИ программа (рис. 1.18), uart.asm – ASM программа (рис. 1.19) и AsyncMix.ldf – линкерный файл (рис. 1.20). Первые три файла находятся в директории ..VisualDSP\218x\lib\crt_src.


//---------- Содержимое файла async.c


#include


unsigned short ch; // принимаемый из UART символ

void (*dm handler)(dm int); // переменная, в которой хранится указатель

// на обработчик прерываний таймера

//---------- Функции, определенные в uart.asm

extern void init_uart(void);

extern void stop_uart(void);

extern unsigned short char_received(void);

extern unsigned short get_char(void);

extern void out_char(unsigned short);

extern void turn_rx_on(void);

extern void turn_rx_off(void);

extern void process_a_bit(int);


void main(void) {

handler = process_a_bit; // инициализация указателя на обработчик

// прерывания от таймера

// Запись адреса обработчика прерываний в таблицу векторов

// прерываний. Константа SIGTIMER определена в Signal.h

interrupt(SIGTIMER, handler);

init_uart(); // инициализация UART

turn_rx_on(); // разрешение приема из UART

while(1) {

ch = get_char(); // ожидание и прием символа из UART

out_char(ch); // эхо-возврат принятого символа

}

}


Рис. 1.18. СИ программа поддержки UART


Программа, представленная на рис. 1.18, функционально идентична фрагменту программы рис. 1.17, который начинается с метки start и заканчивается меткой init_uart. Все используемые функции определены в файле uart.asm, поэтому должны быть объявлены с классификатором extern. Функции, имеющие одинаковое имя на рисунках 1.17, 1.18, имеют одинаковое назначение.

К таким же функциям относятся get_char и get_char_ax1, а также out_char и out_char_ax1. Изменение имен get_char_ax1 и out_char_ax1 про­и­зошло для упрощения их записи, а также в связи с тем, что прямое указание регистра источника и назначения (ах1) теперь не актуально.

Единственной новой функцией является функция char_received(), которая возвращает TRUE, если символ принят из UART и FALSE в противном случае. Эту функцию удобно использовать перед вызовом функции get_char(), которая может зациклиться, если из последовательного канала не приходят данные.


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


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

// доступными в других модулях проекта

.GLOBAL _init_uart, _stop_uart, _get_char, _out_char;

.GLOBAL _char_received, _turn_rx_on, _turn_rx_off;

.GLOBAL _process_a_bit;

{

Далее следуют строки программы рис. 1.17, начиная с #include и заканчивая строкой SECTION/PM UART_CODE. Строки jump start;… start: необходимо опустить, они находятся в файле 218x_int_tab.asm. Необходимо также опустить строки start:…jump next_byte;, они заменены С-программой (см. рис. 1.18).

}



_init_uart:

// Тело подпрограммы полностью идентично телу подпрограммы init_uart

// на рис. 1.17

rts


_stop_uart:

// Тело подпрограммы полностью идентично телу подпрограммы stop_uart

// на рис. 1.17

rts


_process_a_bit:

// Тело подпрограммы полностью идентично телу подпрограммы

// process_a_bit на рис. 1.17, только все команды rti необходимо заменить

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

rts


invoke_UART_transmit:

// Тело подпрограммы полностью идентично телу подпрограммы

// invoke_UART_transmit на рис. 1.17

rts


_char_received:

ax1 = 1;

ax0=dm(flag_rx_no_word);

none=pass ax0;

if eq rts; // если символ из UART получен, то возвращаем 1

ax1 = 0; // в противном случае возвращаем 0

rts;


_get_char:

// Тело подпрограммы полностью идентично телу подпрограммы

// get_char_ax1 на рис. 1.17

rts;


_out_char:

ax0=dm(flag_tx_ready);

none=pass ax0;

if eq jump _out_char; // ожидание передачи предыдущего

// символа

// Формирование указателя (I6) на передаваемый параметр функции

I6 = I4; M5 = 1; MODIFY(I6, M5);

{Pop arg1}

AX1 = DM(I6, M5);

dm(user_tx_buffer)=ax1;

call invoke_UART_transmit; // выдача его в UART

rts;


_turn_rx_on:

// Тело подпрограммы полностью идентично телу подпрограммы

// turn_rx_on на рис. 1.17

rts;


_turn_rx_off:

// Тело подпрограммы полностью идентично телу подпрограммы

// turn_rx_off на рис. 1.17

rts;


Рис. 1.19. ASM программа поддержки UART


Программа рис. 1.19 практически полностью соответствует программе рис. 1.17. Отличие заключается в том, что экспортируемые имена предваряются подчеркиванием (соглашение языка С) и объявляются директивой GLOBAL. Небольшое отличие наблюдается в функции _out_char. Ее аналог out_char_ax1 принимает символ (для выдачи в UART) в регистре ах1, а _out_char – через программный стек Поэтому в индексном регистре I6 формируется указатель на выдаваемый символ, хранящийся в стеке.

Передаваемые в качестве параметров функции значения хранятся по следующим адресам: первый аргумент – в SP + 1, второй – в SP + 2 и т.д. SP хранится в индексном регистре I4, поэтому первым шагом при формировании указателя на передаваемый параметр является I6 = I4. Затем в модификационный регистр М5 записывается 1 и окончательно командой MODIFY(I6, M5); формируется указатель.

Простота адаптации уже написанных программ на ассемблере позволяет широко использовать их в программах на СИ. Необходимо только следить, чтобы соблюдались соглашения об доступных (scratch), сохраняемых (preserved) и предопределенных (dedicated) регистрах.


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

ARCHITECTURE(ADSP-2181) // определение типа процессора
SEARCH_DIR( $ADI_DSP\218x\lib ) // определение пути к библиотекам

// Имена файлов, библиотек, ключей берутся из командной строки,

// необходимо также подключить libc.dlb, но это можно сделать также

// через Project | Project Options | Link | Additional options: libc.dlb

$OBJECTS = $COMMAND_LINE_OBJECTS, libc.dlb;

// 2181 имеет 16K слов (24-bit) ПП и 16K слов (16-bit) ПД

MEMORY {

// Используем всю доступную ПП и ПД

int_area {TYPE(PM RAM) START(0x0000) END(0x002f) WIDTH(24)}

prog_area {TYPE(PM RAM) START(0x0030) END(0x37fe) WIDTH(24)}

data_area {TYPE(DM RAM) START(0x0000) END(0x2fff) WIDTH(16)}

heap_area {TYPE(DM RAM) START(0x3000) END(0x37ff) WIDTH(16)}

stack_area {TYPE(DM RAM) START(0x3800) END(0x3fdf) WIDTH(16)}

}

PROCESSOR p0 {

// Ключи для линкера берутся из командной строки

LINK_AGAINST( $COMMAND_LINE_LINK_AGAINST )

// Имя выходного файла берется из командной строки

OUTPUT( $COMMAND_LINE_OUTPUT_FILE )

SECTIONS {

// Секция таблицы векторов прерываний,

// названия векторов определены в 218x_int_tab.asm

sec_int {

INPUT_SECTIONS( $OBJECTS(IVreset ) )

INPUT_SECTIONS( $OBJECTS(IVirq2 ) )

INPUT_SECTIONS( $OBJECTS(IVirql1 ) )

INPUT_SECTIONS( $OBJECTS(IVirql0 ) )

INPUT_SECTIONS( $OBJECTS(IVsport0xmit ) )

INPUT_SECTIONS( $OBJECTS(IVsport0recv ) )

INPUT_SECTIONS( $OBJECTS(IVirqe ) )

INPUT_SECTIONS( $OBJECTS(IVbdma ) )

INPUT_SECTIONS( $OBJECTS(IVirq1 ) )

INPUT_SECTIONS( $OBJECTS(IVirq0 ) )

INPUT_SECTIONS( $OBJECTS(IVtimer ) )

INPUT_SECTIONS( $OBJECTS(IVpwrdwn ) )

} >int_area

// Программная секция

sec_code {

// program – имя по умолчанию программной секции кода для

// СИ – файлов, может быть изменено в 218x_hdr.asm или

// директивой segment(segment_name) в тексте СИ-программы

INPUT_SECTIONS( $OBJECTS(program) )

// UART_CODE – имя секции программы,

// заданное в файле uart.asm

INPUT_SECTIONS( $OBJECTS(UART_CODE) )

} >prog_area

// Секция данных

sec_data {

// data1 – имя по умолчанию секции данных для

// СИ – файлов, может быть изменено в 218x_hdr.asm или

// директивой segment(segment_name) в тексте СИ-программы

INPUT_SECTIONS( $OBJECTS(data1))

// UART_DATA – имя секции данных, заданное в файле uart.asm

INPUT_SECTIONS( $OBJECTS(UART_DATA))

} >data_area

// Поддержка инициализации СИ – переменных, включая С++

sec_ctor {

INPUT_SECTIONS( $OBJECTS(ctor) )

} >data_area

// Поддержка кучи

sec_heap {

.heap = .;

.heap_size = MEMORY_SIZEOF(heap_area);

.heap_end = . + MEMORY_SIZEOF(heap_area) - 1;

} >heap_area

// Поддержка стека

sec_stack {

ldf_stack_limit = .;

ldf_stack_base = . + MEMORY_SIZEOF(stack_area) - 1;

} >stack_area

} // окончание SECTIONS

} // окончание processor p0


Рис. 1.20. Содержимое линкерного файла AsyncMix.ldf, входящего в проект AsyncMix


Файл рис. 1.20 в основном соответствует содержимому файла рис. 1.16. Отличие заключается в том, что:
  • раздел $OBJECTS дополнен именем файла libc.dlb;
  • в раздел MEMORY включены области памяти int_area, heap_area и stack_area;
  • в раздел SECTION добавлены секции СИ программы: program – для программной секции, data1 – для секции данных (в которой находятся переменные ch и handler), ctor – для секции данных (инициализация переменных CИ-программы), heap – для секции данных (поддержка кучи), stack – для секции данных (поддержка стека).



2. АРХИТЕКТУРА СИСТЕМЫ НА ОСНОВЕ ADSP-2181


2.1. Структурная схема вычислительной (управляющей)

системы на основе ADSP-2181


Структурная схема системы на основе ADSP-2181 представлена на рис 2.1. и рис 2.2.




Рис. 2.1. Структурная схема системы на основе ADSP-2181 (начало)


Рис. 2.1. показывает, что устройство с последовательным интерфейсом (например, такой же процессор ADSP-2181) может быть подключено напрямую через SPORT0 и/или SPORT1 (см. п. 1.12). Системный интерфейс (например, PCI) или микроконтроллер (например, такой же процессор ADSP-2181) могут быть подключены через порт IDMA (см. п. 1.16).

Большие возможности для подключения различных видов памяти и периферийных устройств создает внешняя шина: ADDR[13-0], DATA[23-0], BMS#, IOMS#, PMS#, DMS#, CMS#. Некоторые способы ее использования приводятся на рис. 2.2.




Рис. 2.2. Структурная схема системы на основе ADSP-2181 (окончание, сигналы RD#, WR# условно не показаны)


Байтовая память (BYTE MEMORY, см. п. 1.15) подключается к процессору в соответствии с рекомендациями п. 1.15.1. Байтовая память доступна только через BDMA.

Порты ввода/вывода (I/O SPACE) используют в качестве шины адреса 11 линий внешней шины адреса процессора ADDR[10-0], а в качестве шины данных – 16 линий внешней шины данных процессора DATA[23-8]. Обращение к портам ввода/вывода возможно только с помощью команды IO(..) (см. п. 1.17.4.и).

Оверлейная ПП (PMOVERLAY MEMORY) использует всю ширину внешних шин адреса и 16 линий внешней шины данных процессора DATA[23-8]. Ее особенностью является то, что значение бита ADDR13 устанавливается через регистр PMOVLAY (см. п. 1.3). Значение ADDR13 = 0 обеспечивает доступ к первому сегменту оверлейной ПП, а ADDR13 = 1 – к второму сегменту оверлейной ПП. Обращение к ячейкам памяти обоих сегментов возможно только с помощью косвенного метода адресации (см. пп. 1.17.4.д, з).

Оверлейная ПД (DMOVERLAY MEMORY) использует всю ширину внешней шины адреса и 16 линий внешней шины данных процессора DATA[23-8]. Ее особенностью является то, что значение бита ADDR13 устанавливается через регистр DMOVLAY (см. п. 1.4). Значение ADDR13 = 0 обеспечивает доступ к первому сегменту оверлейной ПД, а ADDR13 = 1 – к второму сегменту оверлейной ПД. Обращение к ячейкам памяти обоих сегментов возможно как с помощью прямого метода адресации (см. пп. 1.17.4.в, е) , так и с помощью косвенного метода адресации (см. пп. 1.17.4.г, ж).


2.2. Цепи синхронизации и запуска процессора


Для формирования импульсов синхронизации процессора используется встроенный генератор, для работы которого ко входам CLKIN (контакт 20) и XTAL (контакт 19) необходимо подключить хронирующие цепи (кварцевый резонатор BQ и конденсаторы С1, С2, см. п. 1.1). Параметр кварцевого резонатора (частота Fclkin = 16,67 МГц) приводится в п. 1.14.1, осталось определить значения емкостей С1 = С2 = 18 пФ.

Схема цепи запуска процессора приведена на рис 2.3.




Рис. 2.3. Схема цепи запуска процессора (D1, D2 – 74HC14)


Схема цепи запуска процессора функционирует аналогично цепи сброса микропроцессора М1821ВМ85А, см. п. 2.6 в [6]. Цепь R1, С1 определяет длительность импульса сброса. Цепь R2, D1, D2 является антидребезговой. Если конденсатор С1 перемкнуть нормально разомкнутой кнопкой, то процессор можно сбрасывать вручную с помощью этой кнопки.


ПРИЛОЖЕНИЕ 1


Формат регистров управления


Ниже представлены форматы всех регистров управления и состояния кроме ASTAT (см. табл.1.9), SSTAT (см. табл.1.11), MSTAT (см. табл.1.12), и регистров управления таймером TPERIOD, TCOUNT, TSCALE (см. табл.1.15). Также не представлены некоторые регистры, имеющие простой формат, например, SPORTx CLKDIV, SPORTx RFSDIV.

Цифры в битах и битовых полях отражают содержимое соответствующих битов после сброса, отсутствие цифр отражает неопределенное содержимое соответствующих битов после сброса. Серым цветом закрашены зарезервированные биты и битовые поля. В них всегда должны записываться нулевые значения.


П1.1. System control register (регистр управления системой)


Адрес регистра: 0x3FFF.


15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

0

0

0

0

0

1

0

0

0

0

0

0

0

1

1

1










S0E

S1E

S1C






















PWAIT