This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

--bitband compiler switch fails (very strange!!!)

Look at this (Controller: STM32F407I, uVision 4.23, Armcc 4.1.0.894):

struct __attribute__((bitband)){
  unsigned int Bit1:1;
  unsigned int Bit2:1;
}Bits __attribute__((at(0x20000100)));

int main( void){

  Bits.Bit1= 1;

  while(1);
}


This compiles nicely with the compiler switch --bitband to the following code (for the C command line "Bits.Bit1=1"):

0x08000278 4901      LDR           r1,[pc,#4]  ; @0x08000280
0x0800027A 2001      MOVS          r0,#0x01
0x0800027C 6008      STR           r0,[r1,#0x00]


And at address 0x08000280 the correct memory address for bitbanding 0x22000000.

Now, if I insert

#include <stm32f4xx.h>


at the first line of the code, then I get exactly the same assembler code, but at address 0x08000280 the value is 0x20000000. And this of course is NOT correct for bit banding.

Anyone has an idea, what is going on here? How can this be influenced by this standard header file (from the standard Keil folder \Keil\ARM\Inc\ST\STM32F4xx). This is really extremely strange!!! (how can a header file, which is not used in the code, influence the code???).

Looking further into this stm32f4xx.h I finally came nearer to the problem: This includes the core_cm4.h - and the problem is in this file. This further includes the core_cmInstr.h, and again if I comment this out, all works nicely, so the problem is in core_cmInstr.h.

Finally in the core_cmInstr.h the "bad code" is the following:

/** \brief  Reverse byte order (16 bit)

    This function reverses the byte order in two unsigned short values.

    \param [in]    value  Value to reverse
    \return               Reversed value
 */
static __attribute__((section(".rev16_text"))) __inline __asm uint32_t __REV16(uint32_t value)
{
  rev16 r0, r0
  bx lr
}


If I insert this code directly in my main.c (taking out the stm32f4xx.h - I just need the stdint.h for the uing32_t typedef), then again I get the bad code.

Anybody perhaps has an idea:
- why this function disturbs the --bitband so badly?
- what to do to solve this problem? (can I comment out this function in core_cmInstr.h, or any other way to fix this?)

BTW: The code will also work, if I allocate the struct "Bits" manually (e. g. __attribute(at(0x20000100))) ), but that really is nasty ... (further in this case the code is not so optimum as with automatic allocation by "--bitband" - for manual allocation even in opt level 3 the assembly will use one command and one register more).

Parents Reply Children
  • Can you give some information about some typical situations, where the --bitband access would fail?

    I use --bitband in my project now (which is quite large, and meanwhile also C++), and it seems to work nicely (Processor STM32F407).

    I would be happy, if you could tell me which typical situations I should avoid when using --bitband.

  • I am not aware of any other current issues with armcc and bitbanding.

  • In C++ for bitband variables defined inside a class, bitband will ONLY work in static functions, not in class member functions (presumably as in non-static class member functions there always the "this" pointer is present).

    So if you use C++ classes, which occur only once, it is an advantage to use them completely static (all functions + variables static).

    If I want to use bitband in non-static C++ functions, I current use the following workaround, requiring an additional pointer variable to the bitband base variable:

    Required macros:
    typedef int* PBB;
    
    #define BITNR(x) (x&0x1?0:x&0x2?1:x&0x4?2:x&0x8?3: \ 
    x&0x10?4:x&0x20?5:x&0x40?6:x&0x80?7: \ 
    x&0x100?8:x&0x200?9:x&0x400?10:x&0x800?11: \ 
    x&0x1000?12:x&0x2000?13:x&0x4000?14:x&0x8000?15: \ 
    x&0x10000?16:x&0x20000?17:x&0x40000?18:x&0x80000?19: \ 
    x&0x100000?20:x&0x200000?21:x&0x400000?22:x&0x800000?23: \ 
    x&0x1000000?24:x&0x2000000?25:x&0x4000000?26:x&0x8000000?27: \ 
    x&0x10000000?28:x&0x20000000?29:x&0x40000000?30:x&0x80000000?31:32)
    
    #define PBBADR0(Var)       \ 
    ((PBB) ( ( ((uint32_t)&(Var)) & BB_SRAMMASK) | BB_OFFSET | (( ((uint32_t)&(Var)) & (BB_OFFSET-1)) << 5) ) )
    
    #define PBBADR(pbb, BitMask)       \ 
              ((PBB) ( (BYTE*)pbb + (BITNR(BitMask) << 2) ) )
    
    #define MASK_Bit1  0x1
    #define MASK_Bit2  0x2
    #define MASK_Bit3  0x4
    #define MASK_Bit4  0x8
    #define MASK_Bit5  0x10
    #define MASK_Bit6  0x20
    ...
    int iBits;
    PBB pbbBits;
    
    ... during class initialisation ...:
    pbbBits= PBBADR0(iBits);
    
    ... and to work with the bits:
    if( *PBBADR(pbbBits, MASK_Bit1)){
      *PBBADR(pbbBits, MASK_Bit2)= 0;
      *PBBADR(pbbBits, MASK_Bit3)= 1;
    }
    
    

    This creates very efficient code, just it has the drawback that you need this pointer variable, and you should check this pointer variable from time to time in your software, as of course terrible things would happen, if this pointer changes.

  • Sorry, the first statement of my last post is wrong, it should say:

    In C++ for bitband variables defined inside a class, bitband will ONLY work if the bitband struct is defined static (so with fixed global address).

    (It is NOT required that the class functions invoking this bitband access are static - this is very convenient).

    So for "one-time" classes this is a nice way to access to bits.

    For classes with multiple instances, you can proceed as I described in my last post, using the PPBADR macro... .