STM32 BSRR

 

BSRR (Bit Set/Reset Register) — это регистр установки и сброса битов для управления выводами GPIO в микроконтроллерах STM32. Он позволяет изменять состояние определённых пинов без влияния на другие, что делает его более эффективным и удобным по сравнению с обычной записью в регистр ODR (Output Data Register).

Преимущества BSRR:

  • Позволяет установить или сбросить биты атомарно (без необходимости чтения, изменения и записи).

  • Исключает возможность возникновения "глюков" из-за прерываний при изменении состояния пинов.

  • Позволяет изменять несколько пинов одновременно, записывая одно 32-битное значение.

 

Как устроен BSRR?

BSRR — это 32-битный регистр, который разделен на две части:

  • Младшие 16 бит (0–15): устанавливают пины (1 → HIGH).

  • Старшие 16 бит (16–31): сбрасывают пины (1 → LOW).

Когда мы записываем 1 в младшие 16 бит, соответствующий GPIO-пин устанавливается в HIGH.
Когда мы записываем 1 в старшие 16 бит, соответствующий GPIO-пин сбрасывается в LOW.

Регистр BSRR состоит из двух 16-битных полей:

  1. LOW (LSB) — первые 16 бит (0-15): Установка пинов (логическая "1" устанавливает пин в HIGH).

  2. HIGH (MSB) — вторые 16 бит (16-31): Сброс пинов (логическая "1" сбрасывает пин в LOW).

Формат регистра:

БитЗначение
0-15 Устанавливает соответствующие биты GPIO (1 = HIGH)
16-31 Сбрасывает соответствующие биты GPIO (1 = LOW)

Важно: Если записать 1 в оба поля (в один и тот же бит установки и сброса), то установка имеет приоритет.


Пример использования

Допустим, у нас есть порт GPIOA, и мы хотим:

  1. Установить PA5 в HIGH.

  2. Сбросить PA6 в LOW.

Используем BSRR так:

GPIOA->BSRR = (1 << 5);   // Установить PA5 в HIGH
GPIOA->BSRR = (1 << 22);  // Сбросить PA6 в LOW (6 + 16 = 22)

 

Аналогичный вариант, если нужно изменить несколько пинов одновременно:

GPIOA->BSRR = (1 << 5) | (1 << 7);      // Устанавливаем PA5 и PA7
GPIOA->BSRR = (1 << (6 + 16)) | (1 << (8 + 16));  // Сбрасываем PA6 и PA8

Сравнение с обычной записью в ODR

Если бы мы использовали ODR, то это выглядело бы так:

GPIOA->ODR |= (1 << 5);  // Установить PA5 в HIGH
GPIOA->ODR &= ~(1 << 6); // Сбросить PA6 в LOW

Однако здесь есть проблема: если в этот момент произойдет прерывание и изменит другие биты ODR, то при GPIOA->ODR &= ~(1 << 6); мы могли бы случайно стереть изменения.

BSRR решает эту проблему: он атомарен, и ни одно прерывание не может изменить другие биты.