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

Data Corruption when Segregating Functions into Different Files

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

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

正在移动的代码是原始整体文件的复制和粘贴。我已经在 SWD link 上逐步使用 GDB。看来我用来命中内部 ROM 驱动程序的静态变量之一被 NULLified。稍后取消引用会导致错误。

监视静态变量,我可以看到在 I2C 初始化例程中炸毁它的代码行。有问题的是,init 是使用 NXP 提供的 in-ROM 驱动程序例程完成的。此外,当所有代码都在同一个文件中时,同样的代码可以毫无问题地工作。

问题

回复评论中的问题

代码吐槽

提醒一句,这段代码非常典型且未经优化。其中大部分是从数据表中无耻地复制的。

定义静态变量(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;
}

中断指针的 I2C 初始化代码 (main.c)

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

我看不出上面的代码有什么问题。

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

现在,这是一个通用的评论,与您的代码没有直接关系。它有一定的帮助......祝你好运!