currently i am working on a project with an ARM M4F on arm-gcc and eclipse.
I have declared bitfields within structs to access the IO-registers. Please see as example:
struct abc{
volatile U32 a:1;
volatile U32 b:1;
volatile U32 c:30;
}
Now, some of these structs are mappend onto peripherals, which use a set of "Set and Clear" registers.
You write 1U to the Set-Register to set the specific bit and 1U to the Clear-Register to clear the specific bit.
BUT If a bit is set, it is also reflected as set in the Clear-Register for reads.
So abc_set.a = 1U;
results in abc_clear.a == 1U
In my code if have written: abc_clear.a = 1U;
This results in arm-gcc generating:
ldr.w r0, [r1, #128] ; 0x80
orr.w r0, r0, #536870912 ; 0x20000000
str.w r0, [r1, #128] ; 0x80
The compiler enforces a Read-Modify-Write approach.
BUT If other bits are reflected as "1U" in the abc_clear registers, they get also written as 1U and are subsequently cleared as well.
My question is
How can i enforce gcc to use a "Write-Only" sheme for specific registers?
I am looking for something like:
struct abc{
#pragma "Only-Write" / or attribute((only-write))
volatile U32 a:1;
#pragma "R-M-W allowed"
volatile U32 b:1;
volatile U32 c:30;
}
I have declared bitfields within structs to access the IO-registers.
You can't do this with bitfields. Basically, bitfields are not good for this purpose. uP do not have instructions to write or read a few (less than 8) bits only *. You wasted your time
You need to do this traditional way
#define REG_X_A_POS (0)
#define REG_X_A (1<<REG_X_A_POS)
#define REG_X_B_POS (1)
#define REG_X_B (1<<REG_X_B_POS)
#define REG_X (*(volatile uint32_t *)0x44006655)
And usage:
REGX = REG_X_A
And the resulting code:
foo:
ldr r3, .L2
movs r2, #1
str r2, [r3, #1616]
.L2:
.word 1140875264
When you need RMW you just do it yourself:
REG_X |= REG_X_A;
and the compiler will generate the correct code
ldr r2, .L3
ldr r3, [r2, #1616]
orr r3, r3, #1
str r3, [r2, #1616]
.L3:
.word 1140875264
Another way is to use a temporary variable (not a very convenient way).
struct abc tempReg = abc_set;
tmpReg.a = 1;
abc_set = tempReg
* You can do this using (M4) bitbang areas, but the compiler does not know anything about it.