这个问题令我烦恼。我正在C中进行一些基于LPC15XX系列微控制器的定制传感器板的裸机编程。该平台相当于一堆I2C传感器和连接到其中一个UART的BlueTooth发射器。这不是LPCxpresso(或类似)板之一;它是定制设计。
直到今天,一切都按预期工作,所有测试代码都在一个整体文件中。随着代码的增长,我决定将主要功能部分分解为单独的源文件,以便于管理。不幸的是,一旦我这样做,该程序就开始了segfaulting。
正在移动的代码是原始单片文件的复制+粘贴。我已经逐步通过SWD链接使用GDB。看来用于命中内部ROM驱动程序的我的一个静态变量正在被置空。稍后取消引用会导致错误。
在静态变量上设置监视,我可以看到它的代码行是在I2C初始化例程中。有问题的是init是使用NXP提供的in-ROM驱动程序例程完成的。此外,当同一个代码全部在同一个文件中时,这个代码也没有问题。
问题
像这样的核心文件级静态变量是什么?根据我的理解,变量不应该在堆栈上,所以我没有看到缓冲区溢出导致这种情况。
为什么在文件之间移动代码会暴露这个?不管怎样都不应该编译并链接到一个命名空间中吗?
对评论中的问题的回复
uart_instance
在usart.c
中定义一次,并且只在uart_setup
调用时直接(按名称)写入一次。
同样,i2c_instance
在main.c
中定义(我还没有移动过I2C功能)。是静态的并且与uart_instance
相同地声明。我已更新下面的代码,以包含两个文件中的所有静态变量。
在pI2CApi->i2c_set_bitrate(hI2C, BASE_CLOCK, I2C_BAUD);
的调用中,指针实际上是空的,这是通过在相关内存上设置监视来确定的。
我无法直接跟踪任何ROM驱动程序例程。它们由uC提供,并通过在固定存储器地址处提供的双指针访问。我检查了这些指针对象(hUart
和pUartApi
)并保留了正确的值;只有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;
}
答案 0 :(得分:1)
我认为上面的代码没有错。
通常,通过将代码拆分为多个文件而意外引入的错误是静态变量的重复。例如,main.c和usart.c中都可能有static UART_HANDLE_T uart_instance;
(或者两者都包含在某些.h中甚至很奇怪)。一切都将编译和链接OK,但main.c和usart.c中的函数将使用不相关的变量,程序逻辑将发生变化,可能会导致数据损坏。
现在,这是一个与您的代码没有直接关系的通用备注。它有可能有所帮助......祝你好运![/ p>