Hi.
I would like to use bit-banding feature in SRAM, but don't know exactly how to implement it with C. I already use bit-banding in peripheral region with this kind of macro:
#define BITBAND_PERI_REF 0x40000000
#define BITBAND_PERI_BASE 0x42000000
#define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE + (a - BITBAND_PERI_REF) * 32 + (b * 4)))
But I am confused how to connect bit-banding with some random word (half-word or byte) in SRAM, where separate bits could represent some statuses.
Thank you for your help.
Hi,
STM32 M4 as well as Freescale/NXP Kinetis M4 cores have RAM bitband alias region located at 0x22000000
Writing an analog macro for SRAM is possible:
#define BITBAND_SRAM_REF 0x20000000
#define BITBAND_SRAM_BASE 0x22000000
#define BITBAND_SRAM(a,b) ((BITBAND_SRAM_BASE + (a - BITBAND_SRAM_REF) * 32 + (b * 4)))
Personally, I use the following macro to access both Peripheral and RAM bitband regions:
#define BITBAND_REGION_BIT(src_byte_addr, bit) (((((uint32_t)(src_byte_addr) & 0x000fffff) << 5) | ((uint32_t)(src_byte_addr) & 0xfff00000) | 0x02000000) + (((uint32_t)(bit)) << 2))
Thanks.
So, you have to know exact address for a byte where a bit is located? Also for peripherals. Could you please provide an example, let say how to set EN bit (bit 0) in TIM1->CR1 register with your macro?
In my case I simply write:
BITBAND_PERI((uint32_t)&TIM1->CR1, 0) = 1;
the definition of "BITBAND_PERI" would be wrong.
It should be as the following.
#define BITBAND_PERI(a,b) *((volatile char*) ((BITBAND_PERI_BASE + (a - BITBAND_PERI_REF) * 32 + (b * 4))))
Best regards,
Yasuhiko Koumoto.
Writing is totally the same, but my macro lets you cast to any pointer (so that you can put volatile attribute for peripheral register access for instance) :
*((uint32_t*)BITBAND_REGION_BIT(&RamBitField, 4)) = 1;
But be careful about your compiler output, this may not be the more efficient way to set a bit !!
The major difference between peripheral addresses and RAM is that all peripheral addresses are known at the compilation time, whereas RAM addresses are determined at link time.
If you try to use this kind of macro on a regular RAM variable (placed at link time), your compiler will need to output instructions that perform the address computation, this is really not what you want !!
Here is a code that shows Bit manipulation in RAM with compile-time fixed address:
#define BITBAND_REGION_BIT(src_byte_addr, bit) (((((uint32_t)(src_byte_addr) & 0x000fffff) << 5) | ((uint32_t)(src_byte_addr) & 0xfff00000) | 0x02000000) + (((uint32_t)(bit)) << 2)) #define RBF_ADDRESS (0x20000100) uint32_t RamBitField @ RBF_ADDRESS = 0u; /* This is IAR syntax for absolute placement */ void test(void) { /* Bit band write access */ *((uint32_t*)BITBAND_REGION_BIT(RBF_ADDRESS, 8)) = 1; /* Read-Modify-Write */ RamBitField |= 0x10000u; }
If you look at compiler output, bit band access will lead to :
MOVS R1, #1 LDR.N R2, [PC, #0x5c] ; 0x22002020 STR R1, [R2]
Whereas standard word access:
LDR.N R0, [PC, #0x70] ; RamBitField LDR R1, [R0] ORR.W R1, R1, #4096 ; 0x1000 STR R1, [R0]
Bottom line, in my experience, most of the time you won't find any gain to use bitband access.
Yes, actually I have defined it as:
#define BITBAND_PERIPH(a,b) *(__IO uint32_t *)(PERIPH_BB_BASE + (a-PERIPH_BASE)*32 + (b*4))