keil程序在外部RAM中調試的問題總結(個人的一點經驗總結)


keil程序在內部RAM調試的基本步驟網上已經有非常多了,我就不再贅述,大家能夠在網上搜到非常多。


可是有些時候內部RAM並不夠用,這就須要將程序裝入外部RAM中調試,而在這個過程中可能會出現各種各樣的問題,在這里我將會把我遇到過的一些問題和須要注意的地方總結一下,希望可以對大家有所幫助。


有錯誤的地方也希望大神們可以指教,提前表示感謝···


轉載請注明出處:waitig's blog


先介紹下我項目使用的硬件,芯片是LPC1788,外部RAM是MT48LC4M32B2,大小為16M(128Mb X32 SDRAM),之前用的是MT48LC2M32B2,大小為8M,后來發現東西太多,8M不夠用了,所以換成了16M的。

在換RAM時也遇到過一些問題,這個在下文中會有介紹。


  • 在外部RAM中調試程序,程序中一定不能有操作外部RAM的代碼!


在外部RAM中調試,程序中不要有操作外部RAM的代碼,初始化也不要有,包含對RAM相關引腳的操作。

RAM的初始化和引腳的初始化要放到jlink的下載配置文件里,主要是對LPC的寄存器進行相關配置,不要忘了RAM中的讀取算法配置。

把我的配置文件貼出來供大家參考一下。

FUNC void PinSel(int p1, int n1, int f1)
{
    _WDWORD(0x4002C000 + (p1 * 32 + n1) * 4, 0x8 | f1);
}

FUNC void InitSDRAM(void)
{
    int i;
    
    PinSel(2,16,1);
    PinSel(2,17,1);
    PinSel(2,18,1);
    PinSel(2,20,1);
    PinSel(2,24,1);
    PinSel(2,28,1);
    PinSel(2,29,1);
    PinSel(2,30,1);
    PinSel(2,31,1);

    for(i = 0; i < 32; i++)
        PinSel(3,i,1);
        
    for(i = 0; i < 21; i++)
        PinSel(4,i,1);

    PinSel(4,24,1);
    PinSel(4,25,1);
    PinSel(4,30,1);
    PinSel(4,31,1);
    
    /* PCONP |= 1 << 11 */
    _WDWORD(0x400FC0C4, 0x04288FDE);    // Power On EMC

    /* EMCCONTROL |= 1 */
    _WDWORD(0x2009C000, 0x00000001);    // Enable EMC

    /* EMCDLYCTL */
    _WDWORD(0x400FC1DC, 0x00081818);    // Config data read delay

    /* EMCCONFIG */
    _WDWORD(0x2009C008, 0x00000000);    // Little endian mode

    /* DYNAMICCONTROL */
    _WDWORD(0x2009C020, 0x00000003);    // Set normal self refresh mode, normal power mode
                                        // CE always HI
                                        // Enable clock out
                                        // Clock do not stop during idle

    /* DYNAMICREFRESH */
    _WDWORD(0x2009C024, 0x0000001F);    // refresh timing 

    /* DYNAMICREADCONFIG */
    _WDWORD(0x2009C028, 0x00000001);    // read timing 

    /* DYNAMICRP */
    _WDWORD(0x2009C030, 0x00000002);    // tRP

    /* DYNAMICRAS */
    _WDWORD(0x2009C034, 0x00000003);    // tRAS
    
    /* DYNAMICSREX */
    _WDWORD(0x2009C038, 0x00000005);    // tSREX

    /* DYNAMICAPR */
    _WDWORD(0x2009C03C, 0x00000001);    // tAPR

    /* DYNAMICDAL */
    _WDWORD(0x2009C040, 0x00000005);    // tDAL

    /* DYNAMICWR */
    _WDWORD(0x2009C044, 0x00000003);    // tWR

    /* DYNAMICRC */
    _WDWORD(0x2009C048, 0x00000004);    // tRC

    /* DYNAMICRFC */
    _WDWORD(0x2009C04C, 0x00000004);    // tRFC

    /* DYNAMICXSR */
    _WDWORD(0x2009C050, 0x00000005);    // tXSR

    /* DYNAMICRRD */
    _WDWORD(0x2009C054, 0x00000001);    // tRRD

    /* DYNAMICMRD */
    _WDWORD(0x2009C058, 0x00000003);    // tMRD

    /* DYNAMICCASRAS0 */
    _WDWORD(0x2009C104, 0x00000303);    // RAS/CAS Latency

    /* DYNAMICCONFIG0 */
    _WDWORD(0x2009C100, 0x00004500);    // Config device type as SDRAM
                                        // Config address mapping

    _sleep_(100);                       // Wait 100 ms

    /* DYNAMICCONTROL */
    _WDWORD(0x2009C020, 0x00000183);    // nop command

    _sleep_(100);                       // Wait 100 ms

    /* DYNAMICCONTROL */
    _WDWORD(0x2009C020, 0x00000103);    // pre-charge command
    
//    /* DYNAMICREFRESH */
//    _WDWORD(0x2009C024, 0x00000002);    // refresh timing 

    _sleep_(100);                       // Wait 100 ms

    /* DYNAMICREFRESH */
    _WDWORD(0x2009C024, 0x0000001F);    // refresh timing 
    
    /* DYNAMICCONTROL */
    _WDWORD(0x2009C020, 0x00000083);    // mode command
    _RDWORD(0xA0000000 | (0x32 << (2 + 2 + 8)));
    
    _sleep_(100);                       // Wait 100 ms

    /* DYNAMICCONTROL */
    _WDWORD(0x2009C020, 0x00000003);    // noamal command

    /* DYNAMICCONFIG0 */
    _WDWORD(0x2009C100, 0x00084500);    // enable buffer
    
    _sleep_(100);                       // Wait 100 ms
}

以上是外部RAM的初始化部分,不要忘了當中的RAM本身的寄存器,在本例中的地址是0xA0000000,寄存器中的各個位數的作用例如以下圖:


(截圖自MT48LC4M32B2的datasheet)

當中數據要配置正確,RAM才干正確工作。接下來是對內存保護單元(MPU)的配置,兩者結合,就是Jlink對RAM的初始化和配置。


RAM_Debug.ini 的文件例如以下所看到的:

INCLUDE MT48LC4M32LFB5.ini

InitSDRAM();                                // Initialize memory

LOAD ..\SDRAM_obj\uc1788.axf INCREMENTAL    // Download program

/* RNR */
_WDWORD(0xE000ED98, 0x00000000);            // Use No.0 MPU

/* RBAR */
_WDWORD(0xE000ED9C, 0xA0000000);            // Set MPU base addr

/* RASR */
_WDWORD(0xE000EDA0, 0x03000031);            // Set MPU size and permission

/* SHCSR */
// _WDWORD(0xE000ED24, 0x00000100);            // Enable memory managemeng fault

/* MPU_CONTROL */
_WDWORD(0xE000ED94, 0x00000005);            // Enable MPU

/* VTOR */
_WDWORD(0xE000ED08, 0x10000000);            // Set vector table offset

SP = _RDWORD(0x10000000);                   // Set stack pointer
PC = _RDWORD(0x10000004);                   // Set program counter

這樣就能像在FLASH中調試一樣來在RAM中調試了。

可是,程序中不要出現不論什么操作RAM的代碼!一定記住!


  • 程序裝入RAM中起始地址出錯


所謂起始地址,就是指程序剛裝入RAM中,還沒有執行的那個pc地址。

正常情況下,這個地址是指向芯片啟動代碼的systemiInit()這個函數所在的地址的,可是有些時候這個地址會出錯,跑到一個不知道什么地址的地方去。


例如以下圖所看到的:



我分析出現這個現象的原因是在jlink對RAM的配置方面有問題,也就是對RAM沒有配置成功,導致程序沒有成功存入RAM中,或者是儲存成功,可是讀取失敗,或者儲存讀取都有問題。


解決方式就是查看內存中的數據,看是否正確。或者對設備又一次上電,對jlink復位后又一次調試。


這個問題在我這里偶爾會出現,但又一次調試又會消失,所以到眼下我也沒弄清楚這個問題出現的原因。


  • 程序跑入HardFault_Handler

HardFault_Handler是指指令錯誤中斷,通常是由於程序代碼翻譯成的匯編代碼中出現了錯誤的指令。

解決問題的方法通常是找出錯誤指令的地址,假設地址是在當前分配的代碼段的最開始位置(比方我在分散載入里面將這段代碼放在0xA0001000-0XA0002000之間,然后出錯指令出如今0xA0001010這個位置);

或者在上個代碼段的結束位置(比方我將這段代碼放在0xA0001000位置處,上段代碼在0xA0000900結束,而出錯指令在0xA0000920這個位置);

普通情況下是內存不夠用導致的,並且出錯的語句通常是向全局變量賦值的語句。由於內存不夠用,可是jlink在向RAM中寫數據的時候並不知道內存不夠,導致后來溢出的數據折返回代碼段起始地址,將曾經的內容覆蓋所導致的。(內存覆蓋)


解決問題的方法就是換一個大的RAM。


另一種可能,就是在程序中有操作RAM的代碼,這也會導致RAM中內容被改動,出現錯誤的指令。


  • 程序中途跑飛


上一條中的問題也有可能導致程序中途跑飛,此外另一種可能就是指針問題。

指針沒有正確初始化,使用了未初始化的指針,或者是指針沒有正確回收,導致出現野指針,是最常見的,也是最easy導致程序跑飛的原因。出現故障應最先考慮此因素。


排除了以上的因素后,能夠依據那些常規方法,比方查看LR寄存器的值,找到出現故障的語句等方法來查找詳細原因。


  • 更換新外部RAM時要注意的問題


更換新RAM之前先看RAM的手冊和芯片的手冊,看清楚使用的芯片支持不支持新的RAM,我就由於沒看清楚手冊導致買了芯片不支持的RAM,既費錢又費力。。。。

芯片user manul上一般都有一個表,表中就是它所支持的全部RAM的類型。例如以下圖:



先查清楚再買芯片,血淋淋的教訓。。。


不同的RAM讀寫規則有些會有所不同,配置也不盡同樣,所以在更換新RAM時要細致讀懂RAM的datasheet,對其清楚掌握。

基本上須要配置的最主要參數有下面幾個:頁大小,外部總線地址映射(行,列,bank),空間大小,位數,讀寫的算法(在RAM自己的寄存器中配置);

外部總線地址映射要與芯片相應,然后通過上表來確定配置寄存器的值。(程序在RAM中調試要改動jlink的ini文件)



  • 結語:臨時就想到了這些,以上的問題都是我在實際項目中碰到的問題,和一些經驗介紹。因為我自己也學藝不精,能力有限,所以難免有錯誤的地方,希望路過的大神能夠幫忙指正。同一時候聲明,僅供參考。


轉載請注明出處:waitig's blog



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM