I have searched information on Bit-Banding in Cortex-M3 and M4 with the GNU GCC ARM EABI NONE, I have seen basic examples on the internet but none works with GNU GCC also seems that no intention to have such feature implemented.
Can someone tell me if the LD via memory remapping really work? the best approach?
What is the best way?
> none works with GNU GCC
can you be more specific on how you tested this?
I use bit banding for the peripheral memory range without problems, but by using direct access, without any expectations from the linker scripts.
BitBanding works with GCC.
There are two ways BitBanding can be used.
ARM Keil offers an extra attribute for bitbanding:
Compiler User Guide: __attribute__((bitband)) type attribute
To me, it looks like the __attribute__((bitband)) have not yet made it into GCC (please correct me if I'm wrong).
There are two manual approaches too. One is to calculate the address yourself (normally by using macros), the other is to make the compiler/linker do the hard work and make the source code pretty (by using a linker-script that supports the bitband regions).
I believe the approach you want to take, by using the linker-scripts should work.
-But I also believe it's important to mark all the variables, which you intend to use with bitbanding as 'volatile'.
If you don't, your compiler will cache the old variable values and you will not see the effect of the bit-changes.
Example: You have an 8-bit variable in main memory. You set its value to 10.
In the next line, you use the bitband region to clear bit 1.
In the next line, you use printf to send the result of the variable to your favourite debug-console.
You get the result '10' if you did not mark any of the variables 'volatile'. You get the result '8' if you marked both variables 'volatile'. If you marked only one of the variables volatile, you may get either 8 or 10, but not always the value you would expect.
In short: Mark both the 8-bit and the 1-bit 'variables' as volatile, and it should work the way you would expect.
Hi!
Liviu (ilg), I'm using to show my students the impact of Bit-Banding when migrating from AVR to ARM and unlike the technique used both for access to bit-fields in IO ports.
In case I did some testing with their own Arduino IDE, and enter the code below, and made the dump and the code is mixed C and Assembly, did nothing more than the statement of the variable and then assigns the value 1 to she.;
0008014c <loop>: ;volatile __attribute__((bitband, at(0x20000004))) uint32_t myFlag =0 ; ;void loop() { ; myFlag = B00000001; 8014c: 4b01 ldr r3, [pc, #4] ; (80154 <loop+0x8>) 8014e: 2201 movs r2, #1 80150: 601a str r2, [r3, #0] ;} 80152: 4770 bx lr 80154: 200708f0 .word 0x200708f0 I figured it did not reach the goal because of the memory address that is the variable, and then I search the internet in the ARM GCC site for windows saw the post that is the link to follow that would not be supported yet.
0008014c <loop>: ;volatile __attribute__((bitband, at(0x20000004))) uint32_t myFlag =0 ; ;void loop() { ; myFlag = B00000001; 8014c: 4b01 ldr r3, [pc, #4] ; (80154 <loop+0x8>) 8014e: 2201 movs r2, #1 80150: 601a str r2, [r3, #0] ;} 80152: 4770 bx lr 80154: 200708f0 .word 0x200708f0
I figured it did not reach the goal because of the memory address that is the variable, and then I search the internet in the ARM GCC site for windows saw the post that is the link to follow that would not be supported yet.
Question #228758 : Questions : GNU ARM Embedded Toolchain
Moreover, I suspect that lack a directive in the command, would it? But in issue up says it is not supported.
Jens (jensbauer), I am using the ARM GNU GCC GNU ARM Embedded Toolchain in Launchpad , Keil also uses the same compiler? I think no!
Nope.
GCC is one compiler.
ARM's own compiler is a different compiler
and clang is a third compiler.
Previous versions of Keil uses ARM's own compiler.
Newer versions of Keil uses clang.
-So GCC, which is used for almost every system, which is not Windows, does not have the __attribute__((bitband)) available.
However, I'd like to encourage you to try the linker script and remember to prefix every variable you use with bitbanding by 'volatile'.
If that fails, you can still use bitbanding the old way (by using predefined macros).
If you're using STM, I know ST-Microelectronics have macros defined in STM32Cube.
carlosdelfino, I'm not sure I understand what you want to show to your students.
bit-banding basically maps each bit to a word address, so a simple pointer arithmetic does the trick
(PERIPHERAL_BITBAND_BASE + (((registerAddress - PERIPHERAL_BASE) * 8) + bitNumber) * 4)
a functional template can be seen in an older µOS++ repository: micro-os-plus-iii-alpha/BitBand.h (the implementation needs some updates for the new µOS++ code style and C++ 14 goodies, but is functional).
This is a guess only, but I think carlosdelfino is teaching the students that if you need to set or clear a single bit, you can use a single write-cycle instead of read+modify+write cycle (3 or 4 clock cycles).
On AVR, it's necessary to read, then use either AND or OR and then write back the modified value.
That has a terrible disadvantage on the AVR. If you write to a port from an interrupt and you want to change a single bit from task-time, you risk that the interrupt will run in the middle of your read-modify-write cycle, which means that the values your interrupt writes will be available on the port for only a short time, then it's quickly changed back to what it was by your task-time.
To fix that, you can disable interrupts and re-enable them after updating the port at task-time (now 5 clock cycles were used instead of only 1 on ARM).
So one topic is the atomic access, the other topic is saving CPU-time on accessing the same port from both interrupt code and task-time code.
Exactly @Jensbauer
ilg I checked the example of uOS, but I believe it is not the time to introduce students to the C ++, even though a more advanced topic due to the use of Arduino maintein a low level overall.
I think very valid use of C ++ in microcontrollers, but some structures and the profile of the students who have worked makes the complex topic with C ++ since it would have to enter a preliminary study of the language C ++, even if they already have guidance notions object , as that C is already almost intuitive to them.
In GCC, I did not realize even attribute effect (AT) do not know what went wrong yet, I will do new tests. I hoped that at least he would allow me to allocate variáel in a specific position preventing the reuse of the address.
ilg I wanted to avoid using this macro.
I will now see the example in uOS.
The jensbauer perfectly conveyed my Intent, which comes down show atomicity in the use of bit-bading Cortex-M and the difference in the AVR.
> not the time to introduce students to the C ++
then I'm afraid you need to use a macro. see the examples in Joseph Yiu's book (The Definitive Guide to ARM Cortex-M3 and M4, chapter 6.7.4).
personally I'm no longer that impressed with bit-band accesses; yes, they are atomic and they are fast, but only work for one bit. if you have a bitfield of 2 or more bits, don't be fooled into thinking that a sequence of bit-band accesses can be used, this is equivalent to setting a sequence of different values, which might not be what you want, not to mention that some of the intermediate values might be illegal.
I'm quite positive that it can be done with plain C and a linker-script (without using the macro).
The linker-script will need two special sections; one for bitband-access and one for normal access.
Then making two instances of the variable using 'volatile __attribute__((section("NAME")))', where NAME is for instance bitband_bits or bitband_vars.
It would be safest to group those two together, however, there's no guarantee that it will work well, if more than one bitband variable is used at a time.
carlosdelfino: The macro will be just as fast as the linker-script access, it's also the safest approach if you're not using Keil.
Well, the question does not move unseen by theme.
this is very important consideration when it comes to more than one bit, actually at the end ends up not being such a definitive solution, but anyway still win the amount of instructions.
Yes doubts in Jesph Yiu book is complete on this issue, but as I saw some discussions about the use of GCC thought something might have emerged something new after 2013 about the https://answers.launchpad.net/gcc-arm-embedded/+question/228758
Thanks for the suggestions.
I am teaching this to my class in Embedded Systems this semester. We are using System Workbench for STM32 (SW4STM32) which is an Eclipse based IDE that uses GCC as the build toolchain. Anything done in this environment will work just as well with command line versions of GCC as well. I am not using LD scripts to do any of this, but rather doing much simpler preprocessor directives that provide the effect that I think you are looking for.
What I find to be the simplest and most direct way to implement both direct memory-mapped register addressing, as well as bitband access is through a few simple #define statements. These do not allocate any storage in memory and simply direct the compiler on how to access memory locations with fixed pointer addresses.
To access any particlular register, a statement of the form:
#define REGISTER_NAME (*((volatile uint32_t *) 0x400xxxxx))
will create a variable name (which is a de-referenced pointer) which allows you to access a uint32_t quantity located at address 0x400xxxxx directly. Setting or resetting a bit would be done like this:
REGISTER_NAME |= 0x080;
REGISTER_NAME &= 0xFFFFFF7F;
Which will set or reset bit 7 respectively with a mask that will prevent unwanted changes to other bits in the register.
You can also define a macro similarly to calculate a bitband address that takes as input the register address and the bit number and returns the 32 bit address value in the bitband space. A call to this macro can be substituted for the absolute address in the above define statement so that in one line (after the bitband macro is defined) you can define a variable name that, when used, will write directly to the correct bitband address corresponding to the bit position and register address of interest.
The bitband macro for the peripheral bitband space (the 0x40000000 band, if you want the SRAM bitband just change the base addresses appropriately) can be defined as:
#define BITBAND_PERIPH(addr,bitpos) (((addr - 0x40000000)*32 + bitpos*4) + 0x42000000)
then BITBAND_PERIPH() can be inserted in place of the address value above, so to create a variable name which, when used, will access the bitband location alias for Bit position 12 in the register located at 0x40020014, you would write:
#define GPIO_REG_BB (*((volatile uint32_t *) BITBAND_PERIPH(0x40020014, 12))
Once done, reads and writes to GPIO_REG_BB will access the alias address in the BitBand region for the register and bit position described above.