STM32 BSRR VS ODR.
Те кто читает эту статью, думаю знают, что записать единицу в нулевой бит порта А можно двумя способами
или
И везде пишут, что второй способ правильнее так, как установка бита в таком случае выполянется атомарно. Тут не поспоришь.
А теперь давайте представим ситуацию, у нас есть восьмибитная шина, по которой передаются данные, подключение к шине выглядит следующим образом.
То есть получается, перед установкой очередного бита средствами BSRR, необходимо проверить его значение и в зависимости от того, что хотим получить, производить манипуляции. Но проверять каждый бит долго, поэтому предлагаю посмотреть на эту ситуацию под другим углом.
Линии относящиеся к порту Е : Е7, Е8, Е9, Е10 пронумерованы последовательно, а линии относящиеся к порту D образуют две последвательные пары PD0, PD1 и PD14, PD15.
Как писалось выше, с помощью BSRR устанавливать биты не вариант — очень долго. Это можно сделать быстрее, переписывая фрагменты регистра ODR, но теряя при этом атомарность.
И так первым делом из нашей переменной извлечём данные, которые будут передаваться по порту Е(D4 - D7).
В результате этой операции мы получили данные, которые надо передать, осталось их установить в нужную позицию. Сейчас данные располагаются с 4 по 7 бит, а должны с 7 по 10, поэтому сдвинем их на три позиции влево.
В итоге получим следующее выражение
С помощью тех же рассуждений записываем нужное значение в порт D.
и
Но это еще не всё, каждый раз перед установкой биты нужно очищать.
В итоге код отправки данных по шине будет выглядеть так.
В этой ситуации использование регистра ODR оказалось оправданным, а вопрос атомарности решается, с помощью регистра PRIMASK, который будучи установлен в единицу запрещает все прерывания с конфигурируемым приоритетом.
GPIOA->ODR |= GPIO_ODR_ODR0;
или
GPIOA->BSRR = GPIO_BSRR_BS0;
И везде пишут, что второй способ правильнее так, как установка бита в таком случае выполянется атомарно. Тут не поспоришь.
А теперь давайте представим ситуацию, у нас есть восьмибитная шина, по которой передаются данные, подключение к шине выглядит следующим образом.
//D0 - PD14
//D1 - PD15
//D2 - PD0
//D3 - PD1
//D4 - PE7
//D5 - PE8
//D6 - PE9
//D7 - PE10
То есть получается, перед установкой очередного бита средствами BSRR, необходимо проверить его значение и в зависимости от того, что хотим получить, производить манипуляции. Но проверять каждый бит долго, поэтому предлагаю посмотреть на эту ситуацию под другим углом.
Линии относящиеся к порту Е : Е7, Е8, Е9, Е10 пронумерованы последовательно, а линии относящиеся к порту D образуют две последвательные пары PD0, PD1 и PD14, PD15.
Как писалось выше, с помощью BSRR устанавливать биты не вариант — очень долго. Это можно сделать быстрее, переписывая фрагменты регистра ODR, но теряя при этом атомарность.
И так первым делом из нашей переменной извлечём данные, которые будут передаваться по порту Е(D4 - D7).
cmd & 0xF0
В результате этой операции мы получили данные, которые надо передать, осталось их установить в нужную позицию. Сейчас данные располагаются с 4 по 7 бит, а должны с 7 по 10, поэтому сдвинем их на три позиции влево.
(cmd & 0x00F0)<<3;
В итоге получим следующее выражение
GPIOE->ODR |= (cmd & 0xF0)<<3;
С помощью тех же рассуждений записываем нужное значение в порт D.
GPIOD->ODR |= (cmd & 0x03)<<14;
и
GPIOD->ODR |= (cmd & 0x0C)>>2;
Но это еще не всё, каждый раз перед установкой биты нужно очищать.
В итоге код отправки данных по шине будет выглядеть так.
#define __enter_critical() {uint32_t flag; flag = __get_PRIMASK();
#define __exit_critical() __set_PRIMASK(flag);}
#define _Atomic(X) __enter_critical(); {X}; __exit_critical();
static void TFT_Send_Cmd(uint8_t cmd)
{
_Atomic
(
RS_LOW
RD_HIGH
CS_LOW
GPIOE->ODR &= ~(0xF0<<3);
GPIOE->ODR |= (cmd & 0xF0)<<3;
GPIOD->ODR &= ~(0x03<<14);
GPIOD->ODR |= (cmd & 0x03)<<14;
GPIOD->ODR &= ~(0x0C>>2);
GPIOD->ODR |= (cmd & 0x0C)>>2;
WR_LOW
delay_us(5);
WR_HIGH
CS_HIGH
)
}
В этой ситуации использование регистра ODR оказалось оправданным, а вопрос атомарности решается, с помощью регистра PRIMASK, который будучи установлен в единицу запрещает все прерывания с конфигурируемым приоритетом.
Похожие статьи