MyTetra Share
Делитесь знаниями!
Что быстрее: работа с регистрами CRL/CRH напрямую или через переменную?
Время создания: 09.05.2022 23:30
Текстовые метки: stm32, bluepill, регистры, CRL, CRH, режим, переключение, чтение, запись, ножка, пин
Раздел: Компьютер - Аппаратное обеспечение - Микроконтроллеры ARM
Запись: xintrea/mytetra_syncro/master/base/1652128251j46n4j3eus/text.html на raw.github.com

Иногда надо сделать на STM32 такое устройство, в котором режим ножек будет постоянно переключаться. Обычно режим ножки выставляется один раз в начале программы, и дальше ножка используется только в этом режиме. В STM32 даже не предусмотрено механизма быстрой установки режимов, как это сделано для значений портов через регистры BSRR/BRR.


Зачем же может понадобиться постоянное переключение режима работы ножки?


Например, если ножка подключается к какому-то цифровому устройству, и через нее должны выводиться сигналы только при наступлении определенного события (например, когда устройство обращается на чтение к STM-ке с помощью отправки сигнала по другой ножке). А все остальное время ножка должна находиться в неком режиме, чтобы не мешать работе подключенного устройства. Этот некий режим - режим Input, в котором STM-ка никак не может повлиять на значение сигнала на ножке, а может только его считывать (если это необходимо)


Получается, что для вывода сигнала ножка должна переключиться в режим Output, а когда ножка не должна ничего передавать, она должна переключиться в режим Input.


Установка режима ножки обычно происходит следующими этапами:



  1. В битах CRL/CRH, отвечающих за MODE и CNF, выставляются нули. Делается это через маски чтобы не затронуть биты других ножек
  2. В биты режимов MODE и CNF вносится новый режим путем применения ИЛИ между значением регистров CRL/CRH (в которых в местах настройки режимов уже установлены нули) и значением, где все биты равны 1, кроме тех мест, где расположены настройки режимов - там выставлены коды режимов.



Описанные действия можно сделать следующим кодом (на примере пина B15):



// Режим MODE и CNF, которые надо установить

const uint32_t mode=0b11; // Режим выхода с максимальной частотой 50 МГц

const uint32_t cnf=0b00; // Двухтактный выход (Output push-pull)


// Обнуление битов режима

GPIOB->CRH &= ~(GPIO_CRH_MODE15_Msk | GPIO_CRH_CNF15_Msk);


// Установка режима

GPIOB->CRH |= (mode << GPIO_CRH_MODE15_Pos) | (cnf << GPIO_CRH_CNF15_Pos);



Здесь видно, что происходит считывание регистра GPIOB->CRH, выставление нулей в нужных местах, потом его запись, затем снова считывание, выставление битов режимов и запись.


И возникает вопрос: а максимально ли быстро происходит этот процесс? Можно ли его хоть немного, но ускорить? Что если один раз считать значение регистра, подготовить нужное, и один раз записать в регистр? Будет ли такое решение работать быстрее? Измерения на оциллографе показывают, что да.


Следующий код работает примерно на 5% быстрее, чем предыдущий:



// Режим MODE и CNF, которые надо установить

const uint32_t mode=0b11; // Режим выхода с максимальной частотой 50 МГц

const uint32_t cnf=0b00; // Двухтактный выход (Output push-pull)


// Переменная для хранения настроек регистра

// В нее считывается значение регистра управления CRH.

uint32_t statusB=GPIOB->CRH;


// Обнуление битов режима во временной переменной

statusB &= ~(GPIO_CRH_MODE15_Msk | GPIO_CRH_CNF15_Msk);


// Установка режима

GPIOB->CRH = statusB | (mode << GPIO_CRH_MODE15_Pos) | (cnf << GPIO_CRH_CNF15_Pos);



Получается, что работа с памятью ОЗУ происходит несколько быстрее, чем работа с регистрами состояния портов.



Так же в этом разделе:
 
MyTetra Share v.0.65
Яндекс индекс цитирования