USART и UART: в чем различие
Поправлял ли вас когда-нибудь коллега, говоря, что это не UART, а USART? Иногда взаимозаменяемость этих терминов может быть вполне допустимой, но во многих случаях будет ошибкой. Давайте же рассмотрим внимательнее, что представляют собой USART и UART, и в чем их основные различия.
Большинство разработчиков встраиваемых систем знают, что такое UART: Universal Asynchronous Receiver/Transmitter (универсальный асинхронный приемник/передатчик). Это периферийное устройство микроконтроллера, преобразующее входящие и исходящие байты в последовательный поток данных. Стартовый бит инициирует начало передачи потока битов, а стоповый бит (или два) завершает слово данных. Кроме того, для выявления ошибок при передаче данных UART может вставлять в поток контрольный бит. На Рисунке 1 показан стандартный пример того, что ожидают увидеть инженеры при передаче данных через UART.
USART – Universal Synchronous/Asynchronous Receiver/Transmitter (универсальный синхронный /асинхронный приемник/передатчик) – ‘это периферийное устройство микроконтроллера, преобразующее входящие и исходящие байты в последовательный поток данных. Хм. Определение USART ничем не отличается от UART, за исключением одного добавленного слова «синхронный». Но должны же быть какие-то более значимые различия? Иначе USART был бы известен просто как UART.
Да, различия есть, причем весьма существенные. Первое отличие USART от UART определяется тем, каким образом могут синхронизироваться последовательные данные. Сигналы тактирования UART генерируются внутри микроконтроллера и синхронизируются с потоком данных по переходу стартового бита. Каких-либо входящих синхросигналов, связанных с данными, здесь нет, поэтому для правильной обработки принимаемых данных приемник должен заранее знать, какой будет скорость передачи.
Напротив, USART может быть настроен для работы в синхронном режиме. В этом режиме отправляющая данные периферия генерирует сигнал синхронизации, который периферией приемной стороны может быть извлечен из потока данных без априорной информации о скорости передачи. Возможен и другой вариант, когда для сигнала синхронизации выделяется отдельная линия. Использование внешнего сигнала синхронизации позволяет USART работать на скоростях до 4 Мбит/с – недостижимых для стандартных UART.
Другое важное отличие USART от UART заключается в количестве поддерживаемых периферийных протоколов. UART прост, и может предложить лишь небольшие вариации базового формата – количество стоповых бит и способ контроля ошибок (по четности или нечетности). USART намного сложнее и способен формировать потоки данных, совместимые со многими стандартными протоколами; IrDA, LIN, Smart Card, Driver Enable для RS-485 и Modbus – лишь несколько из них. При этом USART может, как и UART, работать в асинхронном режиме, что позволяет ему генерировать точно такие же типы последовательных данных, какие показаны на Рисунке 1.
Рисунок 1. | Поток последовательных данных UART. |
Периферийные устройства USART и UART имеют определенно различные возможности и могут быть полезны в различных ситуациях, поэтому в стандартном микроконтроллере разработчик может обнаружить оба интерфейса. К примеру, возьмем микроконтроллеры семейства STM32, основной областью применения которых являются микромощные приложения. Среди периферийных устройств на кристаллах этих приборов есть как USART, так и UART. USART предназначен для выполнения «тяжелой работы» по последовательному обмену в периоды «большого» расхода энергии. Когда же микроконтроллер находится в спящем режиме или в режиме с пониженным потреблением, используется UART, способный выполнять низкоскоростной обмен, не выходя за рамки допустимого лимита энергии.
Так можно ли говорить, что USART и UART – это одно и тоже? Технически правильный ответ – «нет». USART, как правило, имеет набор функций, расширенный по сравнению с UART, и способен обрабатывать синхронизированные потоки данных на скоростях, во много раз превышающих скорости UART. Действительно, USART может выполнять все функции UART, и, возможно, поэтому во многих приложениях разработчики, имея в руках всю мощь USART, используют их как простые UART, игнорируя преимущества синхронного тактирования. Неудивительно, что очень многие используют эти термины так, будто они являются синонимами.
ARM Учебный курс. USART
Вообще у STM32 сей девайс навороченный и умеет не только байтики в терминалку слать в классических режимах (асинхронном, синхронном, мультипроцессорном), но и кое чего еще. В частности он может работать в
- Однопроводном полудуплексном режиме
- В режиме SmartCard — т.е. на том же языке на котором общаются с телефоном SIM карты. Вообще там вроде бы протокол отличается только таймингами немного
- В режиме IrDA — помните на старых телефонах была такая фиговина? Вот это оно. Отличается от обычного протокола тем, что тут данные передаются краткими импульсами. Этакими вспышками. А 0 и 1 ловятся по паузам между ними. Так себя фотоприемники видать лучше чувствуют.
- Также есть LIN режим. LIN это автомобильная сеть, этакий CAN для бедных. Вон во всяких приорах стекла и сигналки на LIN шине сидят.
В общем, полный фарш. Расписывать все не буду. Только самое основное. Иначе это книгу написать можно.
Не все блоки одинаково могучи, зависит от номера. А количество блоков зависит от модели проца. Чем жирней проц, чем больше у него ног, тем больше у него блоков USART. Всего их может быть 6 и в зависимости от номера умеют они следующее:
▌Состав
Итак, из чего состоит USART на STM32?
Снаружи это выводы RX и TX. А также всякие CTS и RTS для управления потоком данных. Блоков у нас три, так что данных штуковин у нас тоже 3 комплекта.
Распиновка выглядит как то так. Вроде нигде не ошибся 🙂 Если каких то выводов нет у вас вживую, ничего страшного, просто у вас не тот корпус. Модификация F103C8 идет в разных корпусах. От 36 до 100 ног.
Т.е. можно ремапить все UART выводы на другие ноги. Это удобно при разводке. О ремапе портов было рассказано в главе про GPIO
Внутри надо смотреть на каких шинах сидят UART блоки, чтобы тактирование им подрубить. Тут нам поможет блок схема контроллера, оттуда же, из даташита на подсемейство.
По ней видно, что UART1 сидит на APB2, а остальные на APB1
А на софтверном уровне UART для нас это прежде всего регистры и флаги. Вот ща ими и займемся. Опять же глубоко копать не буду. Только самое основное.
▌Регистры
USART_SR Status Register. Регистр состояния автомата передатчика. Тут все флаги по которым можно понять, что происходит вообще с передачей данных.
- CTS — ставится в 1 когда идет запрос на прием данных по линии CTS. Если конечно это разрешено в настройках битом CTSE. Также по этому флажку генерируется прерывание. Сбрасывается вручную.
- LBD — LIN Break flag. Какой то запрос от LIN шины. Сбрасывается вручную, умеет выдавать прерывание.
- TXE — Tx Empty. Передатчик пуст, можно кидать следующий байт. Может сгенерировать прерывание. Сбрасывается сам, когда записываем в USART_DR.
- TC — Transmit Complete. Передача завершена. От TXE отличается тем, что у нас не просто буфер пустой, а еще и сдвиговый регистр отстрелялся. Может генерировать прерывание. Сбрасывается либо вручную, либо автоматически при чтении из USART_SR с последующей записью в USART_DR.
- RXNE — Read data register not empty. Что то нам на вход пришло и можно забирать. Генерит прерывание и сбрасыватся либо ручками, либо чтением из USART_DR регистра.
- IDLE — IDLE line detected. Линия свободна, можно вещать. Может генерировать прерывание и сбрасывается чтением сначала USART_SR, потом USART_DR. Думаю это можно трактовать как конец приема. Когда данные пришли и новых на линии нет.
- ORE — Overrun error. Просрали байт. Сливай воду. Выскакивает когда данные не успеваем считывать, а новые все лезут и лезут. Генерирует прерывание (куда же без него) и сбрасывается когда мы сначала читаем регистр статуса, а потом заглядываем в регистр данных. Причем тут есть нюанс. Убиваются входящие данные только в сдвиговом регистре. Т.е. пока мы сами не прочитаем данные из регистра данных им ничего не грозит.
- NE — Noise error flag. Срач в линии. Тоже есть прерывание. Сбрасывается точно также как и ORE.
- FE — Frame Error. Ошибка кадра. Это если данные побились по ходу. Ну например, частота если плавает у передатчика и в линию идет какая то странная фигня. Ведь USART асинхронный и там все на время завязано. Дает прерывание, сбрасывается точно также как и ORE.
- PE — Parity Error. Ошибка контроля четности. Очищается также как и прошлые три, но тут надо перед сборосом подождать пока встанет бит RXNE. Дает прерывание. Кто бы сомневался 🙂
USART_DR — Data Register. Сюда падают данные, сюда же мы грузим данные для отправки. Занимает 32 бита из которых используются только 9 (!) первых бит, остальные принудительно зануляются аппаратно. Как и в AVR физически это двухголовый регистр с одним именем. Разница только между чтением и записью. Читаем из приемника, а записываем в передатчик. И также как в AVR данные отсюда проваливаются сразу же в сдвиговый регистр USART и полетели…
USART_BRR — Baud rate register. Регистр задания бодрейта. Первые его два байта определяют частоту передачи. Вторые принудительно ноль. Также как и в AVR.
Как вычислить USARTDIV? Даташит нам предлагает такую формулу:
Только тут надо учитывать тот прикол, что тактуется USART с шины APB и частоту для бодрейта надо вычислять исходя из этой величины, а не частоты ядра, которая может очень сильно отличаться от частоты шины периферии. Подробней о частотах в главе про RCC и тактирование. И про эти вилы забывать нельзя. Помните СКОЛЬКО возможных режимов тактирования есть у STM32 и как там лихо все разветвляется.
Осталось только ее пересчитать в целую и дробную часть. Делается это так:
Например, у нас частота шины 36МГц, а бодрейт у нас должен быть 19200 бод.
Целая часть у нас будет 117, а вот дробную надо будет восстановить, умножив на 16 и округлив до ближайшего целого:
Переводим в хекс и получаем 0х75 и 0х3 т.е. USART_BRR = 0x00000753
Надо помозговать и написать макрос под это дело.
USART_CR1 — регистр настроек.
- UE — USART Enable — включить USART блок.
- M — длина байта. 1 = 9 бит. 0 = 8 бит. Изначально 0
- WAKE — какой то бит пробуждения (Из Sleep mode?) 0 = по свободной линии, 1 = по совпадению адреса. Что-то связанное с мультиконтроллерной связью.
- PCE — Parity control enable. Контроль четности, если =1 то четность проверяется.
- PS — Parity selection. Тип контроля четности. 0 = проверяем на четность. 1 = проверка на нечетность.
- PEIE — PE interrupt enable. Включение прерывания по четности (флагу PE регистра состояния уарта).
- TXEIE — TXE interrupt enable. Включение прерывания по опустошению буфера передатчика.
- TCIE — Transmission complete interrupt enable. Включение прерывания по окончании передачи.
- RXNEIE — RXNE interrupt enable. Включение прерывания по приему байта.
- IDLEIE — IDLE interrupt enable. Включение прерывания по окончанию приема (освобождение линии)
- TE — Transmitter enable. Включить передатчик.
- RE — Receiver enable. Включить приемник.
- RWU — Receiver wakeup. Что то с пробуждением по приходу.
- SBK — Send break. Послать символ прерывания. Ставим этот бит и уарт отрыгивает в линию код BREAK и после сам снимает бит.
USART_CR2 — регистр настроек
- LINEN — LIN mode enable. Режим LIN шины.
- STOP[1:0] — два бита определяющие тип стоп бита. 00 = 1 стоп бит, 01 = полубит, 10 = 2 бита, 11 — полтора бита.
- CLKEN — Clock enable. Разрешение CK входа. Это для синхронной передачи.
- CPOL — Clock polarity. Полярность CK линии. Что там будет принято за готовность 0 или 1, соответственно.
- CPHA — Clock phase. Фаза СК синхролинии. По первому дрыгу пойдут данные (0) или по второму (1).
- LBCL — Last bit clock pulse. Что то там с последним дрыгом синхролинии при синхронной передаче.
- LBDIE — LIN break detection interrupt enable. Разрешение прерывания от LIN шины.
- LBDL — lin break detection length. Длина этого сигнала от LIN шины.
- ADD[3:0] — Address of the USART node. Адрес на шине, для мультипроцессорной коммуникации.
USART_CR3 — регистр настроек
- CTSIE — CTS interrupt enable. Разрешение прерывания от CTS
- CTSE — CTS enable. Просто разрешение использования CTS входа.
- RTSE — RTS enable. Разрешение использования RTS выхода.
- DMAT — DMA enable transmitter. Разрешение DMA для передатчика.
- DMAR — DMA enable receiver. Разрешение DMA для приемника.
- SCEN — Smartcard mode enable. Режим работы со смарткартами.
- NACK — Smartcard NACK enable. Разрешение передачи ошибки четности для смарткарт.
- HDSEL — Half-duplex selection. Полудуплексный режим.
- IRLP — IrDA low-power. Выбор режима работы IrDA. 1 = маломощный, 0 — обычный режим.
- IREN — IrDA mode enable. Включение режима ИК передачи данных.
- EIE — Error interrupt enable. Разрешение прерываний от ошибок. Это FE, ORE, NE)
USART_GTPR — Guard time and prescaler register
Содержит несколько параметров задающих делители для режимов смарт карты и IrDA.
Вот всю эту тряхомудию надо нам будет настроить. Хотя по простому нам не нужны все биты. Так что можно не запариваться, а просто их изучить, чтобы знать что у нас там есть.
▌Прерывания USART
Видели сколько там прерываний? На каждый чих. Думаете там как в AVR каждму сверчку свой шесток? Хрена! Вот вам:
Все события стекаются в ОДНО прерывание (как на PIC, ага). Т.е. попав в него надо проверить по какому поводу мы там и сделать выводы. Сбросить флаги нас вызвавшие, проверить ошибки и прочее.
Ладно хоть у каждого USART прерывание свое. Лезем, как обычно в STM32F10x.s и ищем там вектора, точнее их имена:
DCD USART1_IRQHandler ; USART1 DCD USART2_IRQHandler ; USART2 DCD USART3_IRQHandler ; USART3
Что, попробуем что-нибудь настроить. Для начала просто попинаем байтики через USART1.
▌Стенд
Возьмем мою демоплату Pinboard II с модулем ARM и организуем себе терминалку. Т.к. отладчик CoLink занимает канал А, а UART1 сидит на нем же, то пробросим его на канал В. FTDI. Для этого нам потребуются две перемычки. Соединим ими на коммутаторе выводы таким образом:
Ну и само собой не забыть пару джамперов, чтобы соединить модуль по порту UART1 с платой.
▌Программа и шаги по настройке
- 1. Разберемся с частотой. Что у нас и на какой частоте работает. Что надо включить, чтобы такты пошли.
Частота идет с SysClock (72Мгц у меня) на AHB Prescaler. За него отвечают биты HPRE[3:0] регистра RCC_CFGR. После старта там 0000, т.е. без делителя.
Окей, 72 мегагерца пошли дальше. Следующим идет предделитель APB2. Он конфигурируется битами PPRE2[2:0] того же RCC_CFGR. По дефолту там тоже 0. Т.е. частота приходящая в USART у нас 72МГц.
Вообще все тут сильно зависит от фукнции SystemInit(); и тактовой частоты которая указана в system_stm32f10x.c что является частью CMSIS для STM32. У меня там что то вида:
И от этого уже пляшет SystemInit(); у меня она выставляет AHB = SysClock, APB2 = AHB, а APB1 = AHB/2 (т.к. она не может быть больше 36МГц).
Но тут стоит проверить. Как проверить? Прогнать под эмулятором или внутрисхемным отладчиком (Обладатели Pinboard II с отладчиком CoLink радуются и юзают 🙂 ) и посмотреть, что попало в регистры после SystemInit.
В Keil это выглядит так:
RCC->APB2ENR |= RCC_APB2ENR_USART1EN; //USART1 Clock ON
(72 000 000/19200)/16 = 234.375 Получаем старшую часть 0хЕА, а младшую 0х6. Итого BRR = 0xEA6.
USART1->BRR = 0xEA6; // Bodrate for 19200 on 72Mhz
USART1->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; // USART1 ON, TX ON, RX ON
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN; // GPIOA Clock ON. Alter function clock ON GPIOA->CRH &=
GPIO_CRH_CNF9; // Clear CNF bit 9 GPIOA->CRH |= GPIO_CRH_CNF9_1; // Set CNF bit 9 to 10 — AFIO Push-Pull GPIOA->CRH |= GPIO_CRH_MODE9_0; // Set MODE bit 9 to Mode 01 = 10MHz
GPIO_CRH_CNF10; // Clear CNF bit 9 GPIOA->CRH |= GPIO_CRH_CNF10_0; // Set CNF bit 9 to 01 = HiZ GPIOA->CRH &=
GPIO_CRH_MODE10; // Set MODE bit 9 to Mode 01 = 10MHz
Вуаля!
Ну и весь код целиком:
GPIO_CRH_CNF9; // Clear CNF bit 9 GPIOA->CRH |= GPIO_CRH_CNF9_1; // Set CNF bit 9 to 10 — AFIO Push-Pull GPIOA->CRH |= GPIO_CRH_MODE9_0; // Set MODE bit 9 to Mode 01 = 10MHz RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // USART1 Clock ON USART1->BRR = 0xEA6; // Bodrate for 19200 on 72Mhz USART1->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; // USART1 ON, TX ON, RX ON USART1->DR = 10; // Send Byte! // Config CRL GPIOB->CRL &=
GPIO_CRL_CNF5; // Clear CNF bit 5. Mode 00 — Push-Pull GPIOB->CRL |= GPIO_CRL_MODE5_0; // Set bit MODE for pin 5. Mode 01 = Max Speed 10MHz while(1) < >>
Ну и щас, для примера и хохмы ради, попробуем сделать UART-паровозик из Кащенко. Разовьем у нашего контроллера форменную шизофрению и голоса в голове. Он будет разговаривать сам с собой. Приходящие по RX1 мысли будут через TX1 уходить в RX2, из TX2 в RX3, а уже из TX3 пойдут наружу в нашу терминалку. А чтобы голоса в голове не ходили просто так мы будем матаном их грузить. UART 1 будет прибавлять единичку, UART2 десяток, а UART3 сотню. В результате, на входе 1, а на выходе 112. И все это на прерываниях. Как то так…
Сначала сделаем прерывание:
В нем видно, что мы проверяем флаг RXNE, чтобы понять по какому мы, собственно, поводу оказались в прерывании. Делается это одной строчкой и меня искренне удивляют люди которые это пытаются делать то же самой функцией через SPL. ЗОЧЕМ? Также помним, что чтение из DR сбрасывает тот флаг, т.е. нам не нужно о нем заботиться. Но на счет других надо помнить.
Теперь разрешим его, подправив строчку инициализации USART:
USART1->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | // USART1 ON, TX ON, RX ON USART_CR1_RXNEIE; // RXNE Int ON
Разрешим прерывания в NVIC. Через функцию CMSIS. C приоритетом прерываний пока не заморачиваемся. Если вдруг надо, то вам в статью про NVIC:
И осталось разрешить глобальные прерывания. Хотя они ЕМНИП по умолчанию включены, в отличии от той же AVR.
А теперь скопируем это все три раза, подправив биты, чтобы проинициализировать этим три уарта сразу:
GPIO_CRH_CNF9; // Clear CNF bit 9 GPIOA->CRH |= GPIO_CRH_CNF9_1; // Set CNF bit 9 to 10 — AFIO Push-Pull GPIOA->CRH |= GPIO_CRH_MODE9_0; // Set MODE bit 9 to Mode 01 = 10MHz // SET RX1 GPIOA->CRH &=
GPIO_CRH_CNF10; // Clear CNF bit 9 GPIOA->CRH |= GPIO_CRH_CNF10_0; // Set CNF bit 9 to 01 HiZ GPIOA->CRH &=
GPIO_CRH_MODE10; // Set MODE bit 9 to Mode 01 = 10MHz // SET USART1 REG RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // USART1 Clock ON USART1->BRR = 0xEA6; // Baudrate for 19200 on 72Mhz USART1->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | // USART1 ON, TX ON, RX ON USART_CR1_RXNEIE; // RXNE Int ON // USART2 Settings // SET TX2 GPIOA->CRL &=
GPIO_CRL_CNF2; // Clear CNF bit 2 GPIOA->CRL |= GPIO_CRL_CNF2_1; // Set CNF bit 2 to 10 — AFIO Push-Pull GPIOA->CRL |= GPIO_CRL_MODE2_0; // Set MODE bit 2 to Mode 01 = 10MHz // SET RX2 GPIOA->CRL &=
GPIO_CRL_CNF3; // Clear CNF bit 3 GPIOA->CRL |= GPIO_CRL_CNF3_0; // Set CNF bit 3 to 01 HiZ GPIOA->CRL &=
GPIO_CRL_MODE3; // Set MODE bit 3 to Mode 01 = 10MHz // SET USART2 REG RCC->APB1ENR |= RCC_APB1ENR_USART2EN; // USART2 Clock ON USART2->BRR = 0x753; // Baudrate for 19200 on 36Mhz USART2->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | // USART2 ON, TX ON, RX ON USART_CR1_RXNEIE; // USART3 Settings // SET TX3 GPIOB->CRH &=
GPIO_CRH_CNF10; // Clear CNF bit 9 GPIOB->CRH |= GPIO_CRH_CNF10_1; // Set CNF bit 9 to 10 — AFIO Push-Pull GPIOB->CRH |= GPIO_CRH_MODE10_0; // Set MODE bit 9 to Mode 01 = 10MHz // SET RX3 GPIOB->CRH &=
GPIO_CRH_CNF11; // Clear CNF bit 9 GPIOB->CRH |= GPIO_CRH_CNF11_0; // Set CNF bit 9 to 01 HiZ GPIOB->CRH &=
GPIO_CRH_MODE11; // Set MODE bit 9 to Mode 01 = 10MHz // SET USART3 REG RCC->APB1ENR |= RCC_APB1ENR_USART3EN; // USART3 Clock ON USART3->BRR = 0x753; // Baudrate for 19200 on 36Mhz USART3->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | // USART3 ON, TX ON, RX ON USART_CR1_RXNEIE; //UART INT ON NVIC_EnableIRQ (USART1_IRQn); NVIC_EnableIRQ (USART2_IRQn); NVIC_EnableIRQ (USART3_IRQn); __enable_irq (); while(1) < >>
Осталось теперь только USARTы все закольцевать и можно запускать наш шизофреничный паровозик. Соединяем TxB с Rx1, Tx1 с Rx2, Tx2 с Rx3, а Tx3 с RxB.
Запускаем первый байт…
Потом, если не лень будет, я сюда еще каких нибудь примеров работы с USART добавлю. А вам пока вот текущий пример для Keil
Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!
А я встрял на три года, как минимум, ежемесячной пахоты над статьями :)))))))))))) Спасибо вам за такой мощный пинок.
39 thoughts on “ARM Учебный курс. USART”
Опять я первый! Мельком посмотрел, как всегда на высоте. Все охота поиграться с ARM, жаль в протеусе M3 нет. А покупать ради поиграться не охота пока.
Универсальный синхронно-асинхронный приемопередатчик USART
USART (Universal Synchronous Asynchronous Receiver Transmitter) – это модуль последовательного ввода-вывода, который может использоваться для работы с периферийными устройствами, такими как терминалы или персональные компьютеры, модемы, микросхемами ЦАП, АЦП, последовательными EEPROM и т.д.
USART может работать в трех режимах:
- асинхронный, полный дуплекс;
- ведущий синхронный, полудуплекс;
- ведомый синхронный, полудуплекс.
Модуль приемо-передатчика обеспечивает полнодуплексный обмен по последовательному каналу, при этом скорость передачи данных может варьироваться в довольно широких пределах. Длина посылки может составлять от 5 до 9 битов. В модуле присутствует схема контроля и формирования бита четности.
Модуль USART может обнаруживать следующие внештатные ситуации:
- переполнение;
- ошибка кадрирования;
- неверный старт-бит.
Для уменьшения вероятности сбоев в модуле также реализована функция фильтрации помех. Для взаимодействия с программой в микроконтроллере, как правило, предусмотрены прерывания, запрос на генерацию которых формируется при наступлении следующих событий:
- «передача завершена»;
- «регистр данных передатчика пуст»;
- «прием завершен».
Интерфейс USART задействует 3 линии ввода-вывода:
- TxD – передача данных;
- RxD – прием данных;
- XCK – тактовый сигнал (используется только в синхронном режиме).
Соединение двух устройств по интерфейсу USART осуществляется по следующей схеме:
Кадр – совокупность одного слова данных и сопутствующей информации. Кадр начинается со старт-бита, за которым следует младший бит слова данных. Слово данных может состоять из 5, 6, 7, 8 или 9 битов. После старшего бита слова данных следует один или два стоп-бита. Если включена схема формирования бита четности, он включается между старшим битом слова данных и первым стоп-битом.
Схема контроля четности предполагает два возможных режима работы:
- контроль четности (even parity) — исключающее ИЛИ всех битов слова данных:
- контроль нечетности (odd parity) — исключающее ИЛИ всех битов слова данных с логической единицей:
Асинхронный режим работы
В асинхронном режиме, а также в синхронном режиме при работе в качестве ведущего скорость приема и передачи данных задается контроллером скорости передачи, работающим как делитель системного тактового сигнала с программируемым коэффициентом деления.
Скорость передачи данных, как правило, выбирается из стандартного ряда: 300; 600; 1200; 2400; 4800; 9600; 19200; 38400; 57600; 115200; 230400; 460800; 921600 бод.
Реальное значение скорости передачи может отличаться от стандартного ряда, поскольку определяется тактовой частотой микроконтроллера и ограничено разрядностью регистра конфигурации. При этом можно определить величину ошибки:
BaudRate — реальная скорость передачи;
BAUD — требуемая скорость передачи из стандартного ряда.
При использовании скоростей, дающих ошибку больше 0,5 %, снижается помехозащищенность линии передачи.
Для обеспечения приема в асинхронном режиме работы используются схемы восстановления тактового сигнала и данных. Схема восстановления тактового сигнала предназначена для синхронизации внутреннего тактового сигнала, формируемого контроллером скорости передачи, и кадров, поступающих на вывод RxD микроконтроллера. Схема восстановления данных осуществляет считывание и фильтрацию каждого бита принимаемого кадра. Схема восстановления тактового сигнала осуществляет опрос входа приемника с целью определения старт-бита кадра.
Обнаружение спадающего фронта на выводе RxD интерпретируется как возможное появление переднего фронта старт-бита. После этого проверяется значение заданных значений выборок входного сигнала. Если значение хотя бы двух выборок из указанных равно «1», старт-бит считается ложным (помеха), а приемник переходит к ожиданию следующего изменения входного сигнала с «1» в «0». В противном случае считается, что обнаружен старт-бит новой последовательности, с которым синхронизируется внутренний тактовый сигнал приемника. После этого начинает работать схема восстановления данных.
Решение о значении принятого бита принимается также по результатам заданных выборок входного сигнала. Состоянием бита считается логическое значение, которое было получено, хотя бы в двух из трех выборок. Процесс распознавания повторяется для всех битов принимаемого кадра, включая первый стоп-бит.
Старт-бит нового кадра может передаваться сразу же после последней выборки, используемой для определения значения бита.
Синхронный режим работы
При работе в синхронном режиме в качестве ведомого скорость приема и передачи определяется частотой сигнала, поступающего на вход XCK.
При работе модуля USART в синхронном режиме состояние вывода RxD считывается по одному из фронтов сигнала XCK, а выдача сигнала вывод TxD — по другому фронту.
Программирование STM32. Часть 16: USART
Многие из тех, кто имел какое-либо дело с микроконтроллерами, например, с PIC и AVR, знают про такую вещь, как UART. Universal asynchronous receiver transmitter — универсальный асинхронный приемопередатчик встроен как периферийное устройство в любой современный МК, причем в некоторых МК он представлен не в единственном экземпляре. Так же есть некоторая путаница в том, что есть UART, а что есть USART. Universal synchronous asynchronous receiver transmitter (USART) — универсальный синхронный/асинхронный приемопередатчик полностью повторяет функциональность UART, который работает в асинхронном режиме, и включает еще и синхронный режим. В этом случае связь между двумя устройствами USART немного напоминает интерфейс SPI: кроме сигналов RX и TX, добавляется еще один: CK, по которому идет тактовый сигнал от ведущего модуля USART, к ведомому. В данной статье мы рассмотрим самый простой и востребованный случай, а именно обычный асинхронный режим работы USART в микроконтроллере stm32f103c8. Предыдущая статья здесь, все статьи цикла можно посмотреть тут: http://dimoon.ru/category/obuchalka/stm32f1.
Введение
В микроконтроллере stm32f103c8 встроено 3 модуля USART, которые можно достаточно гибко настраивать под свои нужды. Из особенностей можно выделить следующие:
- полный дуплекс;
- возможность работы в полудуплексном режиме по одному проводу;
- дробное задание делителя скорости USART. Это позволяет настроить скорость передачи с нулевой ошибкой на «неудобных» для USART кварцевых резонаторах;
- настраиваемый размер передаваемых данных 8 или 9 бит;
- настраиваемое количество стоп-бит;
- возможность работать с DMA;
- разные примочки для работы с ИК-портом (IrDA), со смарт-картами и т.д.
Описание работы USART
В рамках данной статьи мы коснемся только таких понятий, как формат передаваемых данных (количество бит, контроль четности, стоп-биты) и прерывания USART. Все, что связанно с аппаратным контролем потока, ИК-портом, смарт-картами, синхронным режимом и т.д. мы опустим. Так же пока не будем изучать работу USART совместно с DMA.
Для начала давайте взглянем на блок-схему USART-а:
Рис. 1. Блок-схема USART
Выглядит ужасающе ? Давайте разберемся с основными моментами.
Сдвиговые регистры и регистры данных
Основная часть любого последовательного интерфейса передачи данных — это сдвиговой регистр. В USART-е их 2: один на передачу (Transmit Shift Register), другой на прием (Receive Shift Register). Каждый из этих сдвиговых регистров имеет свой буферный регистр данных: Transmit Data Register (TDR) и Receive Data Register (RDR).
Для того, чтобы отправить слово данных в USART (намеренно говорю «слово», а не «байт», так как размер слова может быть 8 или 9 бит), нужно его загрузить в регистр передачи TDR. После записи в TDR это значение «провалится» в сдвиговой регистр передатчика и процесс передачи будет запущен. Стоит обратить внимание, что как только значение из TDR было отправлено в сдвиговой регистр, в TDR можно загрузить еще данные, которые будут там ждать окончания передачи из сдвигового регистра. Таким образом, у нас есть как бы буфер на 2 слова: одно находится в сдвиговом регистре, другое в TDR, что позволяет передавать данные по USART сплошным потоком без пауз между соседними передачами.
Подобным образом выполняется и прием данных. После получения данных сдвиговым регистром приемника, они попадают в регистр RDR, и приемник тут же готов к приему следующего слова данных. Здесь у нас тоже есть как бы буфер на 2 слова, одно в сдвиговом регистре, другое в RDR. Таким образом, мы имеем возможность производить прием сплошного потока данных без пауз между соседними передачами.
В STM32F103C8 регистры TDR и RDR не доступны напрямую программно. Для этих целей служит регистр DR (Data register). При операции записи в DR записанное значение попадает в регистр TDR, а при чтении из DR будет прочитано значение RDR. То есть, прием и передача данных со стороны прошивки будет выглядеть как обращение к одному и тому же регистру DR.
Флаги и прерывания
В модуле USART микроконтроллеров STM32 есть достаточное количество разнообразных флагов и прерываний, с помощью которых мы можем очень удобно реализовать процесс обмена данными как на прерываниях, так и методом опроса регистров.
Давайте кратко ознакомимся с некоторыми интересными флагами. Рассмотрим процесс передачи данных. Если регистр передатчика TDR пуст, и в него можно записать очередное слово, то в регистре статуса будет установлен в 1 специальный флаг TXE (Transmit data register empty). Стоит отметить, что установка флага TXE в 1 вовсе не означает окончание процесса передачи данных. TXE говорит только о том, что можно записать очередное значение в регистр передатчика.
Для того, чтобы убедится в окончании передачи данных по ножке Tx, есть другой флаг в регистре статуса: TC (Transmission complete). Он устанавливается только в случае, если передача данных завершена и нет очередных данных в регистре передатчика для загрузки в сдвиговой регистр (установлен флаг TXE). Флаг TC может быть полезен при реализации интерфейса RS485, когда направление драйвера интерфейса можно переключить только после завершения передачи данных.
Перейдем к приему данных. В регистре статуса есть флаг RXNE (Read data register not empty). Он устанавливается в 1, если в буфере приемника есть новые данные.
Кроме того, при установке в 1 одного из рассмотренных флагов, есть возможность разрешить генерацию прерывания USART, что очень полезно при передаче данных через прерывания.
Форматы передачи данных
Модуль USART поддерживает настройку следующих параметров передачи данных:
- количество бит данных (8 или 9)
- контроль четности (нет, even, odd)
- количество стоп-битов (0.5, 1, 1.5, 2)
Тут стоит отметить одну особенность при обмене данными с использованием контроля четности. Пусть у нас выбрано 8 бит данных, 1 стоп-бит, то, если мы не используем контроль четности, то формат кадра USART будет таким:
- старт-бит; 8 бит данных; стоп-бит
Но, если использовать контроль четности, что таким:
- старт-бит; 7 бит данных; 1 бит четности; стоп-бит
Иными словами, если мы хотим настроить передачу данных вида «8 бит данных + бит четности», то мы должны длину слова выбрать не 8, а 9 бит. В одном своем проекте сталкивался с таким приколом, вроде как все правильно настроил, а приемная сторона ну ни как не хотела принимать данные. Разобрался при помощи осцилла и вдумчивого изучения мануала.
Скорость передачи
Те, кто работал с микроконтроллерами AVR, знают про специальные частоты резонаторов, удобные для работы с UART-ом. В микроконтроллерах STM32 USART имеет более хитрую реализацию, что позволяет получать нулевое отклонение скорости передачи от стандартных значений при работе от самых обычных кварцев, например, 8 МГц (в таблице ниже указаны частоты шин с использованием PLL):
Рис. 2. Ошибка генерации скорости передачи данных для стандартных значений скоростей
Это достигается путем дробной установки коэффициента деления скорости передачи. Регистр установки коэффициента деления BRR состоит из 2-х частей: DIV_Mantissa и DIV_Fraction. Оба эти значения образуют число с фиксированной запятой: VAL = DIV_Mantissa,DIV_Fraction. Однако, формулы и правила расчета значений DIV_Mantissa и DIV_Fraction, представленные в мануале, очень запутанные, поэтому, упростив эти выкладки получаем следующую формулу для вычисления значения BRR:
BRR = (uint16_t)(BUS_FREQ / BAUD)
BUS_FREQ — частота тактирования модуля USART (частота шины)
BAUD — скорость передачи в бодах.
К слову, в мануале на другие микроконтроллеры STM32, к примеру на STM32F030, формула для вычисления приведена сразу в удобоваримом виде:
Порты ввода-вывода
Давайте выясним, к каким выводам GPIO подключены USART-ы в микроконтроллере STM32F103C8. Открываем Datasheet, находим Таблицу 5: Medium-density STM32F103xx pin definitions. В ней представлено следующее:
- TX: PA9, Remap PB6
- RX: PA10, Remap PB7
- TX: PA2
- RX: PA3
- TX: PB10
- RX: PB11
Для USART1 доступен remap выводов TX и RX на другие порты ввода-вывода, если выводы по-умолчанию заняты.
Теперь обратимся к разделу 9.1.11 GPIO configurations for device peripherals в Reference manual, для того, чтобы понять, как нужно настраивать порты ввода-вывода для работы с USART:
Для самого простого режима полного дуплекса без аппаратного управления потоком нам понадобятся только выводы TX и RX. Остальные выводы можно использовать как обычные порты GPIO.
Итак, настройка будет следующей:
- TX: режим альтернативной функции, тип выхода push-pull или открытый коллектор
- RX: вход без подтяжки или с подтяжкой вверх
Как работать с GPIO можно почитать тут.
Регистры USART
Status register (USART_SR) — регистр статуса
TXE: регистр передатчика пуст. Этот бит устанавливается аппаратно, когда содержимое регистра передатчика TDR (TDR не доступен напрямую из программы, но туда попадают данные при записи в USART_DR) было передано в сдвиговой регистр. Если в USART_CR1 был установлен бит разрешения прерывания TXEIE, то в этот момент генерируется запрос прерывания USART. TXE сбрасывается при записи значения в регистр данных USART_DR.
TC: передача завершена. Этот бит устанавливается аппаратно, если UART завершил передачу данных, при этом бит TXE установлен в единицу. Этот бит может быть полезен для реализации интерфейса RS485 для переключения направления драйвера RS485. Если в регистре USART_CR1 установлен бит TCIE, то генерируется прерывание USART при установке бита TC. Бит TC сбрасывается следующей программной последовательностью: чтение регистра USART_SR с последующей записью в регистр USART_DR. Кроме того, бит TC можно сбросить записью в него значения 0, но это рекомендуется производить только в режиме совместной работы с DMA.
RXNE: регистр приемника не пуст. Этот бит устанавливается в единицу, когда содержимое сдвигового регистра приемника передается в регистр данных USART. Если в регистре USART_CR1 установлен бит RXNEIE, то генерируется запрос прерывания USART. Бит RXNE сбрасывается при чтении регистр данных USART_DR. Кроме того, RXNE можно сбросить записью в него значение 0, но это рекомендуется производить только в режиме совместной работы с DMA.
ORE: ошибка переполнения. Устанавливается в 1, если данные в сдвиговом регистре приемника готовы к передаче в регистр данных, но при этом установлен бит RXNE. Иными словами, мы уже получили очередной байт по USART, но еще не прочитали предыдущий. Если в регистре USART_CR1 установлен флаг RXNEIE, то генерируется запрос прерывания USART. Бит ORE сбрасывается следующей программной последовательностью: чтение регистра USART_SR с последующим чтением регистра USART_DR.
Data register (USART_DR) — регистр данных
DR[8:0]: данные. Этот регистр содержит 2 теневых регистра: TDR и RDR. При чтении из DR будет прочитано значение регистра данных приемника RDR, при записи в DR значение будет записано в регистр данных передатчика TDR. Если используется контроль четности (бит PCE в регистре USART_CR1 установлен в 1), то при записи в DR значение старшего бита будет игнорироваться, так как при передаче он будет заменен битом четности. При приеме с включенным контролем четности старший бит будет содержать бит четности.
Baud rate register (USART_BRR) — регистр скорости передачи данных USART
Регистр BRR содержит коэффициент деления, который задает скорость передачи данных по USART.
BRR = (uint16_t)(BUS_FREQ / BAUD)
где BUS_FREQ — частота шины, на которой висит данный USART
BAUD — желаемая скорость передачи данных.
Control register 1 (USART_CR1) — регистр конфигурации 1
UE: включить USART.
- 0: предделители USART и его выходы отключены
- 1: USART включен
M: длина слова данных. Этот бит определяет длину передаваемых данных. Устанавливается и очищается программно.
- 0: 1 старт-бит, 8 бит данных, n стоп-бит
- 1: 1 старт-бит, 9 бит данных, n стоп-бит
PCE: разрешить контроль четности. Устанавливается и очищается программно
PS: выбор типа контроля четности. Этот бит выбирает вариант контроля четности, если установлен бит PCE. Устанавливается и очищается программно.
- 0: Even
- 1: Odd
TXEIE: разрешить прерывание при опустошении буфера передатчика. Если установлен в 1, то генерируется запрос прерывания USART при установке бита TXE регистра USART_SR.
TCIE: разрешить прерывания окончания передачи. Если 1, то генерируется запрос прерывания USART при установке флага TC в регистре USART_SR.
RXNEIE: разрешить прерывание при появлении данных в регистре приемника. Если 1, то генерируется запрос прерывания USART при установке флага RXNE или ORE в регистре USART_SR.
TE: включить передатчик USART
RE: включить приемник USART
Control register 2 (USART_CR2) — регистр конфигурации 2
STOP: количество STOP-битов
- 00: 1 стоп-бит
- 01: 0.5 стоп-бита
- 10: 2 стоп-бита
- 11: 1.5 стоп-бита
0.5 и 1.5 стоп-бита не доступны для UART4 и UART5 (UART4 и UART5 отсутствуют в микроконтроллере STM32F103C8)
Заключение
Чтобы не забивать голову читателей ненужной информацией, я не стал давать описание каждому флагу и каждому регистру USART, так как для большинства задач это не нужно. Возможно, в дальнейшем добавлю описания битов, ответственных за совместную работу с DMA.
На этом пока все! В следующей части мы перейдем к практике и напишем небольшую библиотеку для работы с интерфейсом USART. Всем пока!