Технология bit-band в Cortex-M3 — это выделение некоторой области памяти, которая служит для побитового доступа к регистрам. Эта технология позволяет напрямую управлять состоянием портов ввода-вывода, что облегчает имплементацию последовательных интерфейсов.
В плате STM32 Value line discovery(процессор SM32F100RBT6B)имеется два светодиода: зелёного и синего цветов.
На PC9 – зелёный и на PC8 - синий.
Обычным путём установка бита на PC9 происходит следующим образом:
GPIOC->ODR|=GPIO_ODR_ODR9; //set
Снятие:
GPIOC->ODR&=~GPIO_ODR_ODR9; //reset
Или
GPIOC->BSRR=GPIO_BSRR_BS9; // set
GPIOC->BSRR=GPIO_BSRR_BR9; // reset
Аналогично для PC8.
Приступим. Пишу относительно IAR, статья же актуальна для любого компилятора. Будем управлять регистром ODR PC9 и PC8.
В файле stm32f10x.h находим:
Базовый адрес периферии:
#define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
Начало памяти соответствующего ему блока памяти для bit-band'a:
#define PERIPH_BB_BASE ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */
Далее, смотрим адрес интересующего нас порта:
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
При этом:
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
Т.е. 0X40000000 + 0x10000 + 0x1000 = 0x40011000;
GPIOC_BASE эквивалентно ((uint32_t)0x40011000)
Далее, регистровая структура порта:
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;
Таким образом, адреса слов будут (4 байта 410 = 0x416):
0x40011000 + 0 = 0x40011000; //GPIOC-> CRL
0x40011000 + 0x4 = 0x40011004; //GPIOC-> CRH
0x40011000 + 0x8 = 0x40011008; //GPIOC-> IDR
0x40011000 + 0xС = 0x4001100С; //GPIOC-> ODR
0x40011000 + 0x10 = 0x40011010; //GPIOC-> BSRR
0x40011000 + 0x14= 0x40011014; //GPIOC-> BRR
0x40011000 + 0x18 = 0x40011018; //GPIOC-> LCKR
Смещение слова GPIOC-> ODR от базового слова периферии равно:
0x4001100С- 0x40000000 = 0x1100С
К тому же, эти все манипуляции можно было обойти с помощью Си:
unsigned long AddressReg;
далее:
AddressReg = (unsigned long)&(GPIOC->ODR);
Прочитав в watch переменную получим то же:
Рисунок 1 Watch window
Номера битов 8 и 9 соответственно.
Приступим к вычислениям.
Согласно
Адрес в области псевдоимен = Начальный адрес области псавдоимен + смещение слова
Смещение слова = Смещение в байтах от начала битовых сегментов * 0x20 + номер в битаx * 4
Таким образом:
Нужный адрес для PC8:
0x42000000 + 0x1100С * 0x20 + 8* 0x4 = 0x42000000 + 0x220180 + 0x20 = 0x422201A0
Напишем определение:
#define PC8B (*((volatile unsigned long *) 0x422201A0 ))
P/S не называйте PC8 – слово зарезервировано, работать не будет!
Для PC9:
0x42000000 + 0x220180+ 9* 0x4 = 0x422201A4
#define PC9B (*((volatile unsigned long *) 0x422201A4 ))
Теперь устанавливать лог. уровни на ножках можно лаконичными выражениями, без битовых масок.
PC8B=1; // логическая единица на PC8
PC8B=0; // логический ноль на PC8
PC9B=1; // логическая единица на PC9
PC9B=0; // логический ноль на PC9
Как видим, не очень сложно, особенно, если пользоваться помощью компилятора, чтобы избежать лишних вычислений.
Аналогичным способом можно определить указатели для линий других портов ввода-вывода.
Теперь перенос кода будет несколько легче.
P/S
Аналогично:
#define PA1_IN (*((volatile unsigned long *) 0x42210104)) //bit-band of PA1 as input
#define PA10_IN (*((volatile unsigned long *) 0x4221012C)) //bit-band of PA10 as input
#define PB4_IN (*((volatile unsigned long *) 0x42218110)) //bit-band of PB4 as input
#define PC14_IN (*((volatile unsigned long *) 0x42220138)) //bit-band of PC14 Input
Немного упростить жизнь поможет калькулятор:
Удачных применений!
А ещё хорошая статья на английском тут:
Из неё следует (как ессенция), что удобно, особенно при многочисленных применения использовать макросы препроцессора, например
#define PERIPHERAL_BASE 0x40000000 #define BITBAND_PERIPHERAL_BASE 0x42000000 #define BITBAND_PERIPHERAL(a,b) (BITBAND_PERIPHERAL_BASE + (a-PERIPHERAL_BASE)*0x20+(b*4)) //port D output register address #define GPIOD_ODR 0x4001140C //create a pointer to bit 5 in bit band location #define PORTDBIT5 (*((volatile unsigned long *)(BITBAND_PERIPHERAL(GPIOD_ODR,5)))) //use it somewhere to set bit to 1 int main() { //... PORTDBIT5 = 1; }
Не знаем как Вы, но мы не выдержали и запилили СВОЙ калькулятор:ПОГЛЯДЕТЬ
При использовании материалов сайта ссылка на данный источник обязательна.