1

I am currently coding in C and using nRF51 MCU from NORDIC (32-bit ARM Cortex M0).

I would like to send an union's buffer by radio. For this purpose I have to give the address of the union's buffer to PACKETPTR. Otherwise the address given to "PACKETPTR" has to be, according to the manuel reference: a byte aligned RAM address. If it isn't aligned, it manages to take the next closest one but in this way the receiver will receive incomplete buffer and "dummy" data...

As you can guess, my buffer isn't byte aligned. Here is the concerned union and the global variable.

My union's elements have to be packed so that they can fit in 7 bytes;

typedef union
{   
    uint8_t buf[7];  //The buffer I give to PACKETPTR
    __packed struct 
    {
        uint8_t             a[2];
        uint8_t             b;
        uint16_t            c : 10;
        uint16_t            d : 6;  
        uint16_t            e : 14;
        uint16_t            f : 2;
    }parts;
}adv_t;

adv_t m_adv; //The global variable

...

//Later in the code to set PACKETPTR

config_tx(ADV_PIPE, m_adv.buf);

...

void __INLINE config_tx(uint8_t tx_pipe, uint8_t* payload)
{
   NRF_RADIO->TXADDRESS = tx_pipe;
   NRF_RADIO->PACKETPTR = (uint32_t)payload;
}

At the beginning I added __packed qualifier before typedef union. But it was as if m_adv was "packed" with some previous data, hence buf address wasn't byte aligned with ram address.

__packed typedef union /* Previous definition */
{   
    uint8_t buf[7];
    __packed struct 
    {
        ...
    }parts;
}adv_t; 

So I removed it, and then buf address was correct (ie. byte aligned with RAM address). I thought that was the solution, but few minutes later it became mis-aligned again... My questions are: Does the __packed qualifier affects also buf because of the union? is there a way to force buf address from my global variable to be aligned? Or any suggestion?

Thanks

TRandom
  • 11
  • 3
  • What happens if you include a `long unused` member in the union? – 2501 Jan 20 '16 at 11:13
  • What are you talking about ? A RAM address is always byte-aligned, by definition. You can't have a fractional address. When you say "mis-aligned", do you mean to say "not packed correctly" ? It looks like your whole question is about packing, and not alignment, but as it is now your question is non-sense and hard to understand. – ElderBug Jan 20 '16 at 11:27
  • When a documentation says "byte-aligned address", it just means "Doesn't need any alignment, any address will do.". – ElderBug Jan 20 '16 at 11:31
  • @ElderBug A ram-address would be, but e.g. madv.parts.d is not (since it is part of a bitfield). It would be thinkable, that in a packed `struct { char a:2; char b; };` b isn't byte-aligned either, because a:2 doesn't end on a byte-boundary. But this isn't the case, b would be byte-aligned here, too – Ctx Jan 20 '16 at 11:38
  • @Ctx Of course bitfield members can be not aligned on byte boundaries, but my point is not about that. There is no such thing as an address not aligned on bytes. You can't take the address of a bitfield member (try it). OP misunderstood this documentation sentence and thought it was the problem, when it really is about packing. – ElderBug Jan 20 '16 at 11:43
  • Make sure to add something like `_Static_assert(sizeof(m_adv.buf) == sizeof(m_adv.parts); "Error: padding detected");` – Lundin Jan 20 '16 at 11:53
  • *Byte* aligned? That seems strange to say unless it includes a specific number of bytes of alignment... – David Hoelzer Jan 20 '16 at 11:58
  • I hope you're not expecting your bit fields to map to specific bytes of your `buf` member. That is extremely implementation-dependent. – Andrew Henle Jan 20 '16 at 12:49

3 Answers3

1

Your problem seems to be about packing, and not the alignment of the RAM address (packing plays with alignment, but alignment itself doesn't matter in your case).

The problem here is that you don't really pack the struct because the attribute is misplaced. It should be :

typedef union
{   
    uint8_t buf[7];
    struct // not here
    {
        uint8_t             a[2];
        uint8_t             b;
        uint16_t            c : 10;
        uint16_t            d : 6;  
        uint16_t            e : 14;
        uint16_t            f : 2;
    } __packed parts; // here, __packed or __attribute__((packed))

}adv_t;

There was an additional byte inserted after b to align the following uint16_t on 16-bit boundaries.

Note that you don't need to make a union if you don't need to access individual bytes. You can just use the struct and pass the address of the struct.

ElderBug
  • 5,926
  • 16
  • 25
0

I am not sure about the compiler you use. But you may define alignment of your structures instance separately from the packing of the datatype.

GCC for example defines an attributes: _attribute__((aligned(4)))
Visual studio has another method __declspec(align(4)).

So look at your compilers manual on how to explicitly define alignment of a data member.

vlad_tepesch
  • 6,681
  • 1
  • 38
  • 80
0

Thank you for your answers.

My struct members fit perfectly in buf as I wanted (no padding, MSB/LSB placed as I expected etc.), and I didn't mean I want to access to particular bitfield members.

I didn't detail enough, but the problem went from the receiver.

I received for ex. 0xEF 0x00 0xFC 0xB2 0x38 0x00 0xB6 instead of 0xCD 0xAB 0xEF 0x00 0xFC 0xB2 0x38 (bufcontent).

So I thought the problem was about buf address and the Manual sentence talking about "RAM address" for PACKETPTR I misunderstood it.. The problem was effectively coming from the frame processing of my receiver... sorry!!

TRandom
  • 11
  • 3