對.Net Micro Framework系統來說,正常情況下Flash(包括NandFlash和NORFlash)分為六個區,分别為:
1、 BLOCKTYPE_BOOTSTRAP(存放啟動代碼,一般為TinyBooter)
2、 BLOCKTYPE_CONFIG(配置區,存放配置資訊)
3、 BLOCKTYPE_CODE(本地代碼區,指TinyCLR代碼)
4、 BLOCKTYPE_DEPLOYMENT(托管代碼區,存放使用者的C#程式)
5、 BLOCKTYPE_STORAGE_A(使用者資料存儲區)
6、 BLOCKTYPE_FILESYSTEM(檔案系統)
其中2、3、4項為.Net Micro Framework系統所必須。
如果Flash為NandFlash,則存放在BLOCKTYPE_BOOTSTRAP區的啟動代碼是無法直接執行的,系統必須在ROM、NORFlash或其它線性執行存儲區存放一個Bootload,由該Bootload加載TinyBooter,然後由TinyBooter引導TinyCLR啟動(當然如果空間允許,TinyBooter也可以放在NORFlash,直接運作來引導TinyCLR,或Bootload直接引導TinyCLR也是可以的)。
TinyCLR一般常見大小為700k左右,其實也可以放在NORFlash中,不需要TinyBooter而直接運作,不過這樣就不友善用MFDeploy對TinyCLR進行更新了。
常見的MF系統,TinyBooter啟動後一般把TinyCLR從NandFlash拷貝到RAM中,TinyCLR實際是在RAM中執行的。這就需要RAM的大小至少要大于TinyCLR的大小,加上堆和棧的大小,理想的RAM大小至少要大于2M。
EM-STM3210E開發闆上的Flash含四部分,片内Flash 512k(系統Flash2k,存放系統Bootload,不能更改,ISP功能就是由該Bootload來支援的),2M NOR Flash,8M SPI Flash,128Mb(16M位元組) NandFlash。
Flash相對比較豐富,但是RAM資源卻有些不足,片内含64K RAM,片外擴充了128KB SRAM。由于RAM相對偏小,是以TinyCLR的代碼是不可能拷貝到RAM中執行的,如果TinyCLR達到常見大小,則片内使用者FLASH也是放不下的,也隻有放到2M的 NOR Flash中去了。不過我們這次Porting的.Net Micro Framework僅是最小集,TinyCLR大概250K左右,此外TinyBooter對我們也不是必須的,我們通過ISP方式下載下傳TinyCLR。
NORFlash和SPI Flash對我們來說不必要,僅需實作NandFlash即可,Flash的型号為ST NAND128W3A2BNb,最終的NandFlash分區如下:
const BlockRange g_NandFlash_BlockStatus[] =
{
{ BlockRange::BLOCKTYPE_CONFIG , 0, 7 }, //128K
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 8, 47 }, //640K
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 48, 87 },
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 128, 167 },
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 208, 247 },
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 288, 327 },
{ BlockRange::BLOCKTYPE_DEPLOYMENT, 328, 1007 },
{ BlockRange::BLOCKTYPE_STORAGE_A , 1008,1015 },
{ BlockRange::BLOCKTYPE_STORAGE_B , 1016,1023 },
};
我們的NandFlash驅動不要放在/DeviceCode/Targets/Native/CortexM3/DeviceCode目錄,因為不同的開發闆雖然采用STM32系列的CPU,但是外圍的Flash有可能型号不同,該NandFlash驅動要放在/Solutions/STM3210E/DeviceCode的目錄,這樣安排比較合理。
我們在該目錄下建立Blockstorage目錄,下有兩個子目錄addDevices和NandFlash,NandFlash目錄放NandFlash驅動代碼和配置資訊,addDevices目錄下的代碼比較簡單,就是把實作的NandFlash驅動加載到BlockStorageList中去,相關代碼如下:
void BlockStorage_AddDevices()
BlockStorageList::AddDevice( &g_NandFlash_BS, &g_NandFlash_BS_DeviceTable, &g_NandFlash_BS_Config, FALSE );
}
NandFlash的配置檔案中主要的内容就是我們上面提到的const BlockRange g_NandFlash_BlockStatus[],此外還要根據NandFlash的實際參數,填寫一些宏。
#define FLASH_MANUFACTURER_CODE 0x20
#define FLASH_DEVICE_CODE 0x73
#define FLASH_BASE_ADDRESS 0x00000000
#define FLASH_SIZE 0x01000000 //16M 128Mbit
#define FLASH_BLOCK_COUNT 1024
#define FLASH_SECTOR_PER_BLOCK 32
#define FLASH_SECTOR_SIZE 512
#define FLASH_BLOCK_SIZE FLASH_SECTOR_PER_BLOCK*FLASH_SECTOR_SIZE
… …
NandFlash驅動是核心内容,我們知道Cortex-M3平台下無論是通路SRAM還是NandFlash (或NandFlash、SD卡等)都是要通過FSMC實作,是以這裡要編寫NandFlash之前,一定要先配置好FSMC寄存器,配置好之後,其Flash 驅動代碼和普通的ARM7或ARM9下NandFlash驅動類似。
具體的代碼這裡不列舉了,可以參考EM-STM3210E開發闆的示例代碼,不過這裡需要說明的是,位址部分四個位元組,其中一個位元組表示扇區偏移,三個位元組表示扇區位址。但是我們的扇區(頁)大小為512+16個位元組,一個位元組無法表示0~511的偏移,這個問題在示例代碼中找不到答案,隻能看相關手冊了。
其實一個扇區(頁)分三部分,A、B、C,A為扇區前256位元組,B為扇區下個256位元組,C區為16位元組。是以下面的代碼就能實作0~511的扇區偏移。
WriteCommand(offset<256 ? COMMAND_AREA_A : COMMAND_AREA_B);
WriteCommand(COMMAND_READ_1);
WriteAddress(offset & 0xFF);
WriteAddress((StartSector >> 0) & 0xFF);
WriteAddress((StartSector >> 8) & 0xFF);
WriteAddress((StartSector >> 16) & 0xFF);
此外還要說明的是,該Flash的擦寫是以Block為邊界的,這和一般的NandFlash以扇區為邊界不同,但是擦寫機關都為一個Block,這是相同的。是以這部分代碼在Porting時要和以前平台的驅動要有些差別。
在NativeSample.proj檔案中添加如下條目,就可以測試我們的NandFlash代碼了。
<ItemGroup>
<RequiredProjects Include="$(SPOCLIENT)/Solutions/Stm3210e/DeviceCode/Blockstorage/addDevices/dotNetMF.proj" />
<DriverLibs Include="BlockStorage_AddDevices_NandFlash.$(LIB_EXT)" />
</ItemGroup>
<ItemGroup>
<RequiredProjects Include="$(SPOCLIENT)/Solutions/Stm3210e/DeviceCode/Blockstorage/NandFlash/Driver/dotNetMF.proj" />
<DriverLibs Include="NandFlash_BL.$(LIB_EXT)" />
<ItemGroup>
<RequiredProjects Include="$(SPOCLIENT)/Solutions/Stm3210e/DeviceCode/Blockstorage/NandFlash/Config/dotNetMF.proj" />
<DriverLibs Include="NandFlash_BL_Config.$(LIB_EXT)" />
NativeSample.cpp中的測試代碼如下:
BlockStorageDevice *device= BlockStorageList::GetFirstDevice();
if(device!=NULL)
{
UINT8 bytRet= device->EraseBlock(0x0); //0x20000
debug_printf("EraseBlock:%s/r/n",bytRet? "OK":"ERROR");
BYTE bytWriteData[10];
for(int i=0;i<10;i++) bytWriteData[i]=(BYTE)(i % 256);
bytRet=device->Write(10,10,bytWriteData,FALSE);
debug_printf("Write:%s/r/n",bytRet? "OK":"ERROR");
bytRet=device->Write(30,10,bytWriteData,FALSE);
bytRet=device->Write(513,10,bytWriteData,FALSE);
BYTE bytReadData[1024];
bytRet=device->Read(5,1024,bytReadData);
debug_printf("Read:%s/r/n",bytRet? "OK":"ERROR"); }
好了,NandFlash驅動我們編寫完畢,下一篇将介紹SysTick驅動的實作。