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

__attribute__((bitband)) address miscalculation?

Hello,

I'm using Keil MDK 3.80a on STM32 and trying to use the bitband attribute to access individual bits in a 32bit register.


typedef struct {
    uint32_t a0: 1;
    uint32_t b0: 1;
    uint32_t c0: 1;
    uint32_t d0: 1;
    uint32_t e0: 1;
    uint32_t f0: 1;
    uint32_t g0: 1;
    uint32_t h0: 1; //8bit

    uint32_t a1: 1;
    uint32_t b1: 1;
    uint32_t c1: 1;
    uint32_t d1: 1;
    uint32_t e1: 1;
    uint32_t f1: 1;
    uint32_t g1: 1;
    uint32_t h1: 1; //8bit

    uint32_t a2: 1;
    uint32_t b2: 1;
    uint32_t c2: 1;
    uint32_t d2: 1;
    uint32_t e2: 1;
    uint32_t f2: 1;
    uint32_t g2: 1;
    uint32_t h2: 1; //8bit

    uint32_t a3: 1;
    uint32_t b3: 1;
    uint32_t c3: 1;
    uint32_t d3: 1;
    uint32_t e3: 1;
    uint32_t f3: 1;
    uint32_t g3: 1;
    uint32_t h3: 1; //8bit

} BB __attribute__((bitband));

BB bb __attribute__((at(0x40010800)));

(0x40010800 is the STM32 GPIOA.CRL register)

When in main I set

bb.a0=1;


which should be bit 0, it compiles to

0x080001BE 4B23      LDR      r3,[pc,#140]  ; @0x0800024C
0x080001C0 F8C30800  STR      r0,[r3,#0x800]

which is off by 0x1C from the correct bitbanding address (which should be 0x42210000) , so instead of setting bit0, it sets bit 7 in GPIOA.CRL

Is my definition of the bitfield wrong or where is the error?

Thank You!

B. Schmidt

Parents
  • Hello,

    the problem is solved.

    I spoke to Keil Tech support and the problem was that I had two structures pointing to the same address using the at attribute.

    One struct for 32bit access and the second using a bitfield and bitbanding to read and write the STM32 registers.

    I should have been given a linker error because these overlapping regions are not supported, but it compiled and linked free of errors and warnings.

    Access using the structure which was later defined always had a wrong address.
    My advice at the moment is not to use the bitband attribute, it is pretty restricted and not worth the hassle in my opionion

    Regards

    Benjamin

Reply
  • Hello,

    the problem is solved.

    I spoke to Keil Tech support and the problem was that I had two structures pointing to the same address using the at attribute.

    One struct for 32bit access and the second using a bitfield and bitbanding to read and write the STM32 registers.

    I should have been given a linker error because these overlapping regions are not supported, but it compiled and linked free of errors and warnings.

    Access using the structure which was later defined always had a wrong address.
    My advice at the moment is not to use the bitband attribute, it is pretty restricted and not worth the hassle in my opionion

    Regards

    Benjamin

Children
  • As long as you have volatile-declared your variables, you should be able to have a pointer to the "raw" address of the register, allowing you to do direct 16-bit or 32-bit updates. This will not affect the linkers ability to place variables at absolute addresses.

    Another alternative is to manuall set an unsigned variable "at" the register address, and a struct/array of 32-bit unsigned integers "at" the alias address for bit-addressing. Remember that the bit-banding does its magic by having the bitbanded variables aliased to two different addresses. The bitband attribute is a bit of black magic added by the compiler to try and automagically hide this aliasing.

  • "One struct for 32bit access and the second using a bitfield and bitbanding"

    So would a union have fixed this?

  • A union would allow a direct write to the full register width, or and/or operations on individual bits.

    But it wouldn't have allowed the more optimized accesses from making a 32-bit write to an aliased address to set or clear a single bit. In this case, the processor has a 128 byte array of 32 32-bit integers mapping that are aliased to a single 32-bit address in either device space or a limited range of the normal RAM. Making one 32-bit write takes less code than having to read a 32-bit address, and then set or clear a bit before writing back the result. The hardware still has to perform a read/modify/write, but you will not waste instructions for it.

    This optimization is only possible for single-bit updates. Any multi-bit updates will require either multiple single-bit updates in the bitband-aliased address range, or a normal and/or performed on the unaliased address.