这个问题让我烦恼。我正在做一些基于LPC15XX系列微控制器的定制传感器板的裸机编程。该平台相当于一堆I2C传感器和连接到其中一个UART的蓝牙发射器。这不是LPCxpresso(或类似)电路板之一;它是一个定制设计。将函数分隔成不同文件时的数据损坏
直到今天,所有测试代码都在一个单片文件中,正如所料。随着代码的增长,我决定将主要功能块分解成单独的源文件以简化管理。不幸的是,只要我这样做,该计划开始segfaulting。
正在移动的代码是原始单片文件的副本+粘贴。我已经通过SWD链接使用了GDB。看来我用来命中内部ROM驱动程序的一个静态变量被取消了。稍后解除引用会导致错误。
在静态变量上设置一个监视,我可以看到它的代码行在I2C初始化例程中。有问题的是init是使用恩智浦提供的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;
}
断开指针的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;
}
你可以转储'i2c_set_bitrate'的程序集吗? 'i2c_setup'中可能有些东西可以让你启动segfault? 'i2c_instance'是静态的吗?你是否在'extern'声明的其他文件中使用'uart_instance'?我做的另一件事是看链接器映射文件 - 请参阅附近的变量.. – Abhi 2015-04-04 01:35:01
除了@Abhi写了什么之外,setupI2C()的哪一行会消失?我认为这可能是对i2c_setup()的调用。设置变量i2c_instance。如果这个变量声明不正确,它可能会覆盖会影响uart_instance的相邻全局内存。 – 2015-04-04 12:23:14
如果链接器不吐出静态变量 - 删除静态声明。由于您在其他地方的评论表明没有其他'uart_instance'。 – Abhi 2015-04-05 06:28:10