STM Урок 200. CMSIS. Bit banding

 

 

 

Архитектура ядер семейства Cortex-M, на котором также основываются многие микроконтроллеры STM32, аппаратно поддерживает интересную технологию. Называется данная технология bit banding.

Это такая возможность модели памяти, при которой биты определённых участков данной памяти отображаются на целые слова другого участка памяти. То есть если в первом участке какой-нибудь бит установлен, то в области, куда он отображается, также будет установлен нулевой бит в отображаемом слове. А если бит сброшен, то и слово в области отображении тоже будет в нуле. Ну и также наоборот, если слово в области отображения равно 1, то и бит установлен, а если равно 0, то бит сброшен.

Вот так выглядит данная схема в описании модели памяти в документации STM32F10xxx-20xxx-21xxx-L1xxxx-Programming-Manual (и не только, в документации на ядро также это есть)

 

 

Схема не совсем удобная для восприятия, но тем не менее здесь можно разглядеть, какая область памяти поддерживает bit-banding, и также в какую область памяти данная область отображается.

Bit-banding работает для области памяти SRAM, начиная с адреса 0x20000000 размером в 1 мегабайт и данная область отображается в область памяти с адреса 0x22000000 размером, соответственно в 32 мегабайта (оно и понятно, раз для каждого бита нужно слово, это же в 32 раза больше). Также bit-banding поддерживается для области памяти периферии, начиная с адреса 0x40000000 размером в 1 мегабайт и данная область уже отображается в область памяти с адреса 0x42000000 размером в 32 мегабайта.

Всё это очень интересно, но для чего это может потребоваться?

А может потребоваться для того, чтобы снизить время операций установки и сброса определённых битов памяти. В принципе, для ножек портов периферии GPIO есть для этого специальные биты BS и BR в регистре BSRR, но тем не менее есть регистры другой периферии, в которых нужно бывает срочно установить или сбросить какой-нибудь бит, также может возникнуть такая надобность и в области памяти SRAM.

Каким образом экономится время операции установки или сброса бита с помощью bit-banding?

Если мы решили установить бит в каком-нибудь участке памяти, то для того, чтобы не изменить состояние других битов, мы должны считать весь регистр (всё слово) в регистр общего назначения (РОН), ну или хотя бы байт, затем мы должны применить логическую операцию OR если нам нужно установить бит либо логическую операцию AND, чтобы бит сбросить, а на третьем этапе мы должны это слово или байт записать обратно в его родную ячейку. А если мы воспользуемся технологией bit-banding, то нам достаточно будет записать единицу или ноль в отображаемое место нашего бита, для того, чтобы его установить или сбросить. На этапе инициализации периферии это не так важно, потому что это происходит либо однократно либо очень редко, а вот в каком-то периодическом процессе это может очень помочь в оптимизации данного процесса.

Поэтому, я думаю, данную технологию не стоит оставлять в стороне, и мы просто обязаны с ней познакомиться.

Как рассчитать адрес той ячейки памяти, в которую отображается тот или иной бит?

Для этого есть определённая формула

 

То есть нам нужны для расчёта следующие величины:

 

byte_offset – адрес регистра или ячейки памяти, с битами которой мы собираемся работать,

byte_number – номер бита в данном регистре или ячейки памяти,

bit_band_base – базовый адрес области памяти – 0x22000000, если это SRAM, 0x42000000, если это Peripheral.

Данные две формулы для простоты расчёта можно объединить в одну:

 

bit_word_addr = bit_band_base + byte_offset x 32 + bit_number x 4

 

Вот, в принципе, и вся теория битбэндинга.

Теперь можно приступить и к практике.

Попробуем помигать светодиодами с применением битбэндига.

Проект за основу мы возьмём из урока 165 с именем BLINK01_CMSIS и назовём его CMSIS_BLINK_BITBAND.

Схема будет та же как и в 165 уроке

 

 

Откроем наш проект в Keil, затем откроем файл main.c, соберём его и в бесконечном цикле функции main() распределим команды каждую в свою строку, до этого они были объединены по 3 команды в строке. Это потребуется для того, чтобы лучше было смотреть ассемблерный код в отладчике

 

 

Соберём код, прошьём контроллер и установим точку останова, например вот здесь

 

 

Запустим отладку, остановившись на данном брейкпоинте, и посмотрим участок кода, отвечающий за включение второго светодиода

 

 

Как я и отметил выше, процесс установки бита разворачивается на 3 этапа: загрузка из памяти в РОН, установка бита при помощи операции OR и загрузка данных с установленным битом обратно в память.

Операция по установке в низкий уровень ещё загадочнее

 

 

Хотя здесь применяется инструкция сброса битов по маске, процесс тем не менее затянулся вон на сколько инструкций. Это, видимо, какие-то издержки языка C.

Теперь посмотрим как это всё будет выглядеть после того, когда мы применим бит-бэндинг.

Закомментируем макросы зажигания п гашения светодиодов

 

 

Аналогичные макросы мы теперь должны написать с применением технологии bit-banding.

 

 

Для этого нам надо сначала узнать все необходимые адреса и смещения.

Первый адрес – это базовый адрес памяти, куда отображаются адреса периферии. Он хранится в специальном макросе библиотеки

 

#define PERIPH_BB_BASE ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */

 

Также нам нужен реальный адрес регистра. Для перового светодиода это регистр ODR порта A. В данной таблице в документации Reference Manual на наш контроллер есть информация об адресах различной периферии, найдём в ней наш порт

 

 

А адрес регистра мы можем вычислить. Вот здесь его смещение относительно базового адреса порта

 

 

Значит нужный нам адрес – 0x40010800 + 0x0C = 0x4004080C.

Номер бита для первого светодиода – 2

 

 

Также адрес порта можно вычислить, используя следующие макросы библиотеки

 

#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)

#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)

#define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */

 

Величина смещения порта относительно базового адреса периферии будет равна GPIOA_BASE-PERIPH_BASE, а адрес регистра – GPIOA_BASE-PERIPH_BASE+0xC.

Вот теперь у нас есть всё для нашего первого макроса, который будет выглядеть вот таким образом

 

 

Соответственно, для того, чтобы нам светодиод отключить, мы всего лишь 1 меняем на 0, следовательно, у нас готов и второй макрос

 

 

Также используя те же принципы вычислений, добавим макросы и для других светодиодов

 

 

Всё готово! Можно проверять работу нашего кода.

Соберём код, прошьём контроллер, у нас по-прежнему всё работает

 

 

Посмотрим, что изменилось в машинном коде

 

 

Запись единицы в бит регистра теперь происходит за одну инструкцию, если не считать запись в r0 единицы и загрузки в r1 адреса регистра.

Аналогично происходит и операция записи нуля в тот же бит

 

 

Первые две операции не считаются, так как в них происходит всего лишь вычисление адреса регистра.

Сама операция записи нуля или единицы в бит у нас теперь длится только одну операцию, вот этого и позволяет нам достичь технология отображения битов в слова.

Итак, на данном уроке мы познакомились с технологией bit banding, аппаратно реализованной в ядрах Cortex-M3 и Cortex-M4, и, надеюсь, знание, как использовать данную технологию, нам не раз пригодится в будущем.

Всем спасибо за внимание!

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код

 

 

Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6

Программатор недорогой можно купить здесь ST-Link V2

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM CMSIS. Bit banding

Один комментарий на “STM Урок 200. CMSIS. Bit banding

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*