如何 convert/align 我的 uint8_t 指针缓冲区指向 uint32 以使其与自动生成的 HAL 函数一起工作
How to convert/align my uint8_t pointer buffer to uint32 for it to work with auto-generated HAL functions
在我自动生成的用于实现 CRC 的 HAL 代码中,我有以下功能:
uint32_t HAL_CRC_Accumulate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
{
uint32_t index; /* CRC input data buffer index */
uint32_t temp = 0U; /* CRC output (read from hcrc->Instance->DR register) */
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_BUSY;
switch (hcrc->InputDataFormat)
{
case CRC_INPUTDATA_FORMAT_WORDS:
/* Enter Data to the CRC calculator */
for (index = 0U; index < BufferLength; index++)
{
hcrc->Instance->DR = pBuffer[index];
}
temp = hcrc->Instance->DR;
break;
case CRC_INPUTDATA_FORMAT_BYTES:
temp = CRC_Handle_8(hcrc, (uint8_t *)pBuffer, BufferLength);
break;
case CRC_INPUTDATA_FORMAT_HALFWORDS:
temp = CRC_Handle_16(hcrc, (uint16_t *)(void *)pBuffer, BufferLength); /* Derogation MisraC2012 R.11.5 */
break;
default:
break;
}
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_READY;
/* Return the CRC computed value */
return temp;
}
问题是我自己的 inBuff 是 uint8_t * inBuff
类型的,我可以在自动生成的代码中看到它需要一个 uint32_t 作为输入,然后再将其类型转换为uint8_t 因为我为我的 CRC 使用了 CRC_INPUTDATA_FORMAT_BYTES 选项。需要我的 uint8_t buff 的原因是让它与我的其余代码(相当大的项目)一起工作。有什么理由可以在不损坏我自己的 inBuff 内容的情况下以有效的方式解决这个问题?它需要正确对齐。
How to convert/align my uint8_t pointer buffer to uint32 for it to work with auto-generated HAL functions
什么都不做。
The problem is that my own inBuff is of type uint8_t * inBuff and I can see in the auto-generated code that it needs a uint32_t as input
所以投指针。
HAL_CRC_Accumulate(..., (uint32_t*)your_buffer, ...)
Is there any reason to work around this in an efficient way without damaging my own inBuff content?
没有。 (?)
是的,令人不快的是它不使用 void*
指针,或者每个 INPUTDATA_FORMAT 不只是单独的 API。不过,您无需执行任何操作,只需传递指针值 - 内部例程无论如何都会通过 uint8_t*
正确的句柄访问它们。
INPUTDATA_FORMAT_BYTES 所需的对齐方式为 1,在字节边界处。
- 将您的缓冲区分配到所需的大小加上
sizeof(uint32_t) - 1
。
例如,如果你的缓冲区静态分配给SIZE
,那么你可以这样做:
uint8_t buff[SIZE + sizeof(uint32_t) - 1];
- 将指针指向缓冲区中的最低地址,该地址与
uint32_t
: 对齐
size_t addr = (size_t)buff + sizeof(uint32_t) - 1;
uint8_t* inBuff = (uint8_t*)(addr / sizeof(uint32_t) * sizeof(uint32_t));
问题:
- 不打算通过 pointed-at 类型访问指针参数的函数不应使用该类型声明。如果
HAL_CRC_Accumulate
从未打算将 pBuffer
作为 uint32_t
的(数组)访问,那么它不应该使用该类型。然后它应该被声明为 uint8_t*
.
- 将指向数组第一项的
uint8_t*
传递给接受 uint32_t*
的函数是非常危险的代码,确实可能导致错位问题。你的大部分问题归结为:为什么这个函数使用uint32_t[]?这没有任何意义。
- 将
uint32*
转换为 uint16_t*
同样是不好的做法和未定义的行为,以防传递此 uint16_t*
的函数将访问该参数作为 uint16_t
.不仅因为可能的错位,还因为严格的别名。同样,如果该函数无意使用 uint16_t*
访问 uint16_t
对象,那么它不应该使用该指针类型。同样,整个代码似乎应该适用于 uint8_t*
类型。
- 像这样“链接”多个转换
(uint16_t *)(void *)
是无稽之谈。 void*
没有增加任何东西,也没有解决任何问题。
- 通常情况下,计算 CRC 的函数将在
const
合格缓冲区上运行,因为它不应该更改任何内容。如果 so-called“FCS”(计算的校验和)应该附加在数据缓冲区的末尾,那么最好单独进行设计。
- 因为在评论中提到了 MISRA-C:以上所有内容在 mission-critical 代码库中都是特别不可接受的。 Auto-generated 代码不是草率的、可能会破坏类型使用的借口——恰恰相反。比咨询规则 11.5 更重要的是,您多次违反了(必需)MISRA-C:2012 规则 11.3,并且 none 符合 MISRA 标准。
STMCubeMX 不会生成最好的代码,您已经找到了一个很好的例子。
首先,他们 (ST) 确实希望您传入一个 uint32_t 缓冲区,因为他们希望数据在 32 位边界上对齐。看到这一行:
hcrc->Instance->DR = pBuffer[index];
他们期望读取一个 uint32_t 值并将其写入 32 位 DR 寄存器。未对齐的指针会在那里导致错误。
如果缓冲区实际上未在 32 位边界上对齐,则您尝试将 uint8_t 缓冲区转换为 uint32_t 可能会出现问题。你可以这样排列你的:
uint8_t mybuf[128] __attribute__((aligned(4)));
您仍然需要将指针转换为 uint32_t* 以将其传递给 HAL_CRC_Accumulate,这样编译器就不会报错,但它会工作,因为它确实对齐了!
我强烈建议您不要修改 CubeMX 生成的代码。除非您的代码添加到 ST 代码的特殊 /* USER */ 部分,否则每次重新生成项目时它都会丢失。这会一遍又一遍地咬你的屁股。
在我自动生成的用于实现 CRC 的 HAL 代码中,我有以下功能:
uint32_t HAL_CRC_Accumulate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
{
uint32_t index; /* CRC input data buffer index */
uint32_t temp = 0U; /* CRC output (read from hcrc->Instance->DR register) */
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_BUSY;
switch (hcrc->InputDataFormat)
{
case CRC_INPUTDATA_FORMAT_WORDS:
/* Enter Data to the CRC calculator */
for (index = 0U; index < BufferLength; index++)
{
hcrc->Instance->DR = pBuffer[index];
}
temp = hcrc->Instance->DR;
break;
case CRC_INPUTDATA_FORMAT_BYTES:
temp = CRC_Handle_8(hcrc, (uint8_t *)pBuffer, BufferLength);
break;
case CRC_INPUTDATA_FORMAT_HALFWORDS:
temp = CRC_Handle_16(hcrc, (uint16_t *)(void *)pBuffer, BufferLength); /* Derogation MisraC2012 R.11.5 */
break;
default:
break;
}
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_READY;
/* Return the CRC computed value */
return temp;
}
问题是我自己的 inBuff 是 uint8_t * inBuff
类型的,我可以在自动生成的代码中看到它需要一个 uint32_t 作为输入,然后再将其类型转换为uint8_t 因为我为我的 CRC 使用了 CRC_INPUTDATA_FORMAT_BYTES 选项。需要我的 uint8_t buff 的原因是让它与我的其余代码(相当大的项目)一起工作。有什么理由可以在不损坏我自己的 inBuff 内容的情况下以有效的方式解决这个问题?它需要正确对齐。
How to convert/align my uint8_t pointer buffer to uint32 for it to work with auto-generated HAL functions
什么都不做。
The problem is that my own inBuff is of type uint8_t * inBuff and I can see in the auto-generated code that it needs a uint32_t as input
所以投指针。
HAL_CRC_Accumulate(..., (uint32_t*)your_buffer, ...)
Is there any reason to work around this in an efficient way without damaging my own inBuff content?
没有。 (?)
是的,令人不快的是它不使用 void*
指针,或者每个 INPUTDATA_FORMAT 不只是单独的 API。不过,您无需执行任何操作,只需传递指针值 - 内部例程无论如何都会通过 uint8_t*
正确的句柄访问它们。
INPUTDATA_FORMAT_BYTES 所需的对齐方式为 1,在字节边界处。
- 将您的缓冲区分配到所需的大小加上
sizeof(uint32_t) - 1
。
例如,如果你的缓冲区静态分配给SIZE
,那么你可以这样做:
uint8_t buff[SIZE + sizeof(uint32_t) - 1];
- 将指针指向缓冲区中的最低地址,该地址与
uint32_t
: 对齐
size_t addr = (size_t)buff + sizeof(uint32_t) - 1;
uint8_t* inBuff = (uint8_t*)(addr / sizeof(uint32_t) * sizeof(uint32_t));
问题:
- 不打算通过 pointed-at 类型访问指针参数的函数不应使用该类型声明。如果
HAL_CRC_Accumulate
从未打算将pBuffer
作为uint32_t
的(数组)访问,那么它不应该使用该类型。然后它应该被声明为uint8_t*
. - 将指向数组第一项的
uint8_t*
传递给接受uint32_t*
的函数是非常危险的代码,确实可能导致错位问题。你的大部分问题归结为:为什么这个函数使用uint32_t[]?这没有任何意义。 - 将
uint32*
转换为uint16_t*
同样是不好的做法和未定义的行为,以防传递此uint16_t*
的函数将访问该参数作为uint16_t
.不仅因为可能的错位,还因为严格的别名。同样,如果该函数无意使用uint16_t*
访问uint16_t
对象,那么它不应该使用该指针类型。同样,整个代码似乎应该适用于uint8_t*
类型。 - 像这样“链接”多个转换
(uint16_t *)(void *)
是无稽之谈。void*
没有增加任何东西,也没有解决任何问题。 - 通常情况下,计算 CRC 的函数将在
const
合格缓冲区上运行,因为它不应该更改任何内容。如果 so-called“FCS”(计算的校验和)应该附加在数据缓冲区的末尾,那么最好单独进行设计。 - 因为在评论中提到了 MISRA-C:以上所有内容在 mission-critical 代码库中都是特别不可接受的。 Auto-generated 代码不是草率的、可能会破坏类型使用的借口——恰恰相反。比咨询规则 11.5 更重要的是,您多次违反了(必需)MISRA-C:2012 规则 11.3,并且 none 符合 MISRA 标准。
STMCubeMX 不会生成最好的代码,您已经找到了一个很好的例子。
首先,他们 (ST) 确实希望您传入一个 uint32_t 缓冲区,因为他们希望数据在 32 位边界上对齐。看到这一行:
hcrc->Instance->DR = pBuffer[index];
他们期望读取一个 uint32_t 值并将其写入 32 位 DR 寄存器。未对齐的指针会在那里导致错误。
如果缓冲区实际上未在 32 位边界上对齐,则您尝试将 uint8_t 缓冲区转换为 uint32_t 可能会出现问题。你可以这样排列你的:
uint8_t mybuf[128] __attribute__((aligned(4)));
您仍然需要将指针转换为 uint32_t* 以将其传递给 HAL_CRC_Accumulate,这样编译器就不会报错,但它会工作,因为它确实对齐了!
我强烈建议您不要修改 CubeMX 生成的代码。除非您的代码添加到 ST 代码的特殊 /* USER */ 部分,否则每次重新生成项目时它都会丢失。这会一遍又一遍地咬你的屁股。