STR912 bitfield access to memory mapped peripherals

Good day, I wonder if somebody has managed to create a structured way of accessin the memory mapped IO attached to the STR912 [ARM9] via bitfields.

I can manipulate the members of a union that is declared in main(), bus a soon as I make a pointer type of my union and point it to the memory bus, get unexpected results.

The following two posts, from 2000 and 2005, make it seem asif it is onl possible to access 4 byte values on the ARM memory architecture at a tim and that bitfield accesses won't work:

formatting link

formatting link

My test code is as follow:

main() { uint32_t uwI; uint32_t *pwPointer;

typedef struct { volatile uint32_t PLL_MDIV:8; // [7:0] PLL Pre-divider volatile uint32_t PLL_NDIV:8; // [15:8] PLL Feedback divider volatile uint32_t PLL_PDIV:3; // [18:16] PLL Post-divider volatile uint32_t PLL_EN:1; // [19] PLL Enable (0=off, 1=on)

volatile uint32_t uwPAD:12; // [31:20] -PADDING- } mySCU_PLLCONF_t;

typedef union { volatile uint32_t ALL; volatile mySCU_PLLCONF_t BITS; } mySCU_PLLCONF_u; mySCU_PLLCONF_u umyPLLCONF; volatile mySCU_PLLCONF_u *pPLLCONF;

umyPLLCONF.BITS.PLL_MDIV = 0x80; umyPLLCONF.BITS.PLL_NDIV = 0x10; umyPLLCONF.BITS.PLL_PDIV = 0x2; umyPLLCONF.BITS.PLL_EN = 1;

uwI=umyPLLCONF.ALL; The value in uwI is 0x000a1080, as expected.

// ON SCU bus pwPointer = (uint32_t *)(AHB_NB_APB1_BASE + SCU_OFST); //5c00 2000 pwPointer++; //increment one word, to get aligned with PLL //5c00 2004 pPLLCONF = (mySCU_PLLCONF_u *)pwPointer; pPLLCONF->BITS.PLL_MDIV = 0x80; uwI=pPLLCONF->ALL; //Value is 0x8080-->Both 'MDIV' and 'NDIV'altered... pPLLCONF->BITS.PLL_NDIV = 0x10; uwI=pPLLCONF->ALL; //Value is 0x1010-->Both 'MDIV' and 'NDIV'altered... }

I'm running gcc 4.3.1, compiled for target: arm-elf, with newlib. If i will help, I could supply the detailed configure switches when I build th toolchain and CFLAGS/LDFLAGS of my Makefile.

Any help will be much appreciated.

Regards, Frikkie Thirion

Reply to
frikkiethirion
Loading thread data ...

[code snipped]

It is an extremely bad idea to use bitfields to access hardware registers. There is absolutely no guarantee about how the actual accesses wil be handled by the compiler. Handle the bits by reading/writing the register with required size, and mask the bits as required.

Regards Anton Erasmus

Reply to
Anton Erasmus

Don't do that, it's a bad idea. Seductively bad. Why? you might ask.

- Well first it's both compiler and architecture dependant. That means you cannot tell what's happening in the code by reading it making future maintenance a nightmare. Anyone maintaing the code is going to have to look up the details on how this particular compiler deals with bitfield layout. - Also I suspect that the use of uint32_t in a bit field is not fully defined. IIRC only int and unsigned int are allowed. On an ARM they happen to map to the same thing but... Of course that's particular to this example.

But, you respond, I will only ever be working with a single compiler and architecture. - Have you no sympathy for anyone else who has to maintain the project? Maybe you are developing something that doesn't need to be maintained if you are not around?

If that doesn't convince you consider that what happens when you access a bitfield isn't fully specified. As a for instance consider accessing PLL_MDIV above, the access could be via an 8, 16 or 32bit set of operations (and the 16 and 32 bit methos would require some sort of read-modify-write operation). It is possible (and yes some hardware does have these restrictions) that all access's to this hardware must be made only via 32bit read/writes or maybe only via 8 bit read/writes. It's also possible that a RMW sequence will not work due to harware restrictions. And, yes there are compilers that will optimize the access to 8 bits.

Bitfields on I/O are seductive (i've been seduced by them a time or two myself) but ultimately they cause more problems than they solve. Bitfields are only usefule to reduce in memory storage at the expense of access time.

Robert

** Posted from
formatting link
**
Reply to
Robert Adsett

"frikkiethirion" ...

I know from bad experience that (at least some) GCC compilers do minimize the access - for a bitfield in a 32-bit word it only does a byte read-modify-write, which is deadly for the other bits if you are accessing an I/O register that can only be accessed 32-bits wide. For memory it's OK, so I update a RAM based copy, then write the result to the I/O register. Use a critical section or mutex around the whole operation if other drivers use the other bits...

Arie de Muynck

Reply to
Arie

Good day,

I've created patches for GCC 4.3.2 and GCC 4.4.0 to honor the specified container type of the bitfield when

1) The variable is declared volatile and 2) The gcc internal: TARGET_NARROW_VOLATILE_BITFIELD is '0' (Needs to be set at compile time for GCC. For 'arm' architecture, it is

currently the default setting)

I've posted the patches to

formatting link

If anybody is interested in this, please test it and give me some feedback if it is working for you. I've tested the patches on actual hardware (ST STR912FW44) and it works fine. The included disassembly listings also confirm the correct accesses.

Regards, Frikkie

Reply to
frikkiethirion

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.