新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > C8051F12X系列單片機中多bank的分區跳轉處理

        C8051F12X系列單片機中多bank的分區跳轉處理

        作者: 時間:2012-01-16 來源:網絡 收藏

         在8051核單片機龐大的家族中,C8051F系列作為其中的后起之秀,是目前功能最全、速度最快的8051衍生單片機之一,正得到越來越廣泛的應用。它集成了嵌入式系統的許多先進技術,有豐富的模擬和數字資源.是一個完全意義上的SoC產品。

          C805IFl2X作為該系列中的高端部分,具有最快100MIPS的峰值速度,集成了最多的片上資源。其128 KB的片上Flash和8 KB的片上RAM足以滿足絕大多數應用的需求。使用,只需外加為數不多的驅動和接口,就可構成較大型的完整系統。只是其中128 KB的Flash存儲器不可避免地要處理bank分區問題。

          幸運的是Keil C51開發環境對C8051F系列有良好的支持,包括一般的跨bank分區的程序跳轉和調用。作為數據存儲器使用時,Flash的分區讀寫完全是編程者要考慮的事情,與開發環境無關。本文只針對特殊的強制轉移和μC/OS—II在分區中的移植問題展開討論。

        1 在Keil C51中的分區轉移機制

          Keil C51的連接定位器支持分組連接,允許生成代碼長度大于64 KB的8051目標程序_1_。一般的8051系統只提供16根地址線,需要附加地址線來實現代碼分組切換,而編譯器產生bank切換代碼時受到配置文件 L51_BANK.A51的支持,所以用戶必須根據自己的硬件結構來修改這個配置文件。

          系列不用考慮硬件部分,也不存在地址線的擴展問題,因為128 KB的4個bank區全部都在CPU內部,所以作為常規跨bank的跳轉和調用,不需要處理1.5l_BANK.A51配置文件。但在特殊情況下就必須考慮該問題,否則程序將無法工作。下面以C8051F120為例先討論代碼的透明分組切換過程。

          C805IFl20在Keil C51的項目配置中被劃分為4個bank,每個32 KB。公共bank地址從0~0x7fff,其余bank從0x8000h~0xffff。在對應的配置文件L51_BANK.A51中,涉及到特殊功能寄存器PSBANK(SFR地址:0B1H)、SWITCHn宏、B_BANKn、B_SWITCHn分組信息保存和切換代碼,以及 B_CURENTBANK變量。

          PSBANK為C8051F120內的特殊功能寄存器,128KB Flash的分bank訪問就是通過它來實現的。要想轉移到新的bank中去,必須賦予PSBANK正確的值,然后再轉向bank區內地址即可。

          SWITCHn宏共有4個,分別是SwITCH0、SWlTCH1、SWITCH2和SWITCH3,對應切換到4個bank中。其中SWITCH0對應的語句為:

          MOV PSBANK.#00h ;把00h用1Ih、22h和33h替換,就是其他三個宏

          它將插入到B_SWITCHn代碼中,用來切換新的bank和恢復到原來的bank。

          所有4組B_BANKn和B_SWlTCHn代碼也都是用宏實現的,對應4個bank處理。它們匯集在BANK SWITCH代碼段中,整個bank切換及恢復機制非常巧妙,可以實現任意bank之間函數的相互調用及嵌套。下面以bank3區中的main函數調用bankl區的Delay_noOS() 延時函數為例說明該機制。

          void main(void){
        MCUInit(); //初始化CPU
        Delay_n00s(10); //延時lO ms
        Lcmlnition();

          bank3中被調用的函數Delay_noOS(10)對應的匯編語句為:

          LCALL C:5049

          公共段(即Common段,對應bank0)中C:5049處的匯編語句如下:

          MOV dptr,#Delay_noOS

          AJMP B_BANKl

          這里的B_BANKl就是宏B_BANKN中N為1的例程。現在進入問題的核心:全部的跨bank區程序切換及恢復過程依靠公共段中BANK  SWITCH代碼段里的以下匯編代碼實現,對應的N為0、1、2和3。BANK SWlTCH SEGMENT CODE PAGE

          ;
        B_BANKN:
        PUSH B_CURRENTBANK (1)
        MOV A,#HIGH BANK SWITCH (2)
        PUSH ACC (3)
        PUSH DPL (4)
        PUSH DPH (5)
        B_SWITCHN:
        MOV B_CURRENTBANK,#LOW B_SWITCHN
        (6)
        SWlTCHN (7)
        RET (8)


          Delay_noOS(10)函數的返回地址,即函數LcmIni-tion()的入口地址(也在bank3中),其高低位字節表示為ADDH和 ADDL。程序進入main()后的B_CURRENTBANK變量初值是B_SWITCH3的低8位,其意義稍后敘述。AJMP B_BANKl后程序執行?B_BANKl和?B_SWITCHl的(1)~(8),執行到(5)時的堆棧結構如圖1所示。

        C8051F12X系列單片機中多bank的分區跳轉處理

          繼續執行B_SWITCHl到(7)時,PSBANK變為指向bankl,B_CURRENTBANK變為B_SWITCHl的低8位。執行(8) 后,從堆棧結構可以看出,堆棧彈出①作為新的PC值,程序進入Delay_noOS(10)函數,延時功能完成后,函數最后一條RET指令開始返回。這是 Keil C51處理bank機制的關鍵,此時的返回地址為堆棧中的②,此地址即B_SWITCHH代碼的入口,這里對應main()函數所在的 bank3分組,也就是B_SWITCH3的人口。

          因為所有B_SWITCHN的高8位地址,即BANK  SWITCH代碼段的高8位都一樣,由語句(2)中的操作符HIGH BANK SWITCH確定;低8位保存在已經壓棧的B_CURRENTBANK變量中,此時堆棧中的?B_CURRENTBANK壓棧值是 B_SWITCH3的低8位,這樣②的地址就是B_SWITCH3。

          程序繼續執行B_SWITCH3,在執行? B_SWITCH3的(6)語句之前,B_CURRENTBANK還是前面執行?B_SWITCHl時的值,即B_SWITCHl的低8位。執行語句 (6)后,B_CURRENTBANK恢復為B_SWITCH3的低8位,為返回main函數做準備。然后PSBANK置為33h,即指向bank3,接著執行RET語句,堆棧③成為RET的返回地址,程序回到了main()中Delay_noOS(10)的下一條語句繼續執行, B_CURRENTBANK也已恢復。

          這個調用過程中,用了6個堆棧字節,3條RET指令,關鍵內容就是B_CURRENTBANK變量,它保存了可以恢復調用前bank環境代碼的地址低位。從被調用函數返回 到這個地址后,就能恢復調用前的bank環境,即賦予PSBANK正確的值。

          不采用直接保存PSBANK值然后再恢復,而是用壓棧的方式保存了相關地址(語句(1)~(3)),是為了實現跨bank區的嵌套調用。例如,在 Delay_noOS(10)函數中,如果再次跨bank去調用新函數,會再次重復上述過程,堆棧從②往上再長6個字節。Delay_noOS(10)函數之前執行B_SWITCHI產生的B_CURRENTBANK值(B_SWITCHI的低8位)也會進棧,為調用完新函數后返回到bankl繼續執行 Delay_noOS(10)提供保證。

        2 無操作系統bank分區間的強制跳轉

          通過上面的分析得知,如果要處理跨bank區的跳轉、調用和返回,關鍵是能正確處理好PSBANK中的內容。當程序沒有操作系統用于任務切換,而又需要強制退出某一函數進入到另一函數的某一地址時,比如說在中斷發生后,結束原來的工作轉入到另一工作去,就需要處理好PSBANK。

          如果不考慮bank,可以在轉入新地址之前執行一段代碼,保存該地址處的環境變量[2],包括堆棧指針sP和需要的入口地址。然后在中斷返回之前,恢復此環境變量,執行中斷返回指令進入該新地址。這個思路和C51庫函數setjump和longjump比較相近,但比它們靈活,因為環境變量可以自己處理。

          考慮bank后的情況稍微復雜些,環境變量中需增加bank的處理信息,那么只處理PSBANK行不行呢?

          如果僅保存和恢復PSBANK,則很簡單,在保存環境變量的程序中加入:

          JMPEnv[envl][3]=PSBANK;

          在恢復環境變量的程序中加入:

          PSBANK=JMPEnv[envl][3];

          這里環境變量是二維數組JMPEnv,envl代表一個環境變量,即一個返回點。第二維是變量中的參數個數。因此可以保存多個環境變量以供使用。

          初看起來這樣處理是沒有問題的,可實際上不行。因為進入返回點后,雖然PSBANK正確了,但是B_CUR-RENTBANK可能已經被修改,不能和返回點程序的bank區匹配,如果再次出現跨bank調用的話將不能正確返回。

          處理方法是有點技巧的,因為C語言不支持匯編變量B_CURRENTBANK的寫法,所以在L51_bank.A51中要加上聲明:

          PUBLIC BLCURRENTBANK

          和偽指令:

          B_CURRENTBANK EQU B_CURRENTBANK

          這樣就可以在C程序中使用B_CURRENTBANK了,先聲明B_CURRENTBANK:

          extern Uchar data B_CURRENTBANK;

          然后在保存環境變量程序中加入:

          JMPEnv[envl][3]=PSBANK;

          JMPEnv[envl][4]=B_CURRENTBANK;

          恢復環境變量程序中加入:

          PSBANK=JMPEnv[envl][3];

          B_CURRENTBANK=JMPEnv[envl][4];

          這樣恢復環境變量進入到新程序后,也將恢復該程序對應的正確?B_cuRRENTBANK值,問題得到解決。

        3 no/0S-ll移植中的bank分區處理

          μC/OS-II的51版本已經很成熟,但是所有移植版本均未處理bank問題,需要增加該內容,否則不能在包括C8051F12X系列及其他程序中使用。

          如前所述,Keil C51提供對跨bank調用的透明切換支持,但在使用操作系統時,這種透明切換機制還需要提供對任務切換的支持。因為任務的切換,程序可能需要到別的代碼分組中去運行,而此時PSBANK和B_CUR-RENTBANK還停留在原來代碼分組中的狀態,將導致程序崩潰。顯然,無論由于什么情況導致的任務切換完成之前,都需要保存和恢復PSBANK和B_CURRENT-BANK的值。解決的辦法是在每次任務切換前將PS-BANK和 B_CURRENTBANK壓入用戶任務棧。

          按照μC/OS-II的要求,在任務創建時,任務棧必須初始化成像運行中的任務剛剛發生過中斷一樣嘲。B_CURRENTBANK的初始值取決于該任務所在分組對應的切換代碼段的低8位地址。所以,任務堆棧的初始化函數 OSTaskStkInit需要加入一個參數INT8U bank,指明該任務位于哪個代碼分組中。又由于任務堆棧的初始化函數是被任務創建函數OSTaskCreate調用的,所以該函數一樣需要加入參數 INT8U bank。

          在壓棧,出棧宏中需要加入:

        PUSH PSBANK
        PUSH B_CURRENTBANK

        POP B_CURRENTBANK
        POP PSBANK

          在任務堆棧的初始化函數OSTaskStkInit中需要加入:

        *stk++=17; //堆棧長度增加2個到17

        if(bank==0x22:){ //bank2
        *stk++=bank;
        *stk++=CurrentBank2();
        else if(bank==0x33){ //bank3
        *stk++=bank;
        *stk++=CurrentBank3();
        }
        else{ //bankl和common
        *stk++=0xll; //PSBANK
        *stk++=CurrentBankl();
        )

          其中,bank0用任何的PSBANK值均沒有問題,所以簡化了PSBANK取值0x00的情況。

          函數INT8U CurrentBankl(void),INT8U Current-Bank2(void)和INT8U CurrentBank3(void)是用匯編語言實現的,返回值通過R7傳遞,目的是獲得該任務所在分組對應切換代碼段(SWITCHn)的低8位地址。不用C語言編寫的原因同樣是B_SWITCHN不被C支持。

          CurrentBankl(void)代碼如下,其他兩個類同。

        RSEG PR CurrentBankl Os_CPU_A
        CurrentBankl:
        MOV DPTR,#B_SWITCHl
        MOV R7.DPL
        RET

        結 語

          本文介紹了Keil C51實現大于64 KB程序的bank分組代碼切換機制的原理,提出了沒有操作系統情況下非正常轉移時bank的處理方法以及μc/os—II操作系統在多bank分區程序移植中應采取的措施,在開發實例中均得到了很好的應用。


        關鍵詞: C8051F12X 多bank

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 永寿县| 寿光市| 延安市| 玉溪市| 南昌县| 浑源县| 琼海市| 敖汉旗| 永修县| 沁阳市| 织金县| 龙川县| 钟山县| 项城市| 洪湖市| 舟山市| 金华市| 化德县| 廊坊市| 泸水县| 蒙自县| 龙山县| 资溪县| 呼伦贝尔市| 尚志市| 赤城县| 全州县| 滕州市| 福海县| 西华县| 永登县| 太湖县| 营山县| 通州区| 兰溪市| 莱芜市| 资源县| 南江县| 开远市| 措美县| 乃东县|