Программирование DSP ADSP-BF538: интерфейс UART Fri, March 29 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

ADSP-BF538: интерфейс UART Печать
Добавил(а) microsin   

В процессорах Blackfin ADSP-BF538 и ADSP-BF538F имеется 3 универсальных асинхронных приемопередатчика (universal asynchronous receiver/transmitters, UART), реализованных как внутреннее периферийное устройство процессора BF538 [2]. UART поддерживает полный дуплекс, и является совместимым с популярным индустриальным стандартом последовательного порта компьютеров PC (RS-232, COM-порт). Здесь приведен перевод раздела UART PORT CONTROLLERS даташита [1].

Примечание: в тексте статьи обе модели Blackfin ADSP-BF538 и ADSP-BF538F будут для простоты обозначаться просто как BF538. Непонятные аббревиатуры и термины см. в разделе "Словарик" статьи [2].

В таблице ниже приведена цоколевка ножек портов UART0, UART1, UART2 для процессора BF538. Стоит заметить, что порт UART0 использует выделенные выводы для сигналов RXD и TXD, а у портов UART1 и UART2 функции UART совмещены с функциями портов ввода/вывода (GPIO). Дополнительную информацию по портам ввода/вывода (GPIO) см. в статье [4].

Сигнал UART0 UART1 UART2
RXD выв. T1
RX0
выв. C5
PD10
выв. W14
PD12
TXD выв. R1
TX0
выв. C6
PD11
выв. W15
PD13

Каждый UART преобразует данные между последовательным и параллельным форматами. Последовательный обмен данными следует асинхронному протоколу, который поддерживает различные длины слова, стоп-биты и опции генерации и проверки четности бит. Каждый UART имеет аппаратную поддержку генерации прерываний - прерывания могут быть сгенерированы от 12 разных событий, связанных с периферийным устройством UART. Дополнительно каждый UART поддерживает полудуплексный протокол IrDA® (Infrared Data Association) SIR (скорость 9.6/115.2 Kbps), эта функция разрешается выбором режима.

Сигналы состояния и управления модема (modem status and control) не поддерживаются модулями UART, однако этот функционал может быть реализован программно с использованием выводов портов ввода/вывода общего назначения (GPIO).

Каждый UART имеет поддержку со стороны системы DMA [3] для раздельных мастер-каналов передачи и приема (TX DMA и RX DMA). Таким образом, UART можно использовать для передачи данных либо в режиме DMA, либо в режиме обычного программного доступа, без DMA. Режим без DMA требует программного управления потоком данных либо с помощью прерываний, либо без прерываний, по опросу флагов в регистрах управления (polling). Метод с использованием DMA более эффективен, потому что требует минимального вмешательства со стороны процессора - система DMA берет на себя операцию по перемещению данных между периферийным устройством UART и памятью. Дополнительную информацию о системе DMA см. в статье [3].

Вместе с UART0 для функции автотдетекта скорости передачи (autobaud) может использоваться любое из периферийных устройств таймера. Для UART1 и UART2 функция автодетекта скорости не доступна. Подробнее про таймеры можно прочитать в разделе "Timers" [1].

[Формат фрейма UART]

Каждый UART следует стандартному асинхронному последовательному протоколу обмена данными со следующими настраиваемыми опциями:

• 5..8 бит данных.
• 1, 1.5 или 2 стоп-бита.
• Генерация/проверка четности: None (отключено), even (проверка на четность) или odd (проверка на нечетность).
• Baud rate (скорость следования бит данных) = SCLK / (16 x Divisor), где SCLK это частота системной шины процессора, и Divisor это коэффициент деления, который может быть запрограммирован в любое значение от 1 до 65536.

По стандарту каждое передаваемое слово данных (асинхронный фрейм) требуют наличия стартового бита и как минимум одного стопового бита. Также опционально может присутствовать бит четности, который создается от диапазона бит от 7 до 12. Формат принимаемого и передаваемого фрейма управляется регистром Line control register (UARTx_LCR). Данные всегда передаются так, что самый младший бит слова (least significant bit, LSB) передается первым, и за ним идут биты по нарастанию старшинства, самый старший бит слова (most significant bit, MSB) передается последним. На рис. 12-1 показана физическая диаграмма типичного потока бит, который можно увидеть на выводе TX.

ADSP BF538 UART frame

Рис. 12-1. Как выглядит поток бит на выводе передачи TX.

[Регистры управления и состояния UART]

Процессор BF538 предоставляет набор регистров управления и состояния для каждого UART, которые выполнены в соответствии с общепринятыми индустриальными стандартами. Это регистры, отображенные на адресам памяти, так называемые memory-mapped registers (MMR), которые имеют ширину в 1 байт, и могут быть прочитаны/записаны в общем адресном пространстве памяти как полу-слова (2 байта), где старший байт заполнен нулем.

С целью соответствия со стандартными индустриальными интерфейсами, несколько регистров привязаны к одному адресу. Регистры защелки делителя (divisor latch registers, UARTx_DLH и UARTx_DLL) используют общий адрес с регистром буфера передачи (transmit holding register, UARTx_THR), регистром буфера приема (receive buffer register, UARTx_RBR) и регистром разрешения прерываний (interrupt enable register, UARTx_IER). Бит защелки делителя (divisor latch access bit, DLAB) в регистре управления линией (line control register, UARTx_LCR) управляет набором регистров, который доступен в настоящий момент. Для доступа к этим регистрам программное обеспечение может использовать 16-разрядные инструкции загрузки/сохранения (16-bit word load/store instructions).

Раздельную буферизацию имеют и канал передачи, и канал приема. Регистр UARTx_THR буферизирует регистр сдвига передачи (transmit shift register, TSR) и регистр UARTx_RBR буферизирует регистр сдвига приема (receive shift register, LSR). Регистры сдвига недоступны для прямого доступа со стороны программного обеспечения.

Примечание: на всех рисунках не используемые биты регистров закрашены серым цветом.

Регистр управления линией (UART line control register, UARTx_LCR) управляет форматом передаваемого и принимаемого фреймов (у передаваемого и принимаемого фреймов всегда формат одинаковый, см. рис. 12-2). Бит SB работает даже тогда, когда тактовая частота для UART запрещена. Поскольку вывод TX обычно в состоянии ожидания имеет уровень лог. 1, то он может использоваться как вывод флага, если UART не используется.

ADSP BF538 UARTx LCR

Рис. 12-2. UART Line Control Register (UARTx_LCR).

DLAB (Divisor Latch Access). Бит защелки делителя. 1: разрешает доступ к UARTx_DLL и UARTx_DLH, 0: разрешает доступ к UARTx_THR, UARTx_RBR и UARTx_IER. Бит нужен потому, что эти регистры используют один и тот же адрес MMR.

SB (Set Break). Бит управления состоянием линией передачи. 0: обычный режим, 1: - принудительный вывод лог. 0 на вывод TX.

STP (Stick Parity). Если бит установлен и PEN = 1, то принудительно устанавливает четность в заданное значение. EPS = 1 четность передается и проверяется как 0, EPS = 0 четность передается и проверяется как 1.

EPS (Even Parity Select). Бит настройки четности. 1: Even parity (проверка на четность), 0: Odd parity (проверка на нечетность). Бит работает, когда PEN = 1 и STP = 0.

PEN (Parity Enable). Бит разрешения генерации и проверки четности. 1: передавать и проверять четность, 0: информация четности не передается и не проверяется (этот вариант используется чаще всего).

STB (Stop Bits). Настраивает стоп-бит фрейма. 1: 2 стоп-бита для длин слова не 5 бит, или 1.5 стоп-бита для длин слова в 5 бит. 0: 1 стоп-бит для всех длин слова, этот вариант используется чаще всего.

WLS[1:0] (Word Length Select). Выбор длины слова. 00: 5 бит, 01: 6 бит, 10: 7 бит, 11: 8 бит. Последний вариант используется чаще всего.

Регистр управления модемом (modem control register, UARTx_MCR) управляет портом UART, как это показано на рис. 12-3. Хотя функциональность модема не поддерживается аппаратно внешними выводами, регистр управления модемом все же был предоставлен для поддержки режима закольцовывания (loop back mode). Этот режим используется для самотестирования, в нем принудительно внешний вывод TX переводится в лог 1, и внешний входной вывод отключается от RX, и прием/передача соединяются друг на друга внутри кристалла.

ADSP BF538 UARTx MCR

Рис. 12-3. UART Modem Control Register (UARTx_MCR).

Регистр состояния линии (UART line status register, UARTx_LSR), содержит информацию о состоянии UART, см. рис. 12-4. Этот регистр доступен только для чтения, что вполне логично.

ADSP BF538 UARTx LSR

Рис. 12-4. UART Line Status Register (UARTx_LSR).

TEMT (TSR and UARTx_THR Empty). Бит состояния опустошения регистра сдвига и буфера передачи. 0: регистры заполнены, 1: оба пусты.

THRE (THR Empty). Бит состояния опустошения буфера передачи. 0: THR не пуст, 1: THR пуст.

BI (Break interrupt). 0: нет сигнализации обрыва потока (No break interrupt), 1: состояние обрыва потока на линии (Break interrupt; это означает, что сигнал RX удерживается в состоянии лог. 0 дольше, чем максимальная длина слова).

FE (Framing Error). Бит ошибки фрейма. 0: ошибки нет, 1: ошибка недопустимого стоп-бита (он не равен лог. 0).

PE (Parity Error). Бит ошибки проверки четности. 0: нет ошибки, 1: ошибка четности.

OE (Overrun Error). Бит потери данных на приеме (переполнение приема). 0: нет переполнения, 1: регистр UARTx_RBR не был прочитан в момент приема нового фрейма, поэтому UARTx_RBR был перезаписан новыми данными, и принятые данные предыдущего фрейма были потеряны.

DR (Data Ready). Готовность данных на приеме. 0: новые данные пока не поступили, 1: регистр UARTx_RBR содержит новые принятые данные.

Биты break interrupt (BI), overrun error (OE), parity error (PE) и framing error (FE) очищаются, когда читается регистр состояния линии UARTx_LSR. Бит data ready (DR) очищается, когда читается регистр буфера приема UARTx_RBR.

Из-за деструктивной природы этих операций чтения должны быть предприняты специальные меры. Дополнительную информацию см. в разделах "Спекулятивное выполнение чтения памяти" и "Поведение чтения памяти по условию" статьи [5].

Бит THRE показывает, что канал передачи UART готов к получению новых данных, и программное обеспечение может записать регистр UARTx_THR. Запись в UARTx_THR очистит бит THRE. Этот бит установится снова, когда данные будут автоматически скопированы из UARTx_THR в регистр сдвига передачи (TSR). Может быть проверен бит TEMT, чтобы определить момент, когда была завершена недавно начатая передача.

Запись в регистр буфера передачи (UART transmit holding register, UARTx_THR) инициирует передачу фрейма. Записанные данные будут перемещены во внутренний регистр сдвига передачи (transmit shift register, TSR), откуда данные будут выдвигаться на внешний вывод TX со скоростью, равной SCLK / (16 x Divisor), вместе с битами старта, стопа, четности - так формируется стандартный асинхронный фрейм. Все фреймы начинаются с перехода 1 -> 0 на линии TX (это сигнализирует о начале стартового бита, по этому моменту будет синхронизироваться прием на стороне получателя данных). Перенос данных из UARTx_THR в регистр сдвига передачи установит бит THRE регистра статуса линии UARTx_LSR.

Регистр UARTx_THR доступен только на запись, и использует один и тот же адрес MMR, что и регистры UARTx_RBR и UARTx_DLL. Чтобы получить программный доступ к UARTx_THR, должен быть очищен бит DLAB в регистре UARTx_LCR. Когда бит DLAB очищен, запись по адресу регистра UARTx_THR будет осуществлять запись в регистр буфера передачи, а чтение по тому же адресу будет осуществлять чтение буфера приема UARTx_RBR. Такое совмещение адреса можно использовать потому, что UARTx_THR доступен только для записи, а UARTx_RBR доступен только для чтения. Таким образом, буферы приема и передачи имеют один и тот же адрес MMR.

Обратите внимание, что данные передаются, начиная с самого младшего бита (LSB), далее биты передаются поочередно по старшинству. Оканчивается передача данных самым старшим битом (MSB), за старшим битом данных следует опционально бит четности и далее стоп-биты (один, полтора или два стоп-бита).

ADSP BF538 UARTx THR

Рис. 12-5. UART Transmit Holding Register (UARTx_THR).

Это регистр буфера приема (UART Receive Buffer, UARTx_RBR). Операция приема использует тот же формат фрейма, что и передача, за исключением количества стоп-битов, для которых всегда подразумевается 1 стоп-бит. После детектирования стартового бита принимаемое слово вдвигается в регистр сдвига приема (receive shift register, RSR) со скоростью (частотой следования бит), определенной как SCLK / (16 x divisor). После приема соответствующего количества бит (включая стоп-бит) обновляются данные и любая статусная информация, и данные автоматически перемещаются из регистра сдвига в буфер приема UARTx_RBR. После перемещения слова данных в UARTx_RBR и соответствующей задержки синхронизации обновляется флаг готовности данных DR в регистре UARTx_LSR.

Частота оцифровки входного сигнала данных происходит с 16-кратной частотой следования бит (baud rate * 16), как можно ближе к ожидаемой середине бита. Из-за того, что внутренняя частота выборки не точно соответствует скорости принимаемого потока данных, точка выборки смещается относительно середины каждого бита. Точка выборки синхронизируется каждый раз заново по началу стартового бита, так что ошибка несоответствия скоростей накапливается по всей длине принимаемого слова (на последнем бите смещение относительно ожидаемого центра становится максимальным). Фильтр приема удаляет случайные импульсы, которые по длительности меньше двух периодов тактов выборки.

Регистр UARTx_RBR предназначен только для чтения, и он использует тот же самый адрес, что и регистр только для записи UARTx_THR и регистр UARTx_DLL. Чтобы получить доступ к UARTx_RBR, должен быть очищен бит DLAB в регистре UARTx_LCR. Когда бит DLAB очищен, запись по MMR-адресу для регистра UARTx_RBR поместит данные в регистр UARTx_THR, а чтение вернет данные из регистра UARTx_RBR.

ADSP BF538 UARTx RBR

Рис. 12-6. UART Receive Buffer Register (UARTx_RBR).

Регистр разрешения прерываний (UART interrupt enable register, UARTx_IER) используется для разрешения запросов к системе для опустошения или заполнения регистров данных UART (см. рис. 12-7). За исключением работы по принципу опроса (без прерываний), в этом регистре обычно должны быть установлены биты ERBFI и/или ETBEI.

ADSP BF538 UARTx IER

Рис. 12-7. UART Interrupt Enable Register (UARTx_IER).

ELSI (Enable RX status interrupt). Бит разрешения прерывания состояния приемной линии. 0: нет прерываний, 1: генерируется прерывание состояния линии приема, если установлен любой из бит UARTx_LSR[4:1] (биты статуса BI, FE, PE, OE).

ERBFI (Enable Receive Buffer Full interrupt). Бит разрешения прерывания по заполнению буфера приема. 0: нет прерываний, 1: генерируется прерывание RX, если установлен бит DR в регистре UARTx_LSR.

ETBEI (Enable Transmit Buffer Empty interrupt). Бит разрешения прерывания по опустошению буфера передачи. 0: нет прерываний, 1: генерируется прерывание TX, если установлен бит THRE в регистре UARTx_LSR.

Установка этого регистра без разрешения системы DMA приведет к тому, что периферийное устройство UART через прерывания будет оповещать процессор о событиях, связанных с данными. Для правильной работы в этом режиме должны быть разрешены системные прерывания, и должны быть предоставлены соответствующие подпрограммы обработки прерываний (ISR). Для обратной совместимости UARTx_IIR все еще корректно отражает состояние прерывания.

Функции UART распределены по 3 отдельным каналам прерывания для независимой обработки передачи данных, приема данных, событий состояния линии, независимо от того, разрешен DMA или нет.

Когда разрешен DMA, UART использует DMA для передачи данных между периферийным устройством UART и памятью процессора. Доступны отдельные каналы DMA для операций приема и передачи данных. Обработка событий ошибки линии может быть сконфигурирована полностью отдельно от приема/передачи.

Регистр UARTx_IER отображен на тот же самый адрес MMR, что и регистр UARTx_DLH. Чтобы получить доступ к UARTx_IER, должен быть очищен бит DLAB в регистре UARTx_LCR.

Чтобы разрешить UART DMA, сначала настраиваются системные управляющие регистры DMA [3], и затем разрешаются прерывания UART установкой бит ERBFI и/или ETBEI в регистре UARTx_IER. Причина в том, что линии запроса прерывания дублируются как линии запроса DMA. В зависимости от того, разрешен DMA или нет при приеме этих запросов, блок управления DMA либо генерирует прямой доступ к памяти, либо передает запрос в прерывание UART через блок системной обработки прерываний. Однако прерывание ошибки UART всегда приходит напрямую в блок системной обработки прерываний, полностью минуя блок DMA.

Бит ELSI разрешает генерирование прерывания на независимом канале прерывания, когда возникает любое из следующих условий по соответствующим битам в регистр состояния линии UARTx_LSR:

• Receive overrun error (OE), ошибка переполнения приема
• Receive parity error (PE), ошибка четности приема
• Receive framing error (FE), ошибка фрейма приема
• Break interrupt (BI), сигнал прерывания потока данных на приеме

Когда установлен бит ETBEI в регистре UARTx_IER, модуль UART немедленно выдает прерывание или запрос DMA. Когда инициируется передача строки (или блока данных), то не требуется никакая специальная обработка для первого символа. Установите бит ETBEI, и позвольте подпрограмме ISR загрузить первый символ из памяти и записать его в регистр UARTx_THR, как обычно. Соответственно, бит ETBEI должен быть очищен, если завершена передача строки.

По соображениям совместимости все еще предоставляется регистр идентификации прерываний (UART interrupt identification register, UARTx_IIR), который отражает состояние прерывания UART. Стандартный метод работы с UART (например, какой-то готовый исходный код, который у Вас есть и его нужно по каким-то причинам использовать) может потребовать объединение всех источников прерываний на 1 канал прерываний, и обслуживать их в одном ISR. Это можно достичь путем глобального назначения всех прерываний UART на один и тот же обработчик ISR, с использованием системных контроллеров прерываний (system interrupt controllers, SICx).

Будучи очищенным, бит ожидающего прерывания (pending interrupt bit, NINT) сигнализирует о том, что прерывание ожидает обработки. Поле STATUS показывает ожидающее обработки прерывание, у которого самый высокий приоритет; прерывание опустошения UARTx_THR имеет самый низкий приоритет. В том случае, когда сигнализируют сразу оба прерывания, UARTx_IIR читается как 0x06.

Когда ожидает обработки прерывание UART, обработчик прерывания (ISR) нуждается в явной очистке защелкнутой информации о прерывании. Ниже на рис. 12-8 показаны защелкиваемые биты регистра UARTx_IIR, и ниже в описании бит показано, как из нужно очищать.

ADSP BF538 UARTx IIR

Рис. 12-8. UART Interrupt Identification Register (UARTx_IIR).

STATUS[1:0]. Основные защелки состояния.

00: зарезервированное состояние
01: регистр UARTx_THR пуст. Запись UARTx_THR или чтение UARTx_IIR очистит запрос прерывания.
10: принятые данные готовы к чтению. Чтение UARTx_RBR очистит запрос прерывания.
11: изменение состояния линии приема. Чтение UARTx_LSR очистит запрос прерывания.

Запрос прерывания TX очищается записью новых данных в регистр UARTx_THR или чтением регистра UARTx_IIR. Обратите внимание на специальную роль чтения регистра UARTx_IIR в том случае, когда ISR не желает больше передавать данные. Если программное обеспечение останавливает передачу, оно должно прочитать UARTx_IIR для сброса запроса прерывания. Пока регистр UARTx_IIR читается как 0x04 или 0x06 (это показывает, что ожидает обработки другое прерывание более высоким приоритетом), защелка опустошения UARTx_THR не может быть очищена чтением UARTx_IIR.

Может возникнуть deadlock (безвыходная блокировка программы), если либо прерывание состояния линии, либо прерывание приема данных было назначено с меньшим приоритетом меньше (назначение приоритетов делается программированием SICx), чем у прерывания опустошения буфера передачи. Чтобы избежать такой ситуации, всегда назначайте самое низкое по приоритету прерывание среди приоритетов UART событию опустошения буфера UARTx_THR.

Из-за деструктивной природы этих операций чтения должны быть предприняты специальные меры. Дополнительную информацию см. в разделах "Спекулятивное выполнение чтения памяти" и "Поведение чтения памяти по условию" статьи [5].

Частота следования бит зависит от системной тактовой частоты (system clock, SCLK) и значения 16-разрядного регистра для настройки делителя (divisor). Значение divisor поделено на два байта - регистр младшего байта защелки делителя (UART divisor latch low byte register, UART_DLL) и регистр старшего байта защелки делителя (UART divisor latch high byte register, UARTx_DLH). Эти регистры вместе формирует 16-разрядный divisor (см. рис. 12-9). Частота следования бит, или скорость (baud rate) может быть вычислена по следующему выражению:

BAUD RATE = SCLK/(16 x divisor)

Если оба регистра, и UARTx_DLL, и UARTx_DLH равны 0, то divisor == 65536.

ADSP BF538 UARTx DLH UARTx DLL

Рис. 12-9. UART Divisor Latch Low Byte Register (UARTx_DLL) и UART Divisor Latch High Byte Register (UARTx_DLH).

Регистр UART_DLL отображен на тот же MMR-адрес, что и регистры UARTx_THR и UARTx_RBR. Регистр UARTx_DLH отображен на тот же самый MMR-адрес, что и регистр UARTx_IER. Должен быть установлен бит DLAB в регистре UARTx_LCR, чтобы можно было получить доступ к регистрам защелки UART divisor. Поскольку установка divisor обычно делается один раз в момент настройки параметров UART перед использованием, то такая адресация не создает проблем для доступа к буферам данных UART и к регистру разрешения прерываний.

Имейте в виду, что 16-битный divisor по умолчанию настроен значениями после сброса регистров UARTx_DLH и UARTx_DLL, в результате чего получается 0x0001, и UART по умолчанию работает на максимально возможной скорости. Если UART не используется, запрет тактов UART экономит энергию, потребляемую от источника питания. Регистры UARTx_DLH и UARTx_DLL могут быть настроены программным обеспечением до или после установки бита UCEN.

В таблице 12-1 предоставлены примеры коэффициентов деления divide, требуемые для поддержки наиболее распространенных стандартных скоростей.

Таблица 12-1. Примеры UART Baud Rate (скорости потока бит) для тактовой частоты системной шины (SCLK) 100 МГц.

Скорость DL Реальная скорость % ошибки
2400 2604 2400.15 0.006
4800 1302 4800.31 0.007
9600 651 9600.61 0.006
19200 326 19171.78 0.147
38400 163 38343.56 0.147
57600 109 57339.45 0.452
115200 54 115740.74 0.469
921600 7 892857.14 3.119
6250000 1 6250000 -

Тщательно выбирайте частоту для SCLK, потому что это позволит точнее выдержать ряд стандартных скоростей RS-232.

Содержимое 8-битного UART scratch register (UARTx_SCR), которые показан на рис. 12-10, после сброса равно 0x00. Он может использоваться как хранилище данных общего назначения, и он никак не управляется аппаратурой UART.

ADSP BF538 UARTx SCR

Рис. 12-10. UART Scratch Register (UARTx_SCR).

Регистр общего управления UART (UART global control register, UARTx_GCTL) содержит бит разрешения для внутреннего тактирования UART и для включения режима IrDA.

ADSP BF538 UARTx GCTL

Рис. 12-11. UART Global Control Register (UARTx_GCTL).

FFE (Force Framing Error on Transmit). 1: принудительно выставить ошибку, 0: нормальное функционирование.

FPE (Force Parity Error on Transmit). 1: принудительно выставить ошибку, 0: нормальное функционирование.

RPOLC (IrDA RX Polarity Change). 1: состоянию ожидания линии приема соответствует лог. 1, 0: состоянию ожидания линии приема соответствует лог. 0.

TPOLC (IrDA TX Polarity Change). 1: состоянию ожидания линии передачи соответствует лог. 1, 0: состоянию ожидания линии передачи соответствует лог. 0.

IREN (Enable IrDA Mode). 1: разрешить режим IrDA, 0: запретить режим IrDA.

UCEN (Enable UART Clocks). 1: разрешить тактирование UART. 0: запретить тактирование UART.

Обратите внимание, что бит UCEN не присутствовал в предыдущих реализациях UART. Он был предоставлен для экономии энергии для случаев, когда UART не используется. При портировании кода убедитесь, что разрешили этот бит, иначе UART работать не будет.

Биты настройки полярности приема и передачи RPOLC и TPOLC работают только в случае разрешенного режима IrDA. Два бита принудительного выставления ошибки FPE и FFE предназначены для целей тестирования. Они полезны для отладки программного обеспечения, особенно в режиме закольцовывания входа на выход (loop back mode).

[Работа с UART без использования DMA]

В режиме без DMA данные перемещаются между регистрами UART и памятью ядром процессора. Чтобы предотвратить какую-либо потерю данных в общем потоке регистр состояния линии UARTx_LSR предоставляет два специальных флага THRE (флаг опустошения буфера) и DR (флаг готовности данных). Чтобы передать символ, программа загружает его в регистр UARTx_THR. Для того, чтобы передать следующий символ, необходимо программно отследить флаг опустошения буфера, и снова загрузить в регистр UARTx_THR код следующего передаваемого символа. Принятые данные могут быть прочитаны из регистра UARTx_RBR, факт наличия новых данных должен быть определен чтением бита готовности данных. Процессор должен каждый раз читать или записывать только один символ.

Флаг THRE устанавливается, когда буфер передачи UARTx_THR готов к записи новых данных, и очищается, когда процессор загрузил в UARTx_THR новые данные. Запись UARTx_THR, когда он еще не опустошился, перезапишет регистр новым значением, и предыдущий символ не будет передан.

Флаг DR сигнализирует, что в UARTx_RBR появились новые данные. Этот флаг очищается автоматически, когда процессор читает из UARTx_RBR. Чтение UARTx_RBR, произошедшее до установки флага DR возвратит предыдущее принятое значение. Когда UARTx_RBR не был прочитан во время, новые данные перетрут те, что уже имеются в регистре UARTx_RBR, и будет установлен флаг переполнения приема (overrun, OE).

С запрещенными прерываниями эти флаги состояния должны постоянно, циклически опрашиваться, чтобы определить момент времени, когда данные доступны для перемещения. Обратите внимание, что такой опрос интенсивно затрагивает вычислительный ресурс процессора, поэтому такой принцип работы без прерываний обычно не используется в системах реального времени с цифровой обработкой сигналов. Программное обеспечение может записать до 2 слов в регистр UARTx_THR перед разрешением тактирования UART. Как только будет установлен бит UCEN, эти 2 слова будут отправлены.

Альтернативно записи и чтения UART могут быть выполнены в обработчиках прерывания (ISR). Отдельные линии прерывания предоставлены для событий UART TX, UART RX и UART Error. Соответствующие этим событиям прерывания могут быть индивидуально разрешены настройкой регистра UARTx_IER.

Обработчики ISR могут оценить поле бит состояния в регистре идентификации прерывания UART (UARTx_IIR), чтобы определить источник, сигнализирующий прерыванием. Если сигнал поступил больше чем от одного источника, поле состояния покажет один из них, у которого выше приоритет. Прерывания также должны быть назначены и демаскированы программированием контроллера прерывания процессора. Обработчики ISR должны явно очистить защелки прерываний UARTx_IIR, см. рис. 12-8.

[Работа с UART через DMA]

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

В канале UART DMA не предоставляется дополнительной буферизации, так что требования к задержкам остаются такими же, как и для режима без использования DMA. Однако теперь задержка определяется активностью шины и механизмом арбитража, и на задержку не влияет загрузка процессора вычислениями и приоритеты прерываний. Дополнительную информацию по DMA см. в статье [3].

Обработчик прерывания DMA должен явно записать единицы в соответствующие регистры статуса DMA IRQ, чтобы очистить защелкнутый запрос на обработку прерывания.

Для того, чтобы разрешить UART DMA, сначала настраиваются системные регистры управления DMA, и затем разрешаются прерывания UART ERBFI и/или ETBEI в регистре UARTx_IER. Так настраивается DMA потому, что линии запроса прерывания дублируются как линии запроса DMA. В зависимости от того, разрешен DMA или нет, при поступлении этих запросов блок управления DMA либо будет генерировать прямой доступ к памяти, либо передаст запрос в прерывание UART на блоке обработки системных прерываний. Однако прерывание ошибки UART напрямую поступает в блок обработки системных прерываний, полностью пропуская блок DMA.

UART DMA поддерживает 8-разрядное функционирование.

[Работа с UART в смешанных режимах]

Режимы без DMA и с DMA используют разные механизмы синхронизации. Следовательно, любой последовательный обмен данными должен быть завершен перед тем, как будет произведено переключение из режима без DMA в режим с DMA, или наоборот. Другими словами, перед переключением от передачи без DMA к передачи через DMA нужно убедиться, что оба регистра, и UARTx_THR, и внутренний регистр сдвига (TSR) пусты, путем проверки битов состояния THRE и TEMT в регистре UARTx_LSR. Иначе процессор будет ждать, пока не очистится 2-битное поле состояния буфера DMA в соответствующем регистре конфигурации передачи UART DMA (UARTx_CONFIG_TX).

При переключении из DMA в работу без DMA убедитесь, что оба канала DMA - канал DMA приема (RX) и канал DMA передачи (TX) - полностью передали свои данные, включая данные, которые содержатся в стеках DMA FIFO. В то время как прерывание DMA RX показывает, что последнее слово данных было записано в память (и покинуло DMA FIFO), прерывание DMA TX показывает, что последнее слово данных покинуло память (и вошло в DMA FIFO). Процессор должен подождать, пока не опустошится TX FIFO путем проверки бита состояния DMA_RUN в канале TX регистра IRQ_STATUS - бит должен очиститься, и только после этого можно безопасно запретить канал DMA.

Отдельно от стандартной функциональности RS-232/RS485, модуль UART также поддерживает полудуплексный последовательный обмен данными через сигналы инфракрасного диапазона в соответствии с рекомендациями от Infrared Data Association (IrDA). Физический слой протокола известен как IrDA SIR (скорость 9.6/115.2 Kbps), он основан на модуляции по принципу "возврата к нулю с инверсией" (return-to-zero-inverted, RZI). Модуляция с позицией импульса (pulse position modulation) не поддерживается.

С использованием 16x тактов скорости данных, формирование модуляции RZI достигается путем инвертирования и модулирования кода "без возврата к нулю" (non-return-to-zero, NRZ), который нормально передается модулем UART. На стороне приема 16x такты используются для определения окна выборки импульса IrDA, из которого восстанавливается код NRZ, модулированный RZI.

Поддержка IrDA разрешается путем установки бита IREN в регистре общего управления UART (UART global control register, UARTx_GCTL). Приложение IrDA требует применения внешних трансиверов.

Описание передатчика IrDA. Чтобы генерировать импульс IrDA, передаваемый модулем UART, сначала обычный вывод NRZ инвертируется так, что 0 передается как импульс лог. 1 длительностью 16 периодов тактов UART, и 1 передается как импульс лог. 0 длительностью 16 периодов тактов UART. Затем начальный срез импульса задерживается на 6 периодов тактов UART. Подобным образом завершающий срез импульса обрезается на 8 периодов тактов UART. В результате получается сигнал изначального 0 как импульс лог. 1 только на 3/16 периодов тактов в 16-тактовом периоде UART. Импульс центрируется возле середины времени бита, как это показано на рис. 12-12. Полученный импульс IrDA поступает на внешний драйвер инфракрасного передатчика.

ADSP BF538 IrDA transmit pulse

Рис. 12-12. Импульс передачи IrDA.

Этот метод модуляции гарантирует, что выходная ширина импульса от UART получится для лог. 1 длительностью в 3 такта на каждые 16 тактовых импульсов UART. Как показано в таблице 12-1, ошибка установки скорости передачи получается очень малой, и входит в допуски стандарта большинства инфракрасных трансиверов.

Описание приемника IrDA. Функция приемника IrDA более сложна, чем функция передатчика. Приемник должен выделить импульс IrDA, и вырезать шум. Чтобы достичь этого, приемник ищет импульс IrDA в узком окне, центрированном посередине ожидаемого импульса.

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

Окно выборки приема определяется по счетчику, который тактируется на 16x частоте от частоты следования бит. Окно выборки пересинхронизируется с каждым стартовым битом, путем центрирования окна выборки вокруг стартового бита.

Полярность принимаемых данных можно выбрать, программируя бит IRPOL. Рис. 12-13 дает примеры каждого типа полярности.

• IRPOL = 0 подразумевает, что на входе в режиме ожидания 0, и каждый активный переход лог. 1 соответствует значению лог. 0 UART NRZ.
• IRPOL = 1 подразумевает, что на входе в режиме ожидания 1, и каждый активный переход лог. 0 соответствует значению лог. 0 UART NRZ.

ADSP BF538 IrDA receiver pulse detection

Рис. 12-13. Детектирование импульса IrDA в приемнике.

Заголовочный файл для модуля подпрограмм UARTapp.cpp:

#ifndef __UARTAPP__
#define __UARTAPP__
 
#define UART0  0
#define UART2  2
 
#define UART0_MMR_OFFSET    0x0000
#define UART2_MMR_OFFSET    0x1D00
 
//для SIC_ISR0, SIC_IWR0, SIC_IMASK0
#define UART0_RX_IRQ 0x00004000
//Для SIC_ISR1, SIC_IWR1, SIC_IMASK1:
#define UART1_RX_IRQ DMA16_IRQ
#define UART2_RX_IRQ DMA18_IRQ
 
#define UART0_TXBUFSIZE  256
#define UART0_TXBUFMASK  (UART0_TXBUFSIZE-1)
#define UART0_RXBUFSIZE  256
#define UART0_RXBUFMASK  (UART0_RXBUFSIZE-1)
#define UART2_TXBUFSIZE  256
#define UART2_TXBUFMASK  (UART0_TXBUFSIZE-1)
#define UART2_RXBUFSIZE  256
#define UART2_RXBUFMASK  (UART0_RXBUFSIZE-1)
 
extern section ("sdram0") u8 bufTXuart0[UART0_TXBUFSIZE];
extern u16 inTXuart0, outTXuart0;
extern section ("sdram0") u8 bufRXuart0[UART0_RXBUFSIZE];
extern u16 inRXuart0, outRXuart0;
extern section ("sdram0") u8 bufTXuart2[UART2_TXBUFSIZE];
extern u16 inTXuart2, outTXuart2;
extern section ("sdram0") u8 bufRXuart2[UART2_RXBUFSIZE];
extern u16 inRXuart2, outRXuart2;
 
void InitUART (u8 uartnum);
void UARTpoll (void);
void UartPuts (u8 uartnum, char *msg);
 
#endif   //__UARTAPP__

Модуль основных подпрограмм, работающих с UART0 и UART2:

//UARTapp.cpp: модуль для консоли, работающей через UART0 (DD2 FT231XQ).
#include < cdefBF538.h >
#include < stdint.h >
#include < string.h >
#include < services_types.h >
#include "uart-debug/ADSP-BF538-UART.h"
#include "UARTapp.h"
 
//Кольцевые буферы передачи и приема для UART0:
section ("sdram0") u8 bufTXuart0[UART0_TXBUFSIZE];
u16 inTXuart0, outTXuart0;
section ("sdram0") u8 bufRXuart0[UART0_RXBUFSIZE];
u16 inRXuart0, outRXuart0;
 
//Кольцевые буферы передачи и приема для UART2:
section ("sdram0") u8 bufTXuart2[UART2_TXBUFSIZE];
u16 inTXuart2, outTXuart2;
section ("sdram0") u8 bufRXuart2[UART2_RXBUFSIZE];
u16 inRXuart2, outRXuart2;
 
EX_REENTRANT_HANDLER(UartInterruptsHandlerData);
 
//***************************************
//* Function Name : short UartGpioInit(unsigned char UartNum)
//* Description   : Настраивает ножки процессора, задействованные под UART.
//*
//* Parameters    : нет
//* Returns       : NULL, если все OK, иначе если отрицательное значение.
//* Globals       : нет
short UartGpioInit(u8 UartNum)
{
    switch (UartNum) {
        case 0: break;
#if defined __ADSPBF538__
        case 1: *pPORTDIO_FER &= ~(PD10|PD11);
                break;
        case 2: *pPORTDIO_FER &= ~(PD12|PD13);
                break;
#endif
#if defined __ADSPBF539__
        case 1: *pGPIO_D_CNFG &= ~(PD10|PD11);
                break;
        case 2: *pGPIO_D_CNFG &= ~(PD12|PD13);
                break;
#endif
        default:
                return -1;
    }
    return 0;
}
 
void UARTpoll (void)
{
   //Обработка передачи UART0
   if(inTXuart0 != outTXuart0)
   {
      //В буфере передачи что-то есть
      if (*pUART0_LSR & TEMT)
      {
         //Можно передавать
         *pUART0_THR = bufTXuart0[outTXuart0];
         outTXuart0++;
         outTXuart0 &= UART0_TXBUFMASK;
      }
   }
   //Обработка передачи UART2
   if(inTXuart2 != outTXuart2)
   {
      //В буфере передачи что-то есть
      if (*pUART2_LSR & TEMT)
      {
         //Можно передавать
         *pUART2_THR = bufTXuart2[outTXuart2];
         outTXuart2++;
         outTXuart2 &= UART2_TXBUFMASK;
      }
   }
}
 
/***************************************
 * Function Name : UartInterruptsHandlerData
 * Description   : стандартный обработчик прерываний приема данных UART.
 *                 он один для всех портов UART.
 *
 * Parameters    : нет
 * Returns       : нет
 * Globals       : нет
//EX_INTERRUPT_HANDLER(UartInterruptsHandlerData)
EX_REENTRANT_HANDLER(UartInterruptsHandlerData)
{
   u16 UartMmrOffset = 0;
   u8 UartNum = 0;
   u32 SicIsr0 = 0;
   u32 SicIsr1 = 0;
 
   SicIsr0 = *pSIC_ISR0;
   SicIsr1 = *pSIC_ISR1;
 
   // Этот код привязан к настройкам, которые сделаны в функции UartInterruptsInit.
   //Определение, на какой порт UARTx пришел символ:
   if (SicIsr0 & UART0_RX_IRQ)
   {
      UartMmrOffset = UART0_MMR_OFFSET;
      UartNum = 0;
   }
   else if (SicIsr1 & UART1_RX_IRQ)
   {
      UartMmrOffset = UART1_MMR_OFFSET;
      UartNum = 1;
   }
   else if (SicIsr1 & UART2_RX_IRQ)
   {
      UartMmrOffset = UART2_MMR_OFFSET;
      UartNum = 2;
   }
   else
   {
      asm("EMUEXCPT; jump 0;");
   }
   
   //Чтение принятого символа:
   volatile u16 *pUartRbr = (volatile u16*) (UART0_RBR + UartMmrOffset);
   if (0==UartNum)
   {
      bufRXconsole[inRXconsole] = *pUartRbr;
      inRXconsole++;
      inRXconsole &= UARTCONS_RXBUFMASK;
   }
   else if (2==UartNum)
   {
      bufRXdebug[inRXdebug] = *pUartRbr;
      inRXdebug++;
      inRXdebug &= UARTDEBUG_RXBUFMASK;
   }
   else
   {
      bufRXdebug[inRXdebug] = '?';
      inRXdebug++;
      inRXdebug &= UARTDEBUG_RXBUFMASK;
   }
   ssync();   
}
 
//***************************************
//* Function Name : short UartInterruptsInit(unsigned char UartNum)
//* Description   : настройка прерываний и обработчика прерывания приема данных.
//*
//* Parameters    : номер порта UART
//* Returns       : NULL, если все OK, иначе отрицательное число.
//* Globals       : нет
short UartInterruptsInit(u8 UartNum)
{
   u16 UartMmrOffset = 0;
 
   switch (UartNum)
   {
   case 0:
      UartMmrOffset = UART0_MMR_OFFSET;
      *pSIC_IAR1   |= PX_IVG(UART0_PERIPHERAL_RX_INT_ID, IVG_UART_DATA);
      *pSIC_IMASK0 |= UART0_RX_IRQ;
      break;
   case 1:
      UartMmrOffset = UART1_MMR_OFFSET;
      *pSIC_IAR3   |= PX_IVG(UART1_PERIPHERAL_RX_INT_ID, IVG_UART_DATA);
      *pSIC_IMASK1 |= UART1_RX_IRQ;
      break;
   case 2:
      UartMmrOffset = UART2_MMR_OFFSET;
      *pSIC_IAR5   |= PX_IVG(UART2_PERIPHERAL_RX_INT_ID, IVG_UART_DATA);
      *pSIC_IMASK1 |= UART2_RX_IRQ;
      break;
   default:
      return -1;
   }
 
   register_handler_ex(IVG_UART_DATA, UartInterruptsHandlerData, EX_INT_ENABLE);
 
   volatile u16 *pUartIer = (volatile u16*) (UART0_IER + UartMmrOffset);
 
   //*pUartIer = (ELSI|ERBFI);
   *pUartIer = ERBFI;
   return 0;
}
 
//***************************************
//* Function Name : short UartInitTerminal(unsigned char UartNum, unsigned long UartBitrate)
//* Description   : конфигурирует UART для обмена с PC-терминалом: 8 бит, no parity, 1 stop bit.
//*
//* Parameters    : номер порта UART, значение скорости UART (бод)
//* Returns       : NULL, если все OK, иначе отрицательное значение. is returned.
//* Globals       : нет
short UartInitTerminal(u8 UartNum, u32 UartBitrate)
{
    u16 UartMmrOffset = 0;
    u16 UartDivisor   = 0;
 
    switch (UartNum) {
        case 0: UartMmrOffset = UART0_MMR_OFFSET; break;
        case 1: UartMmrOffset = UART1_MMR_OFFSET; break;
        case 2: UartMmrOffset = UART2_MMR_OFFSET; break;
        default: printf("%s(): UART%d is not available.\n",__func__,UartNum); return -1;
    }
 
    volatile u16 *pUartGctl = (volatile u16*) (UART0_GCTL + UartMmrOffset);
    volatile u16 *pUartLcr  = (volatile u16*) (UART0_LCR  + UartMmrOffset);
    volatile u16 *pUartMcr  = (volatile u16*) (UART0_MCR  + UartMmrOffset);
 
    if (*pUartGctl & UCEN) { return 0; } // UART уже разрешен
 
    UartGpioInit(UartNum);
    UartSetBitrate(UartNum, UartBitrate);
    // Разрешить тактирование UART:
    *pUartGctl = UCEN;
    // Сброс бита LOOP_ENA гарантирует, что режим Loopback запрещен:
    *pUartMcr = 0;
    // Применить конфигурацию UART:
    *pUartLcr = WLS(8);
    UartInterruptsInit(UartNum);
 
    return 0;
}
 
//***************************************
//* Function Name : short UartPutc(unsigned char UartNum, char c)
//* Description   : функция помещает передаваемый символ в кольцевой буфер передачи.
//*
//* Parameters    : номер порта UART, символ для передачи
//* Returns       : NULL, если все OK, иначе отрицательное значение.
//* Globals       : нет
short UartPutc(u8 UartNum, char c)
{
   u16 UartMmrOffset = 0;
   u8* bufptr;
   u16 *in, bufmask;
    
   if (UART0==UartNum)
   {
      bufptr = bufTXuart0;
      in = &inTXuart0;
      bufmask = UART0_TXBUFMASK;
   }
   else
   {
      bufptr = bufTXdebug;
      in = &inTXdebug;
      bufmask = UARTDEBUG_TXBUFMASK;
   }
   bufptr[*in] = c;
   (*in)++;
   (*in) &= bufmask;
   return 0;
}
 
//***************************************
//* Function Name : short UartPuts(unsigned char UartNum, char *c)
//* Description   : функция передает строку, которая должна завершаться нулем
//*                 (NULL-terminated string, ASCIIZ, строка стиля языка C).
//*
//* Parameters    : номер порта UART, указатель на строку для передачи.
//* Returns       : NULL, если все OK, иначе отрицательное значение.
//* Globals       : нет
short UartPuts(u8 UartNum, char *c)
{
    while (*c) {
        UartPutc(UartNum, *c);
#if(0) // об этом может позаботиться uprintf
        if (*c == '\n') { // 0x0A, новая строка?
            UartPutc(UartNum, '\r'); // 0x0D, вставка carriage return
            return 0;
            }
        else if (*c == '\r') { // 0x0D, carriage return?
            UartPutc(UartNum, '\n'); // 0x0A, вставка символа новой строки
            return 0;
            }
        else { c++; }
#else
        c++;
#endif
        }
    return 0;
}
 
//Инициализирует порт UART
void InitUART (u8 uartnum)
{
   //Очистка кольцевого буфера:
   if (0==uartnum)
   {
      inTXuart0 = 0; outTXuart0 = 0;
   }
   else if (2==uartnum)
   {
      inTXuart2 = 0; outTXuart2 = 0;
   }
   //Настройка порта UART:
   UartInitTerminal(uartnum,
                    115200);
}

Модуль основной программы (main.cpp):

//*****************************************************************************
// Пример программы для Blackfin ADSP-BF538, использующий порты UART0 и UART2.
// Прием символов настроен по прерываниям, символы попадают в кольцевые буферы
// bufRXuart0 и bufRXuart2 (обработка данных в кольцевых буферах для упрощения
// не реализована).
//
// Передача также осуществляется через кольцевые буферы (bufTXuart0 
//  и bufTXuart2), данные в кольцевой буфер передачи помещается вызовом 
//  UartPuts, передача осуществляется посимвольно вызовами UARTpoll.
//*****************************************************************************
#include "Units\Timer.h"
#include "pins.h"
#include "WEX025664.h"
#include "delay.h"
#include "uart-debug/BfDebugger.h"
#include "strval.h"
#include "UARTapp.h"
 
int main()
{
   InitCore();
   
   ConfigureInputs();
   ConfigureOutputs();
   
   PowerON();
   
   InitUART(0);
   InitUART(2);
   Beep(100);
   while(1)
   {
      if(buttonApressed())
      {
         Beep(100);
         UartPuts(UART0, "test UART0\r\n");
      }
      if(buttonBpressed())
      {
         Beep(200);
         UartPuts(UART2, "test UART2\r\n");
      }
      UARTpoll();
      // Тут можно вставить вызовы процедур обработки буферов приема
      //  bufRXuart0 и bufRXuart2, а также другой периодически вызываемый
      //  код.
   }
}

[Ссылки]

1. ADSP-BF538/ADSP-BF538F Blackfin® Processor Hardware Reference site:analog.com.
2. Blackfin ADSP-BF538.
3. ADSP-BF538: DMA.
4. ADSP-BF538: управление портами GPIO C, D, E.
5. Память Blackfin.
6. Blackfin: форматированный вывод в окно терминала через UART.
7. Blackfin пишем драйвер последовательного порта site:kit-e.ru.

 

Добавить комментарий


Защитный код
Обновить

Top of Page