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

时间:2015-04-04 00:15:57

标签: c corruption bare-metal lpc

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

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

正在移动的代码是原始单片文件的复制+粘贴。我已经逐步通过SWD链接使用GDB。看来用于命中内部ROM驱动程序的我的一个静态变量正在被置空。稍后取消引用会导致错误。

在静态变量上设置监视,我可以看到它的代码行是在I2C初始化例程中。有问题的是init是使用NXP提供的in-ROM驱动程序例程完成的。此外,当同一个代码全部在同一个文件中时,这个代码也没有问题。

问题

  • 像这样的核心文件级静态变量是什么?根据我的理解,变量不应该在堆栈上,所以我没有看到缓冲区溢出导致这种情况。

  • 为什么在文件之间移动代码会暴露这个?不管怎样都不应该编译并链接到一个命名空间中吗?

对评论中的问题的回复

  • uart_instanceusart.c中定义一次,并且只在uart_setup调用时直接(按名称)写入一次。

  • 同样,i2c_instancemain.c中定义(我还没有移动过I2C功能)。是静态的并且与uart_instance相同地声明。我已更新下面的代码,以包含两个文件中的所有静态变量。

  • pI2CApi->i2c_set_bitrate(hI2C, BASE_CLOCK, I2C_BAUD);的调用中,指针实际上是空的,这是通过在相关内存上设置监视来确定的。

  • 我无法直接跟踪任何ROM驱动程序例程。它们由uC提供,并通过在固定存储器地址处提供的双指针访问。我检查了这些指针对象(hUartpUartApi)并保留了正确的值;只有uart_instance遭到破坏。

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

代码呕吐

警告一句,此代码非常典型且未经优化。其中大部分都是从数据表中无耻地复制过来的。

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

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

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

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

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

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

打破指针(main.c)的I2C初始化代码

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

1 个答案:

答案 0 :(得分:1)

我认为上面的代码没有错。

通常,通过将代码拆分为多个文件而意外引入的错误是静态变量的重复。例如,main.c和usart.c中都可能有static UART_HANDLE_T uart_instance;(或者两者都包含在某些.h中甚至很奇怪)。一切都将编译和链接OK,但main.c和usart.c中的函数将使用不相关的变量,程序逻辑将发生变化,可能会导致数据损坏。

现在,这是一个与您的代码没有直接关系的通用备注。它有可能有所帮助......祝你好运![/ p>