STM32 или дрыгаем ногами через Bit Banding.

bit banding

Довольно часть ковыряясь в чужом коде, я не могу понять, зачем в STM32 люди пользуются библиотекой HAL. ну это просто ужас! Это медленно, это жрет память и запись при этом очень длинная, нет даже так – оооооооочень длинная. Одни программисты используют uint_32 вместо unsigned int а другие придумывают вместо PORTC[13]=0; конструкцию вида HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_RESET); Понимаю, если бы в этом был какой то выигрыш, так нет. Даже конструкция вида GPIOС->BSRR = GPIO_BSRR_BS13; работает в 3 раза медленнее PORTC[13]=0; через битбандинг.

Что же это за зверь и как он может так шустро работать? Bit Banding – операция, функция или термин, называйте как хотите, который использует ARM для обозначения доступа к отдельным битам памяти. Именно битам. Разрядность у STM32 большая, адресов много а памяти столько в контроллере нет. Так зачем пропадать добру? Вот и придумали инженеры назначать каждому имеющемуся биту памяти свой адрес. И это относится не только к оперативной памяти, а вообще к любой. А что у нас является регистрами портов?

В даташите можно найти формулы для расчета адреса бита, выглядят они таким образом:

BB_ADDR_PER = PERIPH_BB_BASE + ((REG_ADDR - PERIPH_BASE) * 32) + (BIT * 4)
BB_ADDR_SRAM = SRAM_BB_BASE + ((SRAM_ADDR - SRAM_BASE) *32) + (BIT * 4)

Адрес бита вычисляется от адреса базы+смещение. Адреса базы всей периферии есть в том же даташите, например доя STM32F10х адрес базы портов равен 0x42000000. А дальше добавив к адресу смещение, можем обращаться к каждому отдельному биту.

Какие преимущества нам это дает? Во первых короткую запись, во вторых быстроту работы – операция установки бита занимает 2 такта процессора, если же писать в регистр напрямую, то что бы установить 1 бит, процессору необходимо считать состояние порта в оперативную память, далее по маске заменить нужный бит и только после этого записать значение обратно в регистр порта. а это как минимум 6 тактов. При этом в эти 6 тактов может вылезть прерывание, записать что то в порт, а программа об этом не знает – она уже считала старое значение порта, и это может привести к интересным и сложно вылавливаемым глюкам. При записи через Bit Banding такой проблемы нет. К биту обратиться очень просто – достаточно по заданному адресу записать любое число отличное от нуля, и бит будет установлен, если записать ноль, то бит будет сброшен.

Как пользоваться?

Для контроллера STM32f103 я посчитал адреса и просто создал заголовочный файл где адреса объявил через #define. При этом если у вас другая серия микроконтроллера, то достаточно изменить только адрес базы и библиотека будет работать с ним.

Вначале я вычислял адреса каждого бита и делал запись в виде define PA0 *((uint32_t *)0Х42210180) define PA1 *((uint32_t *)0Х42210184) define PA2 *((uint32_t *)0Х42210188) а потом обращался к пинам так PА0=1;, PА0=0; -установка и сброс ножки PА0. Но потом нашел более аккуратный способ. Что такое в языке Си массивы? это указатели на область памяти. и перебирая элементы массива мы будем перебирать адреса памяти. А что если назначить размер элемента массива равный по длине смещению? То, что и нужно!

Итого вся библиотека укоротилась до:

#define uint32_t int	
#define PORTА ((uint32_t *)((0x42000000  + ((0x40010800+0x0C)-0x40000000)*32)))
#define PORTB ((uint32_t *)((0x42000000  + ((0x40010C00+0x0C)-0x40000000)*32)))
#define PORTC ((uint32_t *)((0x42000000  + ((0x40011000+0x0C)-0x40000000)*32)))
#define PORTD ((uint32_t *)((0x42000000  + ((0x40011400+0x0C)-0x40000000)*32)))
#define PORTE ((uint32_t *)((0x42000000  + ((0x40011800+0x0C)-0x40000000)*32)))
#define PORTF ((uint32_t *)((0x42000000  + ((0x40011C00+0x0C)-0x40000000)*32)))
#define PORTG ((uint32_t *)((0x42000000  + ((0x40012000+0x0C)-0x40000000)*32)))

Обращаться к портам теперь стало очень просто, например для ножки 13 порта C (на нем висит светодиод на голубой таблетке) запись выглядит так: PORTC[13]=1; -установить 1 (погасить светодиод, он там на шине питания висит и включается инверсно) PORTC[13]=0;-сбросить (зажечь светодиод).

Аналогично можно обращаться и к оперативной памяти, но применения этому для себя я не нашел.

Автор: Ryazanec13

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

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