USART в Xmega

    Данная статья просвещенна особенностям использования и настройки USART микропроцессора Xmega.
    USART (Universal Synchronous Asynchronous Receiver Transmitter – перев. Универсальный Синхронный Асинхронный Приемник Передатчик) является основным элементом в последовательной передачи данных между компьютерами, терминалами и другими устройствами. USART поддерживает полноценную дуплексную передачу как в асинхронном так и в синхронном режиме.
    Передача выполняется посылками, формат которых задается пользователем и позволяет добиться совместимости с различными стандартами. Модуль USART буферизован в обоих направлениях, что позволяет добиться непрерывности передачи данных без каких-либо пауз между посылками. Предусмотрены отдельные векторы прерываний по завершению приема и передачи, что позволяет реализовать управление связью по прерываниям. Ошибки в посылке и по переполнению буфера обнаруживаются на аппаратном уровне, о чем сигнализируют отдельные флаги статуса. Также поддерживается генерация и проверка паритета (четность или нечетность).
    В статье будет рассматриваться асинхронный режим приема-передачи, т.е. режим в котором часы приемника и передатчика не синхронизированы.
    Принцип работы
    Передача по UART основана на символах (кусках), размер символа может быть установлен величиной 5, 6, 7, 8 или 9 битов. Каждому символу (куску посылки) предшествует стартовый бит, а по завершению следует один или два стоповых бита. Стартовый бит всегда низок и противоположен высокому состоянию линии.
    Дополнительно можно включить бит четности, который располагается после битов данных и до стоповых битов. Бит четности помогает обнаружить ошибку в один бит, но бесполезен при ошибки в несколько битов.
    На следующем рисунке показана возможная посылка с одним стартовым битом, 8 битами данных, битом четности и 2 стоповыми битами.
    Модуль USART
    В микропроцессоре XMEGA модуль USART находится по умолчанию в режиме UART (асинхронный режим передачи). Разрешение на прием и передачу устанавливается независимо, обмен может осуществляться по результатам опроса флагов или по прерываниям. За исключением тех случаев, когда используется 9-битный размер символов для передачи данных USART достаточно прост в использовании.
    Использование 9-битных символов требует особого внимания. При приеме и чтении полученных данных необходимо учесть, что 9-ый бит (RXB8) расположен в регистре USARTxn.STATUS. Поскольку флаг RXCIF очищается по чтению регистра USARTxn.DATA, то бит RXB8 должен быть считан раньше, чем будет считан последний бит в регистре USARTxn.DATA.
    При передаче учтите, что 9-ый бит TXB8 расположен в регистре USARTxn.CTRLB. Запись младшего байта в регистр USARTxn.DATA запускает процесс передачи посылки, поэтому бит TXB8 должен быть записан первым.
    Буферы
    USART имеет двойную буферизацию как по приему (RX), так и по передаче (TX). В дополнение к сдвиговым регистрам RX и TX, соединенных с ножками ввода-вывода, есть два буферных регистра – это буферные регистры для RX и TX. Один регистр называется регистром данных, а другой буферным регистром. В нормальном режиме работы можно использовать только регистр данных, так как данные автоматически аппаратными средствами перемещаются из буфера данных в сдвиговый регистр и обратно. Регистры данных RX и TX имеют одинаковый физически адрес, но при чтении открывается доступ к регистру данных приема, а при записи к регистру данных передачи. Общий принцип буферизации показан на следующем рисунке:
    Когда символ (кусок) принят в сдвиговый регистр, он копируется в буфер, после чего сдвиговый регистр готов к приему второго (или третьего) символа. Учтите что, если три символа были получены, а регистр данных не считан, то прием четвертого символа приведет к потере третьего символа в сдвиговом регистре. В этом случае будет установлен флаг переполнения BUFOVF в регистре USARTxn.STATUS. Необходимо считывать принятые данные достаточно часто, чтобы избежать потери данных, которая может потребовать дополнительных аппаратных буферов или основных прерываний.
    Буфер передачи, так же как и буфер приема, является трехуровневым буфером, работающим по принципу «первый пришел – первый вышел» и открывается для записи третьего символа, как только первый уровень буфера будет скопирован в регистр сдвига и начнется обмен.
    Флаги
    Важными флагами для работы USART являются: флаг завершения приема RXCIF, флаг завершения передачи TXCIF и флаг пустоты регистра данных DREIF.
    Флаг RXCIF установлен, когда в буфере приема есть непрочитанные данные и очищен, когда буфер приема пуст. Флаг RXCIF очищается чтением данных и не может быть очищен вручную. Флаг TXCIF установлен, когда вся посылка была отправлена из сдвигового регистра и буфер передачи не содержит новых данных. Флаг DREIF указывает на то, что буфер передачи USARTxn.DATA пуст и готов к приему данных.
    Флаги TXCIF и DREIF могут показаться одинаковыми, но между ними есть разница, которая может быть использована для ускорения передачи данных. TXCIF неустановлен до тех пор, пока USART не завершит передачу всех данных из сдвигового регистра передачи и буфер передачи не очистится. А флаг DREIF устанавливается при занятом буферном регистре. Это означает, что новые данные могут быть помещены в буфер до того, до полной передачи из него данных, что позволяет избежать паузы между передачей символов.
    Все три флага могут использоваться для генерации прерываний.
    Выбор скорости передачи
    В XMEGA в дополнение к битам BSEL[11:0] в регистрах USARTxn.BAUDCTRLA и USARTxn.BAUDCTRLB управляющие генератором часов скорости передачи есть биты BSCALE[3:0] находящиеся в регистре USARTxn.BAUDCTRLB управляющие арифметической настройкой часов скорости передачи.
    При установке BSCALE в 0 (значение по умолчанию), генератор скорости передачи работает без дополнительного масштабирования, и скорость устанавливается в BSEL[11:0] согласно следующему выражению:
    fBAUD = fPER / 16 (BSEL[11:0] + 1)
    При использовании только стандартного режима возможен достаточно широкий выбор скоростей передачи, но биты BSCALE[3:0] позволяют добиться большей гибкости в диапазоне задания скоростей. Установка битов в значение от -7 до 7 (кроме 0) включает арифметическое масштабирование часов и расширяет возможные варианты скоростей передачи.
    BSCALE позволяет масштабировать скорость в большую или меньшую сторону. Положительное значение BSCALE приводит к масштабированию в меньшую сторону, т.е. приводит к увеличению периода и, следовательно, к снижению скорости предачи. При этом, разрешающая способность остается без изменений. Если же BSCALE отрицательный, делитель будет использовать дробную арифметику подсчета, которая увеличивает разрешающую способность. Максимальное значение весового коэффициента ограничено. Значение 2BSCALE не может быть больше половины минимального числа циклов синхронизации, которые требуются для обработки посылки.
    В микроконтроллерах Xmega имеется возможность удвоения скорости передачи в асинхронном режиме, установкой бита CLK2X в регистре USARTxn.CTRLB, для повышения скорости обмена при работе с пониженными частотами синхронизации. В этом режиме приемник сокращает количество выборок, которые используются для приема данных и восстановления синхронизации, с 16 до 8. Вследствие такого снижения, требуется более точная настройка скорости и более точный источник синхронизации.
    Выражения для вычисления настройки регистра скорости показаны в таблице:
    Инициализация USART
    Инициализация USART выполняется по следующей последовательности:
    - Установка высокого уровня на выводе TxD и опционально низкого уровня на выводе XCK.
    - Настройка TxD и опционально XCK на вывод
    - Настройка скорости передачи и формата посылки.
    - Выбор режима работы (при выборе синхронного режима разрешается работа выхода XCK).
    - Разрешение работы передатчика и/или приемника в зависимости от необходимости.
    При управлении передачей по прерываниям перед инициализацией необходимо отключить работу прерываний.
    Перед выполнением повторной инициализации затрагивающей настройки скорости или формата посылки, необходимо, чтобы во время изменения регистров передача не выполнялась. Убедится в завершении отправки всех данных передатчиком и наличия несчитанных данных в буфере приемника, можно с помощью флагов прерываний.
    Отправка данных передатчиком USART
    После разрешения работы передатчика, нормальная работа порта на выводе TxD перекрывается сигналом с выхода передатчика USART. Дополнительно, в регистре направления вывод TxD должен быть настроен как выход.
    Передача данных инициируется записью отправляемых данных в буфер передачи (DATA). Данные из буфера передачи перемещаются в сдвиговый регистр, после освобождения которого возможна отправка новой посылки. Запись в сдвиговый регистр выполняется, когда он не занят передачей или сразу после передачи последнего стоп-бита предыдущей посылки. После записи данных в сдвиговый регистр, он передает посылку.
    По завершении передачи посылки и при условии, что в буфере передачи нет новых данных, происходит установка флага прерывания завершения передачи (TXCIF) и генерируется прерывание.
    Запись в регистр передаваемых данных (DATA) возможна только, когда установлен флаг пустоты регистра данных (DREIF).
    При работе с посылками с числом бит меньшим восьми, старшие биты, записанные в регистр DATA, игнорируются. При передаче 9-битных данных, девятый бит данных необходимо записать в бит TXB8 перед записью младшего байта данных в DATA.
    Отключение передатчика
    Отключение передатчика вступит в силу только тогда, когда полностью завершится передача данных, в том числе выполняющаяся в данный момент и подготовленная, т.е. когда окажутся свободными от данных сдвиговый регистр передатчика и буферный регистр передатчика. После отключения передатчика также отключается перекрытие ножки TxDn.
    Получение данных приемником USART
    После разрешения работы приемника, вывод RxD функционирует, как вход приемника USART. Данный вывод необходимо настроить как вход (настроен по умолчанию).
    Приемник начинает прием данных после обнаружения действительного стартового бита. Вслед за стартовым битом происходит выборка каждого бита данных на частоте генератора скорости или частоте на ножке XCK и помещение их в сдвиговый регистр. Так происходит вплоть до приема первого стопового бита посылки. Второй стоп-бит игнорируется приемником. После приема первого стопового бита и когда в сдвиговый регистр приемника полностью принята посылка, содержимое сдвигового регистра перемещается в буфер приемника. Устанавливается флаг прерывания по завершению приема (RXCIF) и генерируется соответствующие прерывание.
    Опрос буфера приемника можно выполнить чтением регистра данных (DATA). Чтение регистра DATA нельзя выполнять, если флаг прерывания по завершению приема равен нулю. При работе с посылками с числом бит меньше 8, неиспользуемые старшие биты будут считываться с нулевыми значениями. При работе с 9-битными данных, девятый бит необходимо считать из бита RXB8 перед чтением принятых данных из регистра DATA.
    Существуют три флага ошибок USART. Флаги ошибки в посылке (FERR), переполнения буфера (BUFOVF) и ошибки четности (PERR) доступные в регистре статуса. Флаги ошибок расположены в приемном буфере, работающем по принципу «первый пришел – первый вышел», вместе с соответствующей им посылкой. Как следствие буферизации флагов ошибок, чтение регистра статуса необходимо выполнить перед чтением буфера (DATA), т.к. чтение регистра DATA приводит к изменению буфера.
    При разрешении проверки четности (паритета) для каждой принятой посылки вычисляется четность её бит данных, а результат вычислений сравнивается с принятым в соответствующей посылке битом четности. Если обнаруживается несовпадение, устанавливается флаг ошибки четности.
    Отключение приемника
    Отключение приемника происходит незамедлительно. Буфер приемника очищается, а выполняющийся прием прерывается с потерей всех данных.
    Очистка буфера приемника
    При необходимости очистки буфера приемника в ходе работы приемника, необходимо выполнить чтение регистра DATA, пока флаг прерывания по завершению приема равен нулю.
    DMA передача
    DMA в XMEGA позволяет осуществить передачу данных в USART. Это может использоваться для уменьшения загрузки центрального процессора при обмене большими блоками данных. DMA может быть установлен для генерации прерываний, по завершению блоков данных.
    Процедура обработки прерываний для USART
    Покажем пример обработки прерываний при использовании USART C0. В случае использования другого USART процедуры обработки прерываний будут аналогичны показанным ниже.
#pragma vector=USARTC0_RXC_vect 
__interrupt void USARTC0_RxcIsr(void)
{
USART_Rxc(&USART_C0);
}
#pragma vector=USARTC0_DRE_vect
__interrupt void USARTC0_DreIsr(void)
{
USART_Dre(&USART_C0);
}
    Процедуры обработки прерываний вызывают функции (USART_Rxc и USART_Dre) с указателем соответствующего USART в качестве параметра.
    Напоследок приложим реальный пример по обмену с помощью UART, выполненный на микропроцессоре Xmega 128A.
    Пример. Достаточно часто необходимо обмениваться данными между процессорами расположенными на одной или разных платах – для этих целей хорошо подходят интерфейсы, реализованные на UART (в том числе RS-232 и RS-485). Суть программы заключается в том, что на одном микропроцессоре опрашивается входной порт, полученное состояние отправляется по UART на другой микропроцессор, который выставляет аналогичный порт в полученное состояние. Т.е. на втором процессоре порт будет отображать состояние первого.
    Для иллюстрации общего принципа работы UART не будем привязываться к какому-либо конкретному протоколу и интерфейсу. Для простоты возьмем одностороннюю передачу, т.е. один процессор только отправляет данные, а другой только принимает. Чаще всего для исключения ложных приемов используются специальные протоколы, содержащие различные маски и контрольные суммы, но их применение требует особого рассмотрения (может как-нибудь позже), поэтому для избежания ложных приемов, посылка будет содержать лишь адрес устройства, которому предназначается передача и размер посылки.
    Задача 1: Написать программу передатчика, выполняющего считывание ножек порта D и отправки полученных данных порта по UART с частотой передачи посылки 10 Гц (10 раз в секунду).
    Будем использовать внутренний RC-генератор с частотой 2 МГц, передачу с заданной частотой будем осуществлять по прерыванию таймера ТС0 настроенного на 10 Гц. Для передачи будем использовать USART E0 (ножка PE3), в асинхронном режиме и со скоростью обмена близкой к 115200 бит/с. Для дополнительной защиты включим контроль четности передачи по UART. Адрес устройства, которому будет отправлена посылка, примем равным 5. Также для наглядности будем менять уровень сигнала на ножке PC0, при успешной передачи посылки, т.е. при нормальной работе передатчика на ножке PC0 будет меандр с частотой 5 Гц (уровень сигнала меняется с частотой 10 Гц).
    Код работающей программы передатчика для процессора Xmega A1 имеет следующий вид:
#define ENABLE_BIT_DEFINITIONS     // разрешение использования групповых битовых имен 
/* Объявление используемых библиотек */
#include <ioxm128a1.h>
#include <ina90.h>
/* Объявление глобальных переменных */
unsigned char Tx_cnt; // Счетчик числа отправленных байтов
unsigned char Tx_L; // Длина передаваемого сообщения (в байтах)
unsigned char Tx_buf[3]; // Временный буфер передачи данных
void main(void)
{
__disable_interrupt(); // Отключение прерываний
/* Настройка таймера TCС0 */
TCC0.CTRLA=0x05; // N=64;
TCC0.PER=3125-1; // частота таймера 10Гц при частоте процессора 2МГц
TCC0.INTCTRLA=1; // уровень прерываний таймера low
/* Настройка UART E0 */
USARTE0.CTRLC= USART_PMODE1_bm | USART_CHSIZE0_bm | USART_CHSIZE1_bm; // Асинхронная передача, 8 битов данных, 1 стоповый бит, проверка четности включена
USARTE0.BAUDCTRLA=0x91; // BSEL = 401
USARTE0.BAUDCTRLB=0xC1; // BSCALE = -4, Реальная скорость передачи бита: 115108, Ошибка от 115200: -0.08 %
USARTE0.CTRLB=USART_TXEN_bm;// Включить передатчик
USARTE0.CTRLA=USART_DREINTLVL0_bm | USART_TXCINTLVL0_bm; // Присвоить прерываниям по TXC и DRE уровень low
PORTC.DIRSET=0x01; // Настройка ножки 0 порта C как выход
PORTE.DIRSET=0x08; // PE3 (TXD0) как выход
PMIC.CTRL = 1; // приоритет прерываний уровня low
__enable_interrupt(); // Разрешение прерываний
while(1) {} // Основной бесконечный цикл
}
#pragma vector=TCC0_OVF_vect // обработка прерываний по переполнению таймера TCС0
__interrupt void irqTCC0_OVF_vect(void)
{
Tx_L=3; // Установка длины посылки в байтах
Tx_buf[0] = 5; // Запись в буфер посылки адреса принимающего устройства
Tx_buf[1] = Tx_L; // Запись в буфер посылки количество посылаемых байтов
Tx_buf[2] = PORTD.IN; // Запись в буфер посылки состояние ножек порта D
Tx_cnt = 0; // Очистка счетчика передачи
USARTE0.CTRLA |= (1<<(USART_DREINTLVL0_bp)); // разрешаем прерывание "Регистр данных пуст"
}
#pragma vector = USARTE0_DRE_vect // обработка прерываний по пустоте регистра данных USART E0
__interrupt void irqUSARTE0_DRE_vect(void)
{
USARTE0.DATA = Tx_buf[Tx_cnt++]; // запись в регистр данных USART следующий байт посылки
if (Tx_cnt < Tx_L) return; // Если вся посылка передана то выход
USARTE0.CTRLA &= ~(1<<(USART_DREINTLVL0_bp)); // запрещаем прерывание "Регистр данных пуст"
USARTE0.STATUS |= (1<<(USART_TXCIF_bp)); // очищаем флаг "Передача завершена"
}
#pragma vector = USARTE0_TXC_vect // обработка прерываний по окнчанию передачи данных USART E0
__interrupt void irqUSARTE0_TXC_vect(void)
{
PORTC.OUTTGL=0x01; // переключение уровня сигнала на выходе ножки PC0
}
    Задача 2: Написать программу приемника, выполняющего получение данных по UART и выдачу их на ножки порта D.
   Будем использовать внутренний RC-генератор с частотой 2 МГц. Для приема будем использовать USART E1 (ножка PE6), в асинхронном режиме и со скоростью обмена близкой к 115200 бит/с. Адрес приемника был принят ранее равным 5.
    Код работающей программы приемника для процессора Xmega A1 имеет следующий вид:
#define ENABLE_BIT_DEFINITIONS     // разрешение использования групповых битовых имен 
/* Объявление используемых библиотек */
#include <ioxm128a1.h>
#include <ina90.h>
/* Объявление глобальных переменных */
unsigned char Rx_cnt; // Счетчик числа принятых байтов
unsigned char Rx_L; // количество байтов в посылке
unsigned char Rx_buf[3]; // Временный буфер приема данных
unsigned char UART_Node; // Счетчик вершин обращений
char Addr=5; // Адрес приемника
void main(void)
{
__disable_interrupt(); // Отключение прерываний
/* Настройка UART E1 */
USARTE1.CTRLC= USART_PMODE1_bm | USART_CHSIZE0_bm | USART_CHSIZE1_bm; // Асинхронная передача, 8 битов данных, 1 стоповый бит, проверка четности включена
USARTE1.BAUDCTRLA=0x91; // BSEL = 401
USARTE1.BAUDCTRLB=0xC1; // BSCALE = -4, Реальная скорость передачи бита: 115108, Ошибка от 115200: -0.08 %
USARTE1.CTRLB=USART_RXEN_bm;// Включить приемник
USARTE1.CTRLA=USART_RXCINTLVL0_bm; // Присвоить прерыванию по RXC уровень low
PORTD.DIRSET=0xff; // Настройка всех ножек порта D как выходы
PMIC.CTRL = 1; // приоритет прерываний уровня low
__enable_interrupt(); // Разрешение прерываний
while(1) {} // Основной бесконечный цикл
}
#pragma vector = USARTE1_RXC_vect // обработка прерываний по приему данных USART E1
__interrupt void irqUARTE1_RXC_vect(void)
{
register unsigned char data; // Регистр приема кадра посылки
if (USARTE1.STATUS & (1<<USART_PERR_bp) || USARTE1.STATUS & (1<<USART_FERR_bp)) return; // При ошибки по четности или приему кадра, то выход
data = USARTE1.DATA; // Чтение данных и запись в регистр приема кадра посылки
Rx_buf[Rx_cnt++] = data; // Чтение данных и заполнение буфера приема
switch (UART_Node)
{
case 0: // Принимаем адрес
if (data != Addr) // Если принятый адрес не совпадает с адресом контроллера, то сброс счетчиков и выход
{
UART_Node=0;
Rx_cnt=0;
return;
}
UART_Node=1; // Установка счетчика вершин обращений в 1 (начало приема посылки)
return;
case 1: // Принимаем количество байтов в посылке
UART_Node++; // Инкрементация счетчика вершин обращений
Rx_L = Rx_buf[UART_Node]; // Сохранение количество байтов в посылке
return;
case 2: // Принимаем данные
PORTD.OUT = Rx_buf[UART_Node]; // Выдача на порт D принятых по USART данных
UART_Node = 0; // Сброс счетчика вершин обращений
Rx_cnt=0; // Сброс счетчика числа принятых байтов
return;
}
}
    Blogger Comment
    Facebook Comment

0 коммент.:

Отправить комментарий