dsPIC33C 器件具有4M x 24位的程序存儲器地址空間,下面是Flash大小為256KB的程序存儲器地址的映射關系。
整個Flash結構分為活動區(qū)域和非活動區(qū)域,用戶可用的是活動區(qū)域,而活動區(qū)域可分為用戶程序存儲區(qū)和器件配置,其中前兩個字節(jié)0x000000~0x000002為復位入口向量,0x000004~0x0001FE為中斷向量表IVT,0x000200為主程序的入口地址,正常情況下代碼從此處開始存放。
用戶程序存儲空間(User Application Firmware,0x200開始)分配一般是把Bootloader部分放在前,應用程序放在后的結構。這首先是實際的引導加載程序空間,是Bootloader代碼所在的位置,包括IVT和AIVT。引導加載程序空間只能通過對新的BootLoader程序進行編程來修改。第二個存儲空間是應用程序存儲空間或應用程序代碼所在的位置。應用程序存儲空間的一部分包括重新映射的中斷向量(Remapped Applicartion IVT)。該內(nèi)存映射顯示在下面的程序內(nèi)存使用情況中。通過使用引導程序將代碼從外部設備傳輸?shù)酱舜鎯^(qū)域,可以在此處對應用程序代碼進行重新編程。 MCU在上電和復位都是從Bootloader開始執(zhí)行,BootLoader運行后判斷當前是否需要進入升級狀態(tài)。如果不需要升級,就直接運行Flash原有的應用程序;如果需要升級,則進入升級狀態(tài)。
Bootloader程序存放時,是按照正常情況下從0x000200開始存放。但是存放Bootloader程序的空間起始地址不應該緊接著此地址,因為如果這樣擦除第一個閃存存儲頁也會擦除Bootloader的程序。因此,自舉程序的起始地址必須為0x800,為什么是0x800?
因為dsPIC33C一頁有1024指令字,一行有128指令字,一個指令字為32位(實際24位,高8位為虛字節(jié),始終保持為0),由于dsPIC33C系列都是16位單片機,因此每個指令字占2個16位數(shù)據(jù),占2個地址,實際擦除的地址跨度為2048,即0x800。
下面是dsPIC33C 單分區(qū)閃存代碼存儲區(qū)大小的情況。
Flash為256KB大小的具有90112指令字,704行,88頁,下面是具體頁的分布情況。
所以弄清楚了頁的分布后,對Bootloader程序空間分配完畢之后,應用程序的存放需要添加相應的偏移量(可對照此表)。
定義存儲空間的大小和位置主要涉及確定當前BootLoader的大小以及將來容納新功能所需的任何可用空間。 在最終確定此空間的大小之前,提供額外空間非常重要。 如果將來需要更改分配的BootLoader閃存空間的大小,則需要同時更改應用程序的啟動位置,然后重新映射中斷向量表的位置也需要更改。 對應的兩個更改處意味著該應用程序將無法與較早的引導加載程序一起使用。 必須在項目開始時就保留足夠的空間,以便將來提供額外的增長空間。 一旦確定了為引導加載程序分配的閃存大小,即可將其余的閃存分配給應用程序和重新映射的中斷向量表。
BootLoader程序空間的大小必須是設備頁面大小的倍數(shù)。 對于頁面大小為512條指令(1024個字)的設備,頁面大小必須為0x400的倍數(shù)。 同樣,對于具有1024條指令(2048個字)的頁面大小的設備,頁面大小必須為0x800的倍數(shù)。
比如Bootloader程序地址入口為0x800,分配2k指令字的大小,同時由于應用程序也不可緊跟自舉程序之后,它必須從下一個閃存存儲頁的開始處開始存放,那么應用程序的入口地址為0x1800.
TBLRDx和TBLWTx指令提供了讀或寫程序空間內(nèi)任何地址的最低有效字和最高有效字的直接方法,非常適合某些應用。
對于表指令,程序存儲器可被視為并排放置的兩個16位字寬的地址空間,每個地址空間都有相同的地址范圍,由于程序存儲器只有24位寬,所以后一個空間的高字節(jié)不存在(盡管它是可尋址的),被稱為“虛擬字節(jié)”。低位字的地址始終為偶數(shù),而高位字的地址為奇數(shù)。
由于程序存儲器地址始終在低位字處按字對齊,所以在代碼執(zhí)行的過程中地址將遞增或遞減2。這種尋址模式也與數(shù)據(jù)存儲空間尋址兼容,且為訪問程序存儲空間中的數(shù)據(jù)提供了可能。下圖是一個取值示例,PC<22:1>指針遞增1相當于PC<22:0>加2.
在MCU運行時,對內(nèi)部Flash進行擦除、編程(注意,建議不要對當前程序運行區(qū)域進行擦寫,會導致運行異常)。
Flash編程采用的方式是"與"模式,即編程時,將數(shù)據(jù)與Flash地址上的數(shù)據(jù)"與"操作。因此,如果一個地址上的數(shù)據(jù)位不是全都為1,那么編程該地址的結果就是錯誤的,所以我們在操作Flash時要有一個共識,一個程序存儲字可以在擦除之前被編程兩次,但僅限于(1)兩次編程操做使用相同的數(shù)據(jù)或(2)包含1的位被設置為0,但為0的位不能設置為1;所以一般不建議在不擦除的情況下對數(shù)據(jù)進行第二次編程,應該將該地址所有數(shù)據(jù)位置1.我們該如何在編程前將對應地址的數(shù)據(jù)位全部置1呢?
那就是擦除,F(xiàn)lash擦除會把對應區(qū)域的數(shù)據(jù)位全部置1。但是擦除不能僅擦除一個地址的數(shù)據(jù),而是必須擦除一頁的數(shù)據(jù),假設我們擦除0x000000,實際會擦除0x000000-0x0007FF,擦除其中任意地址,都會擦除該頁。所以dsPIC33C擦除操做是按頁擦除,按行進行寫?;蛘呖梢韵葘⒃擁搩?nèi)所有數(shù)據(jù)讀出來,然后擦除flash頁,再修改讀出來的數(shù)據(jù),最后重新寫入該頁所有數(shù)據(jù)。
需要提醒的是,由于配置字在用戶存儲區(qū)域最后一頁,擦除最后一頁會觸發(fā)代碼保護,所有地址數(shù)據(jù)全部清零。以dsPIC33CK256MP506為例,0x02BF00~0x02BFFC為配置字存放的地方,所以0x02B800之后的地址不能被擦除。
在雙分區(qū)閃存模式下,器件的存儲器均分為兩個物理部分,稱為分區(qū)1 和分區(qū)2。每個分區(qū)都包含自己的程序存儲器和配置字。在程序執(zhí)行期間,只可執(zhí)行其中一個分區(qū)中的代碼,該分區(qū)為活動分區(qū)。另一個非活動分區(qū)不可用于執(zhí)行但可進行編程。
支持的三種擦除工作分別是:批量擦除,非活動區(qū)域擦除和頁擦除。
批量擦除是擦除用戶所有存儲區(qū)。
非活動分區(qū)擦除操作可以在運行時從活動分區(qū)執(zhí)行。它將擦除非活動分區(qū)中的所有用戶存儲區(qū)和閃存配置字。非活動分區(qū)擦除命令僅在器件處于雙分區(qū)閃存模式之一時有效。這個功能在做Liveupdate時非常有用,當活動區(qū)處于工作時,這時可以對非活動區(qū)進行擦寫修改某些內(nèi)容,然后實現(xiàn)活動區(qū)與非活動區(qū)的無縫切換,對MCU實現(xiàn)不掉電升級,此類應用在服務器電源應用中比較多。
后面的BootLoader實現(xiàn)均是在基于單分區(qū)模式下。