Программирование 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. Предыдущая статья здесь, все статьи цикла можно посмотреть тут: https://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. Всем пока! 🙂

Метки: , . Закладка Постоянная ссылка.

8 комментариев: Программирование STM32. Часть 16: USART

  1. Den пишет:

    Отличный цикл. С нетерпением жду USART+DMA и ADC ))
    Больше всего нравится то, что не используется SPL & HAL, а все на регистрах. А то везде то SPL на мертвом кокосе, то HAL, который сделан через коленку и раздувает прошивку

  2. Dmitriy пишет:

    Спасибо что нет hal. Ждем практики , радуете , как раз понадобился usart зашел к вам , а у вас новая статья

  3. Василий пишет:

    Спасибо огромное.
    +100500 за то, что CMSIS без библиотек, плюс разжевывание со ссылками на документацию. Просто и понятно. Жду про таймеры.

  4. Vladimir пишет:

    Отличные статьи!
    А про I2C будет?

    • DiMoon пишет:

      Спасибо! Старался 🙂 В планах очень много всего, в том числе по периферии и по приемам программирования МК, организации многозадачности. Так же хотелось написать несколько статей о взаимодействии прошивки МК с управляющей программой на ПК через RS232, там много чего есть рассказать интересного. В данный момент довольно сильно загружен основной работой, надеюсь, в скором времени ситуация улучшится))

  5. Kostja пишет:

    Для того, чтобы отправить слово данных в USART (намеренно говорю «слово», а не «байт», так как размер слова может быть 8 или 9 байт),

    //************************************************
    настраиваемый размер передаваемых данных 8 или 9 бит;

  6. Игорь пишет:

    Про CAN — шину расскажете ?

  7. Юрий пишет:

    Спасибо, у вас очень полезные статьи.

Добавить комментарий для Dmitriy Отменить ответ