ARM MCU固件开发:uint16_t指针数组地址异常排查求助
全局指针数组地址异常与读写错误排查求助
我在基于Eclipse的S32 Design Studio开发ARM MCU固件时,遇到全局uint16_t指针数组safetysettings的异常问题:
- 读取数组最后两个元素结果不符合预期
- 数组元素地址非连续
- 数组起始地址似乎指向末尾而非首元素
另一结构完全类似的数组ssettings工作正常,已确认编译器优化设置为None。
相关定义代码
uint16_t vshut = 2000; uint16_t vrec = 2400; uint16_t durams = 3000; uint16_t otshut = 1100; uint16_t scen = 0; uint16_t ldcos = 0; uint16_t * safetysettings[6] = {&vshut, &vrec, &durams, &otshut, &scen, &ldcos}; uint16_t tax1 = 2000; uint16_t tax2 = 2400; uint16_t tax3 = 3000; uint16_t tax4 = 1100; uint16_t tax5 = 0x0007; uint16_t tax6 = 0x0009; uint16_t * ssettings[6] = {&tax1, &tax2, &tax3, &tax4, &tax5, &tax6};
读写逻辑补充
代码通过update_databus_safetysettings和read_databus_safetysettings对数组进行读写,发现当全局变量初始化为0时,Write_6131_1word写入数据错误;初始化为非零则正常。读写函数实现如下:
update_databus_safetysettings(safetysettings); void update_databus_safetysettings(uint16_t * settings[]){ holt_6135_write_SA_data_array(RT1_CtrlWord_TxSA12 + 1, settings[0], 6, 0); } void holt_6135_write_SA_data_array(uint16_t desc1word, uint16_t * data, uint8_t count, uint8_t offset){ enaMAP(1); Write_6131LowReg(MAP_1,desc1word); // address=0x04C9; contents=0x0628; uint16_t addr = Read_6131_1word(); for(uint8_t i = 0; i<count; i++){ Write_6131LowReg(MAP_1,addr+2+offset+i); // first word is msg info, second is time tag, and third is the first data word. Write_6131_1word(*(data+i)); } } read_databus_safetysettings(safetysettings); void read_databus_safetysettings(uint16_t * settings[]){ holt_6135_readmem_nwords(RT1_CtrlWord_RxSA11+1, settings, 5); // note that during Rx11 only first 5 datawords are used, even though the pointer array has 6 elements. } void holt_6135_readmem_nwords(uint16_t addr, uint16_t * datawords[], uint8_t count){ uint16_t data; enaMAP(3); Write_6131LowReg(MAP_3,addr); data = Read_6131_1word(); // Write_6131LowReg(MAP_3,data); for(uint8_t i = 0; i < count; i++){ Write_6131LowReg(MAP_3,data+2+i); *(datawords[i]) = Read_6131_1word(); } }
整体功能为通过SPI总线与串行通信IC进行数据读写。
测试程序
我编写了测试程序验证预期逻辑,运行正常:
#include <stdio.h> #include <stdint.h> #include <stdbool.h> void read_vals(uint16_t ** settings){ for(int ind = 0; ind < 6; ind++){ *settings[ind] = 2*ind; } } void print_vals(uint16_t ** settings){ for(int ind = 0; ind < 6; ind++){ printf("settings[%d]: %d\n",ind, *settings[ind]); } } uint16_t vshut = 2000; uint16_t vrec = 2400; uint16_t durams = 3000; uint16_t otshut = 1100; uint16_t scen = 0; uint16_t ldcos = 0; uint16_t * safetysettings[6] = {&vshut, &vrec, &durams, &otshut, &scen, &ldcos}; uint16_t ** ssptr = &safetysettings[0]; int main() { // print_vals(&safetysettings[0]); // read_vals(&safetysettings[0]); // print_vals(&safetysettings[0]); print_vals(ssptr); read_vals(ssptr); print_vals(ssptr); return 0; }
排查建议
直接查看数组内存布局
- 在调试器中查看
safetysettings数组的起始地址,以及每个元素(指针)的实际值,对比ssettings的内存布局,确认是否真的存在地址不连续、起始指向错误的情况。 - 检查
safetysettings关联的全局变量(scen、ldcos等)的内存地址,确认这些变量是否被错误放置(比如进入了特殊内存区域)。
- 在调试器中查看
检查链接脚本与内存分配
- 查看项目的链接脚本(
.ld文件),确认全局变量和数组的内存分配规则,是否存在safetysettings被分配到非连续内存段的情况,或者零初始化变量被放到了特殊的ZI段导致异常。 - 对比
ssettings和safetysettings的内存分配区域,看是否有差异。
- 查看项目的链接脚本(
修正函数参数传递的逻辑错误
- 当前
update_databus_safetysettings函数将settings[0](指向单个uint16_t的指针)传入holt_6135_write_SA_data_array,后者将其当作连续的uint16_t数组指针处理,这是核心错误:safetysettings是指针数组,每个元素是独立的变量地址,这些变量在内存中不一定连续,data+i会访问vshut之后的未知内存,而非下一个指针指向的变量。ssettings工作正常只是巧合:其关联的全局变量刚好在内存中连续排列,初始非零值掩盖了错误。
- 修正方法:先将指针数组指向的值拷贝到连续缓冲区,再传入SPI写入函数:
void update_databus_safetysettings(uint16_t * settings[]){ uint16_t temp_buf[6]; for(int i=0; i<6; i++){ temp_buf[i] = *(settings[i]); } holt_6135_write_SA_data_array(RT1_CtrlWord_TxSA12 + 1, temp_buf, 6, 0); }
- 当前
检查零初始化变量的内存特性
- 全局零初始化变量会被放入ZI段,而非已初始化的RW段,检查ZI段是否有特殊访问限制,或者SPI读写函数对ZI段地址的处理存在兼容性问题。
- 临时将
scen、ldcos改为非零初始值,验证是否还会出现写入错误,确认问题是否与零初始化段相关。
调试SPI读写的实际操作
- 在
holt_6135_write_SA_data_array中,查看addr+2+offset+i的实际地址值,以及*(data+i)的内容,确认写入的地址和数据是否符合预期。 - 对比
safetysettings和ssettings在写入时的地址与数据差异,定位具体异常点。
- 在
内容的提问来源于stack exchange,提问作者mzap
相关产品推荐
相关产品推荐

