背景 我正在使用IAR Embedded Workbench IDE和在STM32F091(ARM Cortex-M0内核)微控制器上运行的工具链,使用C语言编写嵌入式应用程序。该应用程序将数据写入微控制器嵌入式闪存,其中只能输入32位字(也许半字也可以工作)。
问题描述 数据存储在uint8_t字节类型数组中,前面是一些头信息(在本例中是来自板载调制解调器的AT响应代码),不应写入闪存。我想发送一个uint32_t指针指向uint8_t缓冲区中实际数据的起始位置。但是如果这个偏移不是4字节对齐,我的应用程序崩溃,因为它试图访问未对齐的uint32_t类型。
这描述了我正在尝试做的事情(不是真正的代码,只是一个例子):
uint8_t modemResponseBuffer[MAX_MODEM_RESPONSE_SIZE];
/* Get the modem response data (including modem response header data) */
size_t modemResponseSize = GetModemResponseData(modemResponseBuffer);
/* Get the actual data size from the header information */
size_t dataSize = GetActualDataSizeFromModemResponseHeader(modemResponseBuffer);
/* Get the offset to where the actual data starts in the modem response */
size_t modemDataOffset = GetModemResponseDataOffset(modemResponseBuffer);
/* Write the data part of the response to embedded flash memory.
The modemDataOffset can be any number which messes up 4 byte data alignment */
ProgramFlashMemory(DATA_FLASH_STORAGE_ADDRESS, (uint32_t*)&modemResponseBuffer[modemDataoffset],
dataSize);
在 ProgramFlashMemory 函数内部,循环调用 FLASH_ProgramWord 标准外设库函数。
问题(S) 如何有效地解决这个问题?我正在研究一个系统,我的内存有限(32 kb RAM),所以我不希望将所需的内容从uint8_t缓冲区复制到uint32_t类型的新缓冲区。目前我通过循环手动对齐数据,但这对我来说似乎相当笨拙。但我还没有提出更好的解决方案,我对我可能会收到的建议感兴趣。
此外,如果有人知道,我也想知道为什么应用程序在这种情况下崩溃。我的核心(或任何核心?)无法处理未对齐数据类型的原因是什么?
答案 0 :(得分:3)
更改ProgramFlashMemory()
以获取void*
,然后在内部将其转换为uint8_t*
,然后您将一次四个字节迭代到unit32_t
,然后您写入闪光灯。
void*
允许写入任何对象的地址而无需显式转换。
类似的东西:
int ProgramFlashMemory( uint32_t* addr, void* data, int length )
{
int byte = 0 ;
int word = 0 ;
while( byte < length )
{
uint32_t flash_word = 0 ;
// Copy four bytes to word
// Note: little-endian byte order assumed,
// reverse for big-endian.
// If end is not aligned, fill with 0xff.
for( b = 0; b < 4; b++ )
{
flash_word |= byte < length ?
(uint8_t*)data[byte] << (b<<3) :
0xFF ;
byte++ ;
}
ProgramFlashWord( addr[word], flash_word ) ;
word++ ;
}
// Return bytes written - may be linger than `length` by up-to
// three for end-alignment.
return byte ;
}
您可能希望保留原始ProgramFlashMemory()
以进行有效的对齐写入,在这种情况下可能ProgramFlashMemoryUnaligned()
。请注意,它不仅仅是对齐,而且长度不一定能被4整除,需要注意。
答案 1 :(得分:1)
这假设在写入有效载荷数据后不再需要标题数据。
要确保缓冲区的对齐方式正确,您可能需要声明它:
uint32_t modemResponseBuffer[(MAX_MODEM_RESPONSE_SIZE * sizeof (uint8_t) / sizeof (uint32_t)) + 1];
在调用writer-function之前,只需将有效负载数据移动到缓冲区的开头:
memmove(modemResponseBuffer, modemResponseBuffer + modemDataoffset, dataSize);
请注意memcpy()
在此处不起作为目的地和来源重叠。
然后像这样打电话给作家:
ProgramFlashMemory(DATA_FLASH_STORAGE_ADDRESS, modemResponseBuffer, dataSize);
答案 2 :(得分:1)
ARM Cortex-M0内核在未对齐访问时崩溃的原因是{{3}}。采用硬故障异常实际上是对某些较旧核心的改进,这些核心将错误地访问该值,然后继续以损坏的值执行。一些较新的ARM内核对未对齐访问的硬件支持有限。
以下是一些建议。
重新设计ProgramFlashMemory()
,使其接受uint8_t*
而不是uint32_t*
。为了对单词进行编程,它应该将缓冲区中的各个字节复制到具有正确对齐的局部变量中。然后将局部变量副本写入flash。
重新设计GetModemResponseData()
,以便在从流中读取标头时解析标头。它将在从流中读取数据之前确定标头的长度和数据的起始点。当流位于数据的开头时,它应该开始将数据复制到一个与标题分开的新缓冲区中并正确对齐。