STR912 bitfield access to memory mapped peripherals

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
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:
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 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

Re: STR912 bitfield access to memory mapped peripherals
On Fri, 25 Jul 2008 10:17:33 -0500, "frikkiethirion"

Quoted text here. Click to load it
[code snipped]
Quoted text here. Click to load it

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



Re: STR912 bitfield access to memory mapped peripherals
frikkiethirion says...
Quoted text here. Click to load it

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


Re: STR912 bitfield access to memory mapped peripherals

"frikkiethirion" ...
Quoted text here. Click to load it

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



Re: STR912 bitfield access to memory mapped peripherals
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?id23%623

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

Site Timeline