這個問題讓我煩惱。我正在做一些基於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