You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

排查建议

  1. 直接查看数组内存布局

    • 在调试器中查看safetysettings数组的起始地址,以及每个元素(指针)的实际值,对比ssettings的内存布局,确认是否真的存在地址不连续、起始指向错误的情况。
    • 检查safetysettings关联的全局变量(scen、ldcos等)的内存地址,确认这些变量是否被错误放置(比如进入了特殊内存区域)。
  2. 检查链接脚本与内存分配

    • 查看项目的链接脚本(.ld文件),确认全局变量和数组的内存分配规则,是否存在safetysettings被分配到非连续内存段的情况,或者零初始化变量被放到了特殊的ZI段导致异常。
    • 对比ssettings和safetysettings的内存分配区域,看是否有差异。
  3. 修正函数参数传递的逻辑错误

    • 当前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);
      }
      
  4. 检查零初始化变量的内存特性

    • 全局零初始化变量会被放入ZI段,而非已初始化的RW段,检查ZI段是否有特殊访问限制,或者SPI读写函数对ZI段地址的处理存在兼容性问题。
    • 临时将scen、ldcos改为非零初始值,验证是否还会出现写入错误,确认问题是否与零初始化段相关。
  5. 调试SPI读写的实际操作

    • 在holt_6135_write_SA_data_array中,查看addr+2+offset+i的实际地址值,以及*(data+i)的内容,确认写入的地址和数据是否符合预期。
    • 对比safetysettings和ssettings在写入时的地址与数据差异,定位具体异常点。

内容的提问来源于stack exchange,提问作者mzap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 09:45:02