C 将函数分离到不同文件时数据损坏

C 将函数分离到不同文件时数据损坏,c,corruption,bare-metal,lpc,C,Corruption,Bare Metal,Lpc,这个问题使我烦恼。我正在用C语言为基于LPC15XX系列微控制器的定制传感器板进行裸机编程。该平台相当于一组I2C传感器和一个连接到其中一个UART的蓝牙发射器。这不是LPCxpresso(或类似)板之一;它是定制设计的 直到今天,所有的测试代码都在一个单片文件中,一切都按预期工作。随着代码的增长,我决定将主要功能部分分解为单独的源文件,以便于管理。不幸的是,我一这么做,程序就开始出错了 正在移动的代码是原始单片文件的复制+粘贴。我已经通过社会福利署的链接使用了GDB。看来,我的一个用于命中内部

这个问题使我烦恼。我正在用C语言为基于LPC15XX系列微控制器的定制传感器板进行裸机编程。该平台相当于一组I2C传感器和一个连接到其中一个UART的蓝牙发射器。这不是LPCxpresso(或类似)板之一;它是定制设计的

直到今天,所有的测试代码都在一个单片文件中,一切都按预期工作。随着代码的增长,我决定将主要功能部分分解为单独的源文件,以便于管理。不幸的是,我一这么做,程序就开始出错了

正在移动的代码是原始单片文件的复制+粘贴。我已经通过社会福利署的链接使用了GDB。看来,我的一个用于命中内部ROM驱动程序的静态变量正在被置零。稍后取消对此的引用将导致故障

在静态变量上设置一个watch,我可以看到在I2C初始化例程中有一行代码将其放大。问题在于init是使用NXP提供的ROM驱动程序例程完成的。此外,当这些代码都在同一个文件中时,它们就可以正常工作了

问题

  • 什么会像那样破坏文件级静态变量?据我所知,变量不应该在堆栈上,因此我看不到导致此问题的缓冲区溢出

  • 为什么在文件之间移动代码会暴露这一点?它不应该被编译并链接到一个名称空间吗

回复评论中的问题

  • uart\u实例
    usart.c
    中定义一次,并且仅在调用
    uart\u设置时直接(按名称)写入一次

  • 同样地,
    i2c\u实例
    main.c
    中定义(我还没有移动i2c函数)。是静态的,声明与uart\U实例相同。我已经更新了下面的代码,以包含这两个文件中的所有静态变量

  • 在调用
    pI2CApi->i2c\u set\u比特率(hI2C,基本时钟,i2c\u波特)时,指针实际上为空,通过在相关内存上设置手表确定

  • 我不能直接跟踪任何ROM驱动程序例程。它们由uC提供,并通过固定内存地址处提供的双指针进行访问。我已经检查了这些指针对象(
    hUart
    pUartApi
    ),它们保留了正确的值;只有
    uart\u实例
    被关闭

  • 我为这个应用程序创建并转储了地图文件;它不包含对
    uart\u实例
    (或任何静态变量)的引用。奇怪。我可以根据要求发布全部内容(有点长)

代码呕吐

一句警告的话,这段代码是非常典型和未优化的。很好,其中大部分都是无耻地从数据表上抄下来的

静态变量的定义(usart.c)

静态变量的定义(main.c)

静态句柄的初始化(usart.c)

int setupUSART0(int系统时钟,int波特率){
UART\u CONFIG\u T CONFIG;
uint32\u t frg\u val=0;
uint32大小单位为字节;
//启用USART0时钟
LPC_SYSCON->SYSAHBCLKCTRL1 |=((1UL UARTCLKDIV=(uint8)USART_PERIPH_PRESCALE);
//配置USART0引脚
LPC_SWM->PINASSIGN0=0;
LPC|u SWM->PINSassign0|=((uint8|t)18)PINSassign0|=((uint8|t)13)PINSassign0|=((uint8|t)0xFF)PINSassign0|=((uint8|t)0xFF)uart获取内存大小();
if(10<(大小单位为字节/4))返回-1;
hUart=pUartApi->uart_设置(LPC_USART0_基础,(uint8_t*)和uart_实例);//uart_初始化(hUart,&配置)FRGCTRL=frg_val;
//在NVIC中启用USART0
NVIC->ISER0 |=((1UL INTENSET |=((1UL SYSAHBCLKCTRL1 |=((1UL DIV=0x0078;//120十进制)
LPC_I2C0->MSTTIME=0x00;//SCL高/低=每个时钟2个
//调试
LPC_SWM->PINENABLE1=0x00;
//启用中断
NVIC->ISER0 |=((1UL INTENSET |=((1UL INTENSET |=((1UL i2c|U设置(LPC|U I2C0|U基础,(uint32|t*)和i2c|U实例);
//这会以某种方式使uart_实例为空
//设置比特率
err=pI2CApi->i2c\u设置\u比特率(hI2C,基本时钟,i2c\u波特率);
//设置主模式

LPC_I2C0->CFG=((1UL我认为上面的代码没有任何错误

通常,通过将代码拆分为多个文件而意外引入的错误是静态变量的重复。例如,main.c和usart.c中都可能存在
static UART\u HANDLE\u T UART\u实例;
(甚至在这两个文件所包含的某些.h中都存在).一切都将编译并链接正常,但是main.c和usart.c中的函数将使用不相关的变量,并且程序逻辑将随着数据损坏的可能性而改变


现在,这是一个与您的代码没有直接关系的通用注释。它可能会有帮助…祝您好运找到bug!

您能转储
i2c\u set\u比特率的程序集吗?
i2c\u设置中可能有什么东西设置了segfault?i2c\u实例是静态的吗?您在中使用
uart\u实例吗其他带有
extern
声明的文件?我做的另一件事是查看链接器映射文件-查看附近的变量..除了@Abhi编写的内容外,还有哪一行setupI2C()为空?我想可能是对i2c_setup()的调用。设置变量i2c_实例。如果此变量声明不正确,它可能会覆盖相邻的全局内存,从而影响uart_实例。如果链接器没有吐出静态变量,请删除静态声明。因为您在别处的注释表明没有其他
uart_实例
。某些链接器具有指令su如“
--mapfile\u contents=sym\u defs
”,可以查看其中的静态变量
static UARTD_API_T* pUartApi;           // USART API function addr table
static UART_HANDLE_T  uart_instance;    // Raw storage for USART API
static UART_HANDLE_T* hUart;            // Handle to USART API
static I2CD_API_T* pI2CApi;             // I2C API function addr table
static I2C_HANDLE_T  i2c_instance;      // Raw storage for I2C API
static I2C_HANDLE_T* hI2C;              // Handle to I2C API
int setupUSART0(int sys_clock, int baud) {

    UART_CONFIG_T config;
    uint32_t frg_val = 0;
    uint32_t size_in_bytes;

    // Enable USART0 clock
    LPC_SYSCON->SYSAHBCLKCTRL1 |= ((1UL << 17));

    // Configure USART clock divider
    LPC_SYSCON->UARTCLKDIV = (uint8_t)USART_PERIPH_PRESCALE;

    // Configure USART0 pins
    LPC_SWM->PINASSIGN0 = 0;
    LPC_SWM->PINASSIGN0 |= ((uint8_t)18) << 0;     // PIO0_18, tx
    LPC_SWM->PINASSIGN0 |= ((uint8_t)13) << 8;     // PIO0_13, rx
    LPC_SWM->PINASSIGN0 |= ((uint8_t)0xFF) << 16;  // Not wired, rts
    LPC_SWM->PINASSIGN0 |= ((uint8_t)0xFF) << 24;  // Not wired, cts

    // Get handle to USART API
    pUartApi = getUartDriver();

    // Initialize memory for UART API
    size_in_bytes = pUartApi->uart_get_mem_size();
    if (10 < (size_in_bytes / 4)) return -1;
    hUart = pUartApi->uart_setup(LPC_USART0_BASE, (uint8_t*)&uart_instance);    // <- uart_instance initialized here

    // Initialize USART API
    config.sys_clk_in_hz = sys_clock / USART_PERIPH_PRESCALE;
    config.baudrate_in_hz = baud;
    config.config = 1;              // 8N1
    config.sync_mod = 0;
    config.error_en = 0;
    frg_val = (pUartApi->uart_init(hUart, &config) << 8) | 0xFF;

    // Configure USART fractional divider
    if (!frg_val) return -1;
    LPC_SYSCON->FRGCTRL     = frg_val;

    // Enable USART0 in NVIC
    NVIC->ISER0 |= ((1UL << 21));

    // Enable UART0 interrupts
    LPC_USART0->INTENSET |= ((1UL << 0));

    return 0;
}
ErrorCode_t setupI2C() {

    ErrorCode_t err;

    // Enable I2C clock

    LPC_SYSCON->SYSAHBCLKCTRL1 |= ((1UL << 13));
    LPC_I2C0->DIV = 0x0078;    // 120 decimal

    LPC_I2C0->MSTTIME = 0x00;    // SCL high / low = 2 clocks each

    //DEBUG
    LPC_SWM->PINENABLE1 = 0x00;

    // Enable interrupts
    NVIC->ISER0 |= ((1UL << 24));                // ISE_I2C0
    LPC_I2C0->INTENSET |= ((1UL << 0));         // MSTPENDINGEN
    LPC_I2C0->INTENSET |= ((1UL << 8));         // SLVPENDINGEN

    // Get handle to I2C API
    pI2CApi = getI2CDriver();

    // Initialize memory for UART API
    hI2C = pI2CApi->i2c_setup(LPC_I2C0_BASE, (uint32_t*)&i2c_instance);

    // This NULLS uart_instance somehow
    // Set bitrate
    err = pI2CApi->i2c_set_bitrate(hI2C, BASE_CLOCK, I2C_BAUD);

    // Set master mode
    LPC_I2C0->CFG = ((1UL << 0));               // MSTEN

    return err;
}