EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

STR912 bitfield access to memory mapped peripherals

Started by frikkiethirion July 25, 2008
Good day,
I wonder if somebody has managed to create a structured way of accessing
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 as
soon as I make a pointer type of my union and point it to the memory bus, I
get unexpected results.

The following two posts, from 2000 and 2005, make it seem asif it is only
possible to access 4 byte values on the ARM memory architecture at a time
and that bitfield accesses won't work:
http://gcc.gnu.org/ml/gcc/2000-05/msg00776.html

http://archives.devshed.com/forums/development-94/new-volatile-keyword-changes-bitfield-access-size-from-32bit-to-1322941.html


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 it
will help, I could supply the detailed configure switches when I build the
toolchain and CFLAGS/LDFLAGS of my Makefile.

Any help will be much appreciated.

Regards,
Frikkie Thirion
On Fri, 25 Jul 2008 10:17:33 -0500, "frikkiethirion"
<frikkie@zitera.co.za> wrote:

>Good day, >I wonder if somebody has managed to create a structured way of accessing >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 as >soon as I make a pointer type of my union and point it to the memory bus, I >get unexpected results. > >The following two posts, from 2000 and 2005, make it seem asif it is only >possible to access 4 byte values on the ARM memory architecture at a time >and that bitfield accesses won't work: >http://gcc.gnu.org/ml/gcc/2000-05/msg00776.html > >http://archives.devshed.com/forums/development-94/new-volatile-keyword-changes-bitfield-access-size-from-32bit-to-1322941.html > > >My test code is as follow: >
[code snipped]
> >I'm running gcc 4.3.1, compiled for target: arm-elf, with newlib. If it >will help, I could supply the detailed configure switches when I build the >toolchain and CFLAGS/LDFLAGS of my Makefile. > >Any help will be much appreciated.
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
In article <XZidnecSAIgQcxTVnZ2dnUVZ_hudnZ2d@giganews.com>, 
frikkiethirion says...
> I wonder if somebody has managed to create a structured way of accessing > the memory mapped IO attached to the STR912 [ARM9] via bitfields. > > 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
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 http://www.teranews.com **
"frikkiethirion" ...
> I wonder if somebody has managed to create a structured way of accessing > 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 as > soon as I make a pointer type of my union and point it to the memory bus, > I > get unexpected results.
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
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 
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23623

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

The 2024 Embedded Online Conference