Многие из тех, кто имел какое-либо дело с микроконтроллерами, например, с 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. В ней представлено следующее:
Для USART1:
- TX: PA9, Remap PB6
- RX: PA10, Remap PB7
Для USART2:
- TX: PA2
- RX: PA3
Для USART3:
- 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. Всем пока! 🙂
Отличный цикл. С нетерпением жду USART+DMA и ADC ))
Больше всего нравится то, что не используется SPL & HAL, а все на регистрах. А то везде то SPL на мертвом кокосе, то HAL, который сделан через коленку и раздувает прошивку
Спасибо что нет hal. Ждем практики , радуете , как раз понадобился usart зашел к вам , а у вас новая статья
Спасибо огромное.
+100500 за то, что CMSIS без библиотек, плюс разжевывание со ссылками на документацию. Просто и понятно. Жду про таймеры.
Отличные статьи!
А про I2C будет?
Спасибо! Старался 🙂 В планах очень много всего, в том числе по периферии и по приемам программирования МК, организации многозадачности. Так же хотелось написать несколько статей о взаимодействии прошивки МК с управляющей программой на ПК через RS232, там много чего есть рассказать интересного. В данный момент довольно сильно загружен основной работой, надеюсь, в скором времени ситуация улучшится))
Для того, чтобы отправить слово данных в USART (намеренно говорю «слово», а не «байт», так как размер слова может быть 8 или 9 байт),
//************************************************
настраиваемый размер передаваемых данных 8 или 9 бит;
Про CAN — шину расскажете ?
Спасибо, у вас очень полезные статьи.