With the support of bit operations in the Cortex-M3, single bits can be read and written using normal load/store instructions.
In the bit-banding supported by the CM3, bit-banding is implemented in two regions.
One is the lowest 1MB range of the SRAM region, 0x20000000 ‐ 0x200FFFFF (the lowest 1MB in the SRAM region);
the second is the lowest 1MB range of the on-chip peripheral region, 0x40000000 ‐ 0x400FFFFF (the lowest 1MB in the on-chip peripheral region).
In addition to being able to use the addresses in these two regions like normal RAM, they also have their own "bit-band alias region", which expands each bit into a 32-bit word. When you access these words through the bit-band alias region, you can achieve the purpose of accessing the original bit.
CM3 uses the following terms to represent the addresses associated with bit-band storage:
* Bit-band region: Address region that supports bit-band operations
* Bit-band alias: Access to the alias address ultimately affects access to the bit-band region (note: there is an address mapping process in between).
Each bit in the bit-band region is mapped to a word in the alias address region - this is a word with only the LSB being valid (only the least significant bit of the word in the bit-band alias region is meaningful).
For a certain bit in SRAM,
the address of the bit in the bit-band alias area is: AliasAddr = 0x22000000 + ((A-0x20000000)*8+n)*4
= 0x22000000 + (A-0x20000000)*32 + n*4For
a certain bit in the on-chip peripheral bit-band area,
the address of the bit in the bit-band alias area is: AliasAddr = 0x42000000 + ((A-0x40000000)*8+n)*4
= 0x42000000 + (A-0x40000000)*32 + n*4Where
A is the address of the byte where the bit is located, 0 <= n <= 7
"*4" means that a word is 4 bytes, and "*8" means that there are 8 bits in a byte.
Of course, bit-band operations are not limited to word-based transfers. It can also be transferred in half-word and byte units.
Bit-banding operations have many benefits, one of which is that they are used to implement "interlocked" access to shared resources between tasks in a multi-tasking system. Multi-tasking shared resources must satisfy the requirement that only one task accesses it at a time - the so-called "atomic operation".
Using bit-banding operations in C language
There is no direct support for bit-banding operations in the C compiler. For example, the C compiler does not know that the same block of memory can be accessed using different addresses, nor does it know that access to the bit-band alias area is only valid for the LSB.
To use bit-banding operations in C, the simplest way is to #define the address of a bit-band alias area. For example:
#define DEVICE_REG0 ((volatile unsigned long *) (0x40000000))
#define DEVICE_REG0_BIT0 ((volatile unsigned long *) (0x42000000))
#define DEVICE_REG0_BIT1((volatile unsigned long *) (0x42000004)) ...
*DEVICE_REG0 = 0xab; //Use normal address to access register
*DEVICE_REG0_BIT1 = 0x1;
It can be simplified further:
//Macro to convert "bit band address + bit number" into alias address
#define BITBAND(addr, bitnum)((addr & 0xF0000000)+0x2000000+((addr & 0xFFFFF)<<5)+(bitnum<<2))
//Convert the address into a pointer
#define MEM_ADDR(addr) *((volatile unsigned long *) (addr))
So:
MEM_ADDR(DEVICE_REG0) = 0xAB; //Use normal address to access register
MEM_ADDR(BITBAND(DEVICE_REG0,1)) = 0x1; //Use bit band alias address
Note: When you use the bit band function, the variable to be accessed must be defined with volatile. Because the C compiler does not know that the same bit can have two addresses, volatile is used to make the compiler write the new value to the memory faithfully every time, instead of using registers to operate the copy of the data in the middle for optimization reasons, and writing the copy back at the end.
As follows:
// Convert "bit segment address + bit number" to an alias address macro
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
//Convert the address into a pointer
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR( BITBAND(addr, bitnum) )
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define PA0 BIT_ADDR(GPIOA_ODR_Addr, 0) //Output
the above addr to represent the bit The address of the band ranges from 0x20000000 to 0x200FFFFF, 0x40000000 to 0x400FFFFF,
addr &0xFFFFF table extracts the offset bits, and the upper 12 bits (000) are masked.
Bit band alias, 32MB in total; Bit band region, 1MB in total; the correspondence between the two is easy to understand, 1 word is 32 bits, each bit in 32 bits is expanded into one word, then one word in the bit band region requires 32 words in the bit band alias, so it is not difficult to understand that 1MB of bit band corresponds to 32MB of bit band alias region.
I checked the lowest 1MB of Peripheral, starting from 0x4000_0000 to 0x4010_0000. It includes all peripheral registers, that is, all peripheral registers can be viewed using the bit alias region.
Page 89 of the ARM Cortex-M3 Authoritative Guide lists two equations for calculating the address of the bit-band alias region, such as the Peripheral calculation:
AliasAddr=0x42000000+((A-0x40000000)*8+n)*4=0x42000000+(A-0x40000000)*32+n*4;
In fact, I understand that the latter way of writing is easier to understand.
AliasAddr=0x42000000+(A-0x40000000)*32+n*4,
0x42000000 is the starting address of the bit alias area;
(A-0x40000000)*32, A is the register address, subtracting the starting address, we can get the total number of words offset, each word has 32 bits, we can calculate the starting address of the relative register; n*4, similarly, each bit occupies 4 bytes, and the number of bits is multiplied by 4 to get the offset address of the register; one bit occupies 32 bits in the alias area, four bytes. In
the example on page 91 of the English content of Cortex_M3, 0x23FFFFE0=0x22000000+(0xFFFFF*32)+0*4;
I think this way of writing is easier to understand. Excluding the base address of the entire peripheral, only the offset address is calculated, which is relatively easier to understand.
In GCC and RealView MDK (Keil) development tools, it is allowed to manually specify the address of a variable when defining it. For example:
volatile unsigned long bbVarAry[7]__attribute__(( at(0x20003014) ));
volatile unsigned long* const pbbaVar= (void*)(0x22000000+0x3014*8*4);
// The "const" after long* tells the compiler that the pointer can no longer be modified to point to another address.
// Note: The address in at() must be aligned to a 4-byte boundary.
In this way, 7 words are allocated at 0x20003014, resulting in a total of 32*7=224 bits.
When using these bits, you can use the following form:
pbbaVar[136]=1; //Set bit 136
However, this has a limitation: the compiler cannot check whether the subscript is out of bounds.
This is also a limitation of the compiler: it does not know that this array is actually bbVarAry[7], so it will count 224*4 bytes more when calculating the memory usage of the program.
For pointers, give each bit to be used a literal name, and only use literal names in the subscript instead of actual numbers, which can greatly avoid array out-of-bounds.
Please note: when defining these "two" variables, "volatile" is added in front. If you no longer use bbVarAry to access these bits, but only use bit-band aliases to access them, these two volatiles are no longer needed.
Previous article:Things to note when porting STM32F05x to GD32F1x0
Next article:STM32F enters STOPMode method and precautions after waking up
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Detailed explanation of intelligent car body perception system
- How to solve the problem that the servo drive is not enabled
- Why does the servo drive not power on?
- What point should I connect to when the servo is turned on?
- How to turn on the internal enable of Panasonic servo drive?
- What is the rigidity setting of Panasonic servo drive?
- How to change the inertia ratio of Panasonic servo drive
- What is the inertia ratio of the servo motor?
- Is it better for the motor to have a large or small moment of inertia?
- What is the difference between low inertia and high inertia of servo motors?
- VII. Power supplies for “Control” questions
- Why is UWB indoor positioning, which is mainly aimed at shopping malls and underground garages, not being utilized?
- Crystal Oscillator Accuracy PPM
- With an estimated total investment of 600 million yuan, Baidu's 5G Smart City intelligent driving project has landed in Chengdu. What do you think of this?
- GD32L233C-START Development Board Evaluation 2: GD32L233C Chip Low Power Performance Test 1
- A novice asked a question about the if statement in C language
- [SAMR21 New Gameplay] 9. Serial Communication-2
- I just used the 1904 version of AD and why can't I get 3D display in LIB
- Ask for a lithium battery boost solution
- Phase-Locked Loop (PLL)