Difference between revisions of "STM32 Bit Banding (or bit-banding)"

From Stm32World Wiki
Jump to navigation Jump to search
 
(14 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
[[Category:STM32]][[Category:STM32 Development]][[Category:C]]{{metadesc|Bit Banding in STM32 MCUs}}
 
[[Category:STM32]][[Category:STM32 Development]][[Category:C]]{{metadesc|Bit Banding in STM32 MCUs}}
In older 8-bit [[MCU]]s it was quite common to have instructions to clear or set a bit as one atomic instruction.  By atomic it means the read->modify->write can not be interrupted resulting in other bits being set wrongly.
+
In older 8-bit [[MCU]]s it was quite common to have instructions to clear or set a bit as one atomic instruction.  By atomic it means the read->modify->write can not be interrupted resulting in other bits being set wrongly.  Unfortunately [[ARM]] did not implement such instructions in the ARM cores.  They did however implement something known as "bit banding" (or bit-banding - not to be confused with [[STM32 bit bang PWM|bit banging]]).
  
Unfortunately [[ARM]] did not implement such instructions in the ARM coresThey did however implement something known as "bit banding" (or bit-banding).
+
Bit banding is an aliased region of memory addresses where each address point to exactly one bit in the original byteThese bytes get updated accordingly to the bits in the original byte and when or if changes only that single bit of the original get set or reset. There are two of these bands.  One is covering the entire SRAM space and one is covering all the peripheral registers.
  
== Macro's to Calculate Bit Band Address ==
+
== Video ==
 +
 
 +
Video here: [https://www.youtube.com/watch?v=a0UQXd8kgbs https://www.youtube.com/watch?v=a0UQXd8kgbs]
 +
 
 +
<center>
 +
{{#ev:youtube|a0UQXd8kgbs}}
 +
</center>
 +
 
 +
== Principle ==
 +
 
 +
The overall principle is that each bit in the memory which is part of a bit-band region correspond to an aliased address for each bit.  On STM32Fxx all SRAM and all peripheral registers are part of a bit-band region.
 +
 
 +
<div class="res-img">
 +
[[File:Bit-band illustration.webp]]
 +
</div>
 +
 
 +
If the original address get updated all the bit-band addresses get update too - and visa-versa.
 +
 
 +
== Calculating Bit Band Address ==
 +
 
 +
The formula for calculating the bit band address is described in the reference manual (for the STM32F405 [https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf here]) like this:
 +
 
 +
<div class="res-img">
 +
[[File:Bit Band Formula.png|600px]]
 +
</div>
 +
 
 +
The values are defined in the 'stm32f405xx.h' file generated by [[STM32CubeMX]] and part of the HAL library:
  
 
<pre>
 
<pre>
#define BITBAND_SRAM_REF    0x20000000
+
#define FLASH_BASE            0x08000000UL /*!< FLASH(up to 1 MB) base address in the alias region                        */
#define BITBAND_SRAM_BASE  0x22000000
+
#define CCMDATARAM_BASE      0x10000000UL /*!< CCM(core coupled memory) data RAM(64 KB) base address in the alias region  */
#define BITBAND_PERIPH_REF  0x40000000
+
#define SRAM1_BASE            0x20000000UL /*!< SRAM1(112 KB) base address in the alias region                            */
#define BITBAND_PERIPH_BASE 0x42000000
+
#define SRAM2_BASE            0x2001C000UL /*!< SRAM2(16 KB) base address in the alias region                              */
 +
#define PERIPH_BASE          0x40000000UL /*!< Peripheral base address in the alias region                                */
 +
#define BKPSRAM_BASE          0x40024000UL /*!< Backup SRAM(4 KB) base address in the alias region                        */
 +
#define FSMC_R_BASE          0xA0000000UL /*!< FSMC registers base address                                                */
 +
#define SRAM1_BB_BASE        0x22000000UL /*!< SRAM1(112 KB) base address in the bit-band region                          */
 +
#define SRAM2_BB_BASE        0x22380000UL /*!< SRAM2(16 KB) base address in the bit-band region                          */
 +
#define PERIPH_BB_BASE        0x42000000UL /*!< Peripheral base address in the bit-band region                            */
 +
#define BKPSRAM_BB_BASE      0x42480000UL /*!< Backup SRAM(4 KB) base address in the bit-band region                      */
 +
#define FLASH_END            0x080FFFFFUL /*!< FLASH end address                                                          */
 +
#define FLASH_OTP_BASE        0x1FFF7800UL /*!< Base address of : (up to 528 Bytes) embedded FLASH OTP Area                */
 +
#define FLASH_OTP_END        0x1FFF7A0FUL /*!< End address of : (up to 528 Bytes) embedded FLASH OTP Area                */
 +
#define CCMDATARAM_END        0x1000FFFFUL /*!< CCM data RAM end address
 +
</pre>
  
 +
Presumably these definitions are available on other processor series as well.
 +
 +
Using the formula, we can now create some macros to calculate the bit band address for both SRAM and peripherals:
 +
 +
<pre>
 
#define bitband_t *(volatile uint32_t*)
 
#define bitband_t *(volatile uint32_t*)
  
#define m_BITBAND_SRAM(address,bit) (BITBAND_SRAM_BASE + (((uint32_t)address) - BITBAND_SRAM_REF) * 32 + (bit) * 4)
+
#define BITBAND_SRAM(address,bit) (SRAM1_BB_BASE + (((uint32_t)address) - SRAM1_BASE) * 32 + (bit) * 4)
#define m_BITBAND_PERIPH(address,bit) (BITBAND_PERIPH_BASE + (((uint32_t)address) - BITBAND_PERIPH_REF) * 32 + (bit) * 4)
+
#define BITBAND_PERIPH(address,bit) (PERIPH_BB_BASE + (((uint32_t)address) - PERIPH_BASE) * 32 + (bit) * 4)
 
</pre>
 
</pre>
  
Line 23: Line 66:
  
 
<pre>
 
<pre>
*((uint8_t *)m_BITBAND_SRAM(&v, 7)) = 1;
+
*((uint8_t *)BITBAND_SRAM(&v, 7)) = 1;
*((uint8_t *)m_BITBAND_SRAM(&v, 6)) = 0;
+
*((uint8_t *)BITBAND_SRAM(&v, 6)) = 0;
*((uint8_t *)m_BITBAND_SRAM(&v, 5)) = 1;
+
*((uint8_t *)BITBAND_SRAM(&v, 5)) = 1;
*((uint8_t *)m_BITBAND_SRAM(&v, 4)) = 0;
+
*((uint8_t *)BITBAND_SRAM(&v, 4)) = 0;
*((uint8_t *)m_BITBAND_SRAM(&v, 3)) = 1;
+
*((uint8_t *)BITBAND_SRAM(&v, 3)) = 1;
*((uint8_t *)m_BITBAND_SRAM(&v, 2)) = 0;
+
*((uint8_t *)BITBAND_SRAM(&v, 2)) = 0;
*((uint8_t *)m_BITBAND_SRAM(&v, 1)) = 1;
+
*((uint8_t *)BITBAND_SRAM(&v, 1)) = 1;
*((uint8_t *)m_BITBAND_SRAM(&v, 0)) = 0;
+
*((uint8_t *)BITBAND_SRAM(&v, 0)) = 0;
 
</pre>
 
</pre>
  
Line 36: Line 79:
  
 
<pre>
 
<pre>
uint8_t *led_pin = (uint8_t *)m_BITBAND_PERIPH(&LED_GPIO_Port->ODR, 13);
+
uint8_t *led_pin = (uint8_t *)BITBAND_PERIPH(&LED_GPIO_Port->ODR, 13);
  
 
// Toggle LED
 
// Toggle LED
Line 44: Line 87:
 
== Miscellaneous Links ==
 
== Miscellaneous Links ==
  
To be added
+
* [https://github.com/STM32World/stm32fun/tree/master/stm32world_bitband Code Example]

Latest revision as of 08:18, 31 October 2024

In older 8-bit MCUs it was quite common to have instructions to clear or set a bit as one atomic instruction. By atomic it means the read->modify->write can not be interrupted resulting in other bits being set wrongly. Unfortunately ARM did not implement such instructions in the ARM cores. They did however implement something known as "bit banding" (or bit-banding - not to be confused with bit banging).

Bit banding is an aliased region of memory addresses where each address point to exactly one bit in the original byte. These bytes get updated accordingly to the bits in the original byte and when or if changes only that single bit of the original get set or reset. There are two of these bands. One is covering the entire SRAM space and one is covering all the peripheral registers.

Video

Video here: https://www.youtube.com/watch?v=a0UQXd8kgbs

Principle

The overall principle is that each bit in the memory which is part of a bit-band region correspond to an aliased address for each bit. On STM32Fxx all SRAM and all peripheral registers are part of a bit-band region.

Bit-band illustration.webp

If the original address get updated all the bit-band addresses get update too - and visa-versa.

Calculating Bit Band Address

The formula for calculating the bit band address is described in the reference manual (for the STM32F405 here) like this:

Bit Band Formula.png

The values are defined in the 'stm32f405xx.h' file generated by STM32CubeMX and part of the HAL library:

#define FLASH_BASE            0x08000000UL /*!< FLASH(up to 1 MB) base address in the alias region                         */
#define CCMDATARAM_BASE       0x10000000UL /*!< CCM(core coupled memory) data RAM(64 KB) base address in the alias region  */
#define SRAM1_BASE            0x20000000UL /*!< SRAM1(112 KB) base address in the alias region                             */
#define SRAM2_BASE            0x2001C000UL /*!< SRAM2(16 KB) base address in the alias region                              */
#define PERIPH_BASE           0x40000000UL /*!< Peripheral base address in the alias region                                */
#define BKPSRAM_BASE          0x40024000UL /*!< Backup SRAM(4 KB) base address in the alias region                         */
#define FSMC_R_BASE           0xA0000000UL /*!< FSMC registers base address                                                */
#define SRAM1_BB_BASE         0x22000000UL /*!< SRAM1(112 KB) base address in the bit-band region                          */
#define SRAM2_BB_BASE         0x22380000UL /*!< SRAM2(16 KB) base address in the bit-band region                           */
#define PERIPH_BB_BASE        0x42000000UL /*!< Peripheral base address in the bit-band region                             */
#define BKPSRAM_BB_BASE       0x42480000UL /*!< Backup SRAM(4 KB) base address in the bit-band region                      */
#define FLASH_END             0x080FFFFFUL /*!< FLASH end address                                                          */
#define FLASH_OTP_BASE        0x1FFF7800UL /*!< Base address of : (up to 528 Bytes) embedded FLASH OTP Area                */
#define FLASH_OTP_END         0x1FFF7A0FUL /*!< End address of : (up to 528 Bytes) embedded FLASH OTP Area                 */
#define CCMDATARAM_END        0x1000FFFFUL /*!< CCM data RAM end address

Presumably these definitions are available on other processor series as well.

Using the formula, we can now create some macros to calculate the bit band address for both SRAM and peripherals:

#define bitband_t *(volatile uint32_t*)

#define BITBAND_SRAM(address,bit) (SRAM1_BB_BASE + (((uint32_t)address) - SRAM1_BASE) * 32 + (bit) * 4)
#define BITBAND_PERIPH(address,bit) (PERIPH_BB_BASE + (((uint32_t)address) - PERIPH_BASE) * 32 + (bit) * 4)

Usage Examples

Considering a variable v, the bits can be individually set/reset like this:

*((uint8_t *)BITBAND_SRAM(&v, 7)) = 1;
*((uint8_t *)BITBAND_SRAM(&v, 6)) = 0;
*((uint8_t *)BITBAND_SRAM(&v, 5)) = 1;
*((uint8_t *)BITBAND_SRAM(&v, 4)) = 0;
*((uint8_t *)BITBAND_SRAM(&v, 3)) = 1;
*((uint8_t *)BITBAND_SRAM(&v, 2)) = 0;
*((uint8_t *)BITBAND_SRAM(&v, 1)) = 1;
*((uint8_t *)BITBAND_SRAM(&v, 0)) = 0;

A peripheral - for example port 13 on GPIOC can be handled like this:

uint8_t *led_pin = (uint8_t *)BITBAND_PERIPH(&LED_GPIO_Port->ODR, 13);

// Toggle LED
*led_pin = !*led_pin;

Miscellaneous Links