2015-04-04 37 views
1

這個問題讓我煩惱。我正在做一些基於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提供,並通過在固定存儲器地址處提供的雙指針來訪問。我檢查了這些指針對象(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; 
} 

斷開指針的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; 
} 
+1

你可以轉儲'i2c_set_bitrate'的程序集嗎? 'i2c_setup'中可能有些東西可以讓你啓動segfault? 'i2c_instance'是靜態的嗎?你是否在'extern'聲明的其他文件中使用'uart_instance'?我做的另一件事是看鏈接器映射文件 - 請參閱附近的變量.. – Abhi 2015-04-04 01:35:01

+0

除了@Abhi寫了什麼之外,setupI2C()的哪一行會消失?我認爲這可能是對i2c_setup()的調用。設置變量i2c_instance。如果這個變量聲明不正確,它可能會覆蓋會影響uart_instance的相鄰全局內存。 – 2015-04-04 12:23:14

+0

如果鏈接器不吐出靜態變量 - 刪除靜態聲明。由於您在其他地方的評論表明沒有其他'uart_instance'。 – Abhi 2015-04-05 06:28:10

回答

1

我沒有看到上面的代碼錯誤。

通常,可以通過將代碼拆分成幾個文件而意外引入的錯誤是靜態變量的重複。例如,在main.c和usart.c中都可能有一個static UART_HANDLE_T uart_instance;(或者甚至在兩個包含的某些.h中都是奇怪的)。一切都會編譯並鏈接OK,但main.c和usart.c中的函數將使用不相關的變量,並且程序邏輯將隨着數據損壞的可能性而改變。

現在,這是一個與您的代碼沒有直接關係的通用註釋。有一些機會可以幫助你...祝你好運狩獵臭蟲!

+0

我只是通過我的每個靜態變量的代碼grepped加倍確定;每個只定義一次。不過我注意到'uart_instance'變量佔用了一個很好的循環地址0x40004000。這非常接近用戶記憶的開始,所以我不確定這是否是一個問題。 – phobos51594 2015-04-04 01:41:41

+1

作爲測試,嘗試聲明一個64字節或128字節的緩衝區,或者在uart_instance之上的任何合理的 - 你的用戶內存之前可能會損壞任何內存區域。 – Abhi 2015-04-05 06:30:45

+0

對不起,在響應延遲;其中一個電壓調節器出現故障並煮熟板,所以另一個必須製作。無論如何,你擊中了頭部。顯然,數據表中提供的數據結構與從API例程返回的結構大小不匹配。 API需要額外的8個字節,這就是爲什麼我的句柄(直接定義在後面)被破壞的原因。非常相信API!我唯一的問題仍然是爲什麼直到我拆分源文件時,這個問題才顯示出來?它不應該一直髮生嗎?這是由於對齊或類似? – phobos51594 2015-04-24 17:33:31