如何将联合缓冲区与 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 0x38
(buf
内容)。
所以我认为问题是关于 buf
地址和关于 "RAM address" 的手册语句 PACKETPTR
我误解了它..问题实际上来自帧处理我的接收器...抱歉!!
我目前正在用 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 0x38
(buf
内容)。
所以我认为问题是关于 buf
地址和关于 "RAM address" 的手册语句 PACKETPTR
我误解了它..问题实际上来自帧处理我的接收器...抱歉!!