如何将联合缓冲区与 RAM 地址字节对齐

How to byte-align a union's buffer with RAM address

我目前正在用 C 编写代码并使用来自 NORDIC(32 位 ARM Cortex M0)的 nRF51 MCU。

我想通过无线电发送工会的缓冲区。为此,我必须将联合缓冲区的地址提供给 PACKETPTR。 否则,根据手册参考,"PACKETPTR" 的地址必须是:字节对齐的 RAM 地址。 如果它没有对齐,它会设法取下一个最接近的,但这样接收方将收到不完整的缓冲区和 "dummy" 数据...

如您所料,我的缓冲区不是字节对齐的。这是相关联合体和全局变量。

我的 union 的元素必须打包,以便它们可以容纳 7 个字节;

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;
}

一开始我在typedef union之前添加了__packed限定词。但是就好像 m_adv 是 "packed" 和一些以前的数据一样,因此 buf 地址没有与 ram 地址字节对齐。

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

所以我删除了它,然后buf地址是正确的(即字节与RAM地址对齐)。我以为那是解决方案,但几分钟后它又变得错位了...... 我的问题是: __packed 限定符是否也因为联合而影响 buf ?有没有办法强制对齐全局变量中的 buf 地址?或者有什么建议吗?

谢谢

我不确定您使用的编译器。但是您可以将结构实例的对齐方式与数据类型的打包分开定义。

例如GCC定义了一个属性:_attribute__((aligned(4)))
Visual studio 还有一个方法 __declspec(align(4)).

因此请查看您的编译器手册,了解如何显式定义数据成员的对齐方式。

您的问题似乎是关于 打包,而不是 RAM 地址的 对齐(打包与对齐有关,但对齐本身在你的情况下无关紧要)。

这里的问题是你没有真正打包结构,因为属性放错了地方。应该是:

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;

b 之后插入了一个额外的字节,以在 16 位边界上对齐以下 uint16_t

请注意,如果您不需要访问单个字节,则无需创建联合。您可以只使用结构并传递结构的地址。

感谢您的回答。

我的结构成员完全符合我的要求 buf(没有填充,MSB/LSB 按我的预期放置等),我并不是说我想访问特定的位域成员.

我不够详细,但问题出在接收器上。

我收到了前任。 0xEF 0x00 0xFC 0xB2 0x38 0x00 0xB6 而不是 0xCD 0xAB 0xEF 0x00 0xFC 0xB2 0x38buf 内容)。

所以我认为问题是关于 buf 地址和关于 "RAM address" 的手册语句 PACKETPTR 我误解了它..问题实际上来自帧处理我的接收器...抱歉!!