NXP JN5169 讀寫片外 FLASH
NXP JN5169 讀寫片外 FLASH
一、原理圖
二、讀寫相容的片外 FLASH 裝置
JN5169 相容的片外 FLASH 裝置如下表所示:
製造商 | Flash 器件 | 扇區數 | 扇區大小(KB) | 總大小(KB) |
---|---|---|---|---|
Atmel | AT25F512 | 2 | 32 | 64 |
STMicroelectronics | M25P05A | 2 | 32 | 64 |
Microchip | SST25VF010A | 4 | 32 | 128 |
STMicroelectronics | M25P10A | 4 | 32 | 128 |
STMicroelectronics | M25P20 | 4 | 64 | 256 |
Winbond | W25X20B | 4 | 64 | 256 |
STMicroelectronics | M25P40 | 8 | 64 | 512 |
Winbond | W25X40(因為M25P40相容W25X40,所以JN5169也相容W25X40) | 8 | 64 | 512 |
這裡以讀寫 W25X40 為例:
PUBLIC void AppColdStart (void)
{
uint8 i, write[64], read[64];
/*等待系統時鐘切換為外部32MHz晶振*/
while (bAHI_GetClkSource() == TRUE);
/*優化快閃記憶體等待狀態*/
vAHI_OptimiseWaitStates();
vAHI_WatchdogStop();
(void)u32AHI_Init();
vUartInit();
vAHI_DelayXms(2000);
for(i = 0; i < 64; i++){
write[i] = i + 64;
}
//呼叫的第一個 Flash 儲存器函式必須是初始化函式 bAHI_FlashInit()。
//在外部 Flash 儲存器的情況下,這個函式要求指定附加的 Flash 器件型別。
//使用ST M25P40,相容華邦 W25X40,512KB
if(bAHI_FlashInit(E_FL_CHIP_ST_M25P40_A, NULL)){
vPrintf("片外FLASH初始化成功!\n");
}
else{
vPrintf("片外FLASH初始化失敗!\n");
return;
}
/**
* W25X40扇區數8(範圍0到7)
* W25X40的每個扇區均為64KB。 不得執行對非空白頁面字的寫入。
* 寫入非空白頁面字的扇區首先應使用bAHI_FlashEraseSector()擦除,然後再寫入該頁面字。
* 如果使用者省略了扇區擦除操作,則從頁字讀取時可能會導致後續錯誤
* 此讀取錯誤將觸發中斷並執行使用bAHI_FlashEECerrorInterruptSet()註冊的回撥函式。
* W25X40 64KB扇區擦除時間典型值1秒,最大值2秒
* 整片擦除典型值5秒,最大值10秒
*/
if(bAHI_FlashEraseSector(0)){
vPrintf("擦除扇區0成功!\n");
}
else{
vPrintf("擦除扇區0失敗!\n");
return;
}
vAHI_DelayXms(1500); //等待擦除完成
/**
* 該功能通過將1到0的相應位清零來對快閃記憶體塊進行程式設計。該功能可用於訪問相容快閃記憶體裝置的任何扇區。
* 此函式只能用於寫入包含16個位元組的倍數的資料塊,並且該塊必須寫入16位元組的邊界。
* 此機制不允許將位元設定為0到1。只能通過擦除整個扇區將位元設定為1
* 因此,在使用此功能之前,必須呼叫函式bAHI_FlashEraseSector()。
* W25X40 絕對地址為0x000000 ~ 0x07FFFF(共0x80000,512kB)
* 一個扇區大小為65536(0x10000,64KB),所以第0扇區絕對地址為0x000000 ~ 0x00FFFF
*/
//向扇區0寫入64個位元組資料
if(bAHI_FullFlashProgram(0x000000, 64, write)){
vPrintf("向扇區0寫入資料成功!\n");
}
else{
vPrintf("向扇區0寫入資料失敗!\n");
return;
}
vPrintf("寫入扇區0的資料為 = ");
for(i = 0; i < 64; i++){
vPrintf(" %x", write[i]);
}
vPrintf("\n");
while (1) {
//從扇區0讀取64個位元組資料
bAHI_FullFlashRead(0x000010, 64, read);
vPrintf("扇區0的資料為 = ");
for(i = 0; i < 64; i++){
vPrintf(" %x", read[i]);
}
vPrintf("\n");
vAHI_DelayXms(2000);
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
效果圖:
三、讀寫不相容的片外 FLASH 裝置
常用 25/26 Flash 系列器件型號、ID、容量對照表
tSPIflashFncTable(JenOS Structures) 用法見 JN-UG-3075 第 174 頁。
這裡以讀寫 LE25FU406C(512KB) 為例:
#define FLASH_PAGE_SIZE 256
#define MSB FALSE //spi從最高位開始傳輸
#define LSB TRUE //spi從最低位開始傳輸
#define WP 1 << 2
#define HOLD 1 << 3
#define READ_DATA 0x03
#define CHIP_ERASE 0xC7
#define PAGE_PROGRAM 0x02
#define WRITE_ENABLE 0x06
#define STATUS_READ 0x05
#define STATUS_WRITE 0x01
#define READ_RDID 0x9F
#define SECTOR_ERASE 0xD8
tSPIflashFncTable FlashTable;
//初始化IO
PRIVATE void vDIOInit (void)
{
vAHI_DioSetDirection(0, WP | HOLD);
vAHI_DioSetPullup(WP | HOLD, 0);
vAHI_DioSetOutput(WP | HOLD, 0);
}
//SPI傳輸接收1個位元組
PUBLIC uint8 vSPI_Transfer_1Byte(uint8 dat)
{
uint8 ReceiveData = 0;
while(bAHI_SpiPollBusy()); /* 等待匯流排空閒 */
vAHI_SpiStartTransfer(7, dat); /* 傳送7+1=8位資料 */
while(bAHI_SpiPollBusy()); /* 等待資料傳送完畢 */
ReceiveData = u8AHI_SpiReadTransfer8(); /* 讀8位資料 */
return (ReceiveData); /* 返回接收到的資料 */
}
/**
* @Description 初始化用於Flash訪問的變數。
* @parameter iDivisor 時鐘除數
* @parameter u8SlaveSel 用於從機選擇的位元組
*/
PRIVATE void vSPIflashInit(int iDivisor, uint8 u8SlaveSel)
{
vAHI_SpiConfigure(u8SlaveSel, //從機數量1
MSB, //高位傳輸
FALSE, //SPI模式0
FALSE,
iDivisor,
FALSE, //禁止SPI中斷
FALSE); //禁止自動選擇從機
}
PRIVATE void vSPIflashSetSlaveSel(uint8 u8SlaveSel)
{
}
//啟用對Flash的寫入。 在擦除或程式設計Flash之前呼叫。
PRIVATE void vSPIflashWREN(void)
{
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(WRITE_ENABLE);
vAHI_SpiSelect(0); //釋放從機
}
//使能對Flash狀態暫存器的寫入。 在寫入快閃記憶體狀態暫存器之前呼叫。
PRIVATE void vSPIflashEWRSR(void)
{
}
//讀取Flash狀態暫存器並返回Flash暫存器資料
PRIVATE uint8 u8SPIflashRDSR(void)
{
uint8 status;
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(STATUS_READ);
status = vSPI_Transfer_1Byte(0xFF);
vAHI_SpiSelect(0); //釋放從機
return (status);
}
//讀取Flash ID暫存器並返回ID暫存器資料,錯誤時為0或2個位元組[ManufacturerId,DeviceId]
PRIVATE uint16 u16SPIflashRDID(void)
{
uint8 ManufacturerId = 0, DeviceId = 0;
//uint8 Capacity;
uint16 ID;
while(u8SPIflashRDSR() & 0x01);//檢測是否空閒
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(READ_RDID);
ManufacturerId = vSPI_Transfer_1Byte(0xFF);
DeviceId = vSPI_Transfer_1Byte(0xFF);
vSPI_Transfer_1Byte(0xFF); //Capacity(容量)
vAHI_SpiSelect(0); //釋放從機
ID = ManufacturerId <<8 | DeviceId;
return (ID);
}
/**
* @Description 將資料寫入 Flash 狀態暫存器
* @parameter u8Data 狀態暫存器資料
*/
PRIVATE void vSPIflashWRSR(uint8 u8Data)
{
vSPIflashWREN();//寫使能
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(STATUS_WRITE);
vSPI_Transfer_1Byte(u8Data);
vAHI_SpiSelect(0); //釋放從機
while(u8SPIflashRDSR() & 0x01);//寫完畢
}
/**
* @Description 將資料寫入Flash
* @parameter u32Addr 地址
* @parameter u16Len 資料長度(位元組)
* @parameter pu8Data 寫入的資料指標
*/
PRIVATE void vSPIflashPP(uint32 u32Addr, uint16 u16Len, uint8* pu8Data)
{
uint8 addr1, addr2, addr3, i;
uint16 j, dic_len;
addr1 = (u32Addr & 0x00FF0000) >> 8 >> 8;
addr2 = (u32Addr & 0x0000FF00) >> 8;
addr3 = u32Addr & 0xFF;
if((addr3 % 16) != 0){ //必須在16位元組邊界上
return;
}
if(u16Len > 0x1000 || u16Len < 1){ //最高為0x1000(1 - 4096)
return;
}
if((u16Len % 16) != 0){ //必須為16的倍數
return;
}
dic_len = FLASH_PAGE_SIZE - addr3; //起始地址頁剩餘空間
if(dic_len >= u16Len){ //頁剩餘空間大於待寫入位元組數
vSPIflashWREN();//寫使能
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(PAGE_PROGRAM);
vSPI_Transfer_1Byte(addr1);
vSPI_Transfer_1Byte(addr2);
vSPI_Transfer_1Byte(addr3);
for(i = 0; i < u16Len; i++){
vSPI_Transfer_1Byte(*pu8Data++);
}
vAHI_SpiSelect(0); //釋放從機
while(u8SPIflashRDSR() & 0x01);//寫完畢
}
else{ //頁剩餘空間小於待寫入位元組數
vSPIflashWREN();//寫使能
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(PAGE_PROGRAM);
vSPI_Transfer_1Byte(addr1);
vSPI_Transfer_1Byte(addr2);
vSPI_Transfer_1Byte(addr3);
for(i = 0; i < dic_len; i++){
vSPI_Transfer_1Byte(*pu8Data++);
}
vAHI_SpiSelect(0); //釋放從機
while(u8SPIflashRDSR() & 0x01);//寫完畢
u16Len = u16Len - dic_len; //剩餘未寫入位元組數
//跨頁寫
j = 1;
while(u16Len >= FLASH_PAGE_SIZE){ //剩餘未寫入位元組數大於等於一頁位元組數
vSPIflashWREN();//寫使能
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(PAGE_PROGRAM);
vSPI_Transfer_1Byte(addr1);
vSPI_Transfer_1Byte(addr2);
vSPI_Transfer_1Byte(addr3);
for(i = 0; i < FLASH_PAGE_SIZE; i++){
vSPI_Transfer_1Byte(*pu8Data++);
}
vAHI_SpiSelect(0); //釋放從機
while(u8SPIflashRDSR() & 0x01);//寫完畢
j++; //下一頁
u16Len = u16Len - FLASH_PAGE_SIZE; //剩餘未寫入位元組數
}
//剩餘未寫入位元組數小於一頁位元組數
vSPIflashWREN();//寫使能
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(PAGE_PROGRAM);
vSPI_Transfer_1Byte(addr1);
vSPI_Transfer_1Byte(addr2);
vSPI_Transfer_1Byte(addr3);
for(i = 0; i < u16Len; i++){
vSPI_Transfer_1Byte(*pu8Data++);
}
vAHI_SpiSelect(0); //釋放從機
while(u8SPIflashRDSR() & 0x01);//寫完畢
u16Len = u16Len - FLASH_PAGE_SIZE; //剩餘未寫入位元組數
}
vPrintf("寫入扇區0的資料為 = ");
pu8Data = pu8Data - u16Len;
for(i = 0; i < u16Len; i++){
vPrintf(" %x", *pu8Data++);
}
vPrintf("\n");
}
/**
* @Description 從Flash讀取資料。
* @parameter u32Addr 地址
* @parameter u16Len 資料長度(位元組)
* @parameter pu8Data 存放讀取的資料指標
*/
PRIVATE void vSPIflashRead(uint32 u32Addr,uint16 u16Len,uint8* pu8Data)
{
uint8 addr1, addr2, addr3, i;
addr1 = (u32Addr & 0x00FF0000) >> 8 >> 8;
addr2 = (u32Addr & 0x0000FF00) >> 8;
addr3 = u32Addr & 0xFF;
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(READ_DATA);
vSPI_Transfer_1Byte(addr1);
vSPI_Transfer_1Byte(addr2);
vSPI_Transfer_1Byte(addr3);
for(i = 0; i < u16Len; i++){
*pu8Data++ = vSPI_Transfer_1Byte(0xFF);
}
vAHI_SpiSelect(0); //釋放從機
pu8Data = pu8Data - u16Len;
vPrintf("扇區 0、1 的資料為 = ");
for(i = 0; i < u16Len; i++){
vPrintf(" %x", *pu8Data++);
}
pu8Data = pu8Data - u16Len;
}
//執行Flash的批量擦除,整片擦除
PRIVATE void vSPIflashBE(void)
{
vSPIflashWREN();//寫使能
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(CHIP_ERASE); //C7/60
vAHI_SpiSelect(0); //釋放從機
while(u8SPIflashRDSR() & 0x01);//擦完畢
}
//執行Flash的扇區擦除,0-7,一個扇區64KB
PRIVATE void vSPIflashSE(uint8 u8Sector)
{
uint8 addr1, addr2, addr3;
if(u8Sector >= 8){
return;
}
addr1 = u8Sector;
addr2 = 0x00;
addr3 = 0x00;
vPrintf("開始擦除扇區 %d ...\n", u8Sector);
vSPIflashWREN();//寫使能
vAHI_SpiSelect(1); //選擇從機
vSPI_Transfer_1Byte(SECTOR_ERASE);
vSPI_Transfer_1Byte(addr1);
vSPI_Transfer_1Byte(addr2);
vSPI_Transfer_1Byte(addr3);
vAHI_SpiSelect(0); //釋放從機
while(u8SPIflashRDSR() & 0x01);//擦完畢
}
//自定義一組與FLASH互動的函式
PUBLIC void vInitFlashTable(void)
{
FlashTable.u32Signature = 0x12345678; //
FlashTable.u16FlashId = 0x6206; //(u8ManufactureId << 8) | u8DeviceId
FlashTable.u16Reserved = 0x0000; //保留,一般不使用
FlashTable.vZSPIflashInit = vSPIflashInit; //初始化用於Flash訪問的變數
FlashTable.vZSPIflashSetSlaveSel = vSPIflashSetSlaveSel;
FlashTable.vZSPIflashWREN = vSPIflashWREN;//啟用對Flash的寫入。 在擦除或程式設計Flash之前呼叫。
FlashTable.vZSPIflashEWRSR = vSPIflashEWRSR;//使能對Flash狀態暫存器的寫入。 在寫入Flash狀態暫存器之前呼叫。
FlashTable.u8ZSPIflashRDSR = u8SPIflashRDSR;//讀取Flash狀態暫存器並返回Flash暫存器資料
FlashTable.u16ZSPIflashRDID = u16SPIflashRDID;//讀取Flash ID暫存器並返回ID暫存器資料,錯誤時為0或2個位元組[ManufacturerId,DeviceId]
FlashTable.vZSPIflashWRSR = vSPIflashWRSR;//將資料寫入 Flash 狀態暫存器
FlashTable.vZSPIflashPP = vSPIflashPP;//將資料寫入Flash
FlashTable.vZSPIflashRead = vSPIflashRead;//從Flash讀取資料
FlashTable.vZSPIflashBE = vSPIflashBE;//整片擦除
FlashTable.vZSPIflashSE = vSPIflashSE;//執行Flash的扇區擦除
}
PUBLIC void AppColdStart (void)
{
uint8 i, write[64], read[64];
/*等待系統時鐘切換為外部32MHz晶振*/
while (bAHI_GetClkSource() == TRUE);
/*優化快閃記憶體等待狀態*/
vAHI_OptimiseWaitStates();
vAHI_WatchdogStop();
(void)u32AHI_Init();
vDIOInit();
vUartInit();
vAHI_DelayXms(2000);
for(i = 0; i < 64; i++){
write[i] = i + 64;
}
vInitFlashTable();
FlashTable.vZSPIflashInit(8, 1);//速率1M,從機1
vPrintf("rdid = %x\n", FlashTable.u16ZSPIflashRDID());
vPrintf("status register = %x\n", FlashTable.u8ZSPIflashRDSR());
//呼叫的第一個 Flash 儲存器函式必須是初始化函式 bAHI_FlashInit()。
//在外部 Flash 儲存器的情況下,這個函式要求指定附加的 Flash 器件型別。
//使用LE25FU406C(512KB)
bAHI_FlashInit(E_FL_CHIP_CUSTOM, &FlashTable);
vPrintf("片外FLASH初始化成功!\n");
/**
* LE25FU406C扇區數8(範圍0到7)
* LE25FU406C的每個扇區均為64KB。 不得執行對非空白頁面字的寫入。
* 寫入非空白頁面字的扇區首先應使用bAHI_FlashEraseSector()擦除,然後再寫入該頁面字。
* 如果使用者省略了扇區擦除操作,則從頁字讀取時可能會導致後續錯誤
* 此讀取錯誤將觸發中斷並執行使用bAHI_FlashEECerrorInterruptSet()註冊的回撥函式。
* LE25FU406C扇區擦除時間典型值80ms,最大值250ms
* 整片擦除典型值250ms,最大值1.6秒
*/
if(bAHI_FlashEraseSector(0)){
vPrintf("擦除扇區0成功!\n");
}
else{
vPrintf("擦除扇區0失敗!\n");
return;
}
vAHI_DelayXms(1500); //等待擦除完成
/**
* 該功能通過將1到0的相應位清零來對快閃記憶體塊進行程式設計。該功能可用於訪問相容快閃記憶體裝置的任何扇區。
* 此函式只能用於寫入包含16個位元組的倍數的資料塊,並且該塊必須寫入16位元組的邊界。
* 此機制不允許將位元設定為0到1。只能通過擦除整個扇區將位元設定為1
* 因此,在使用此功能之前,必須呼叫函式bAHI_FlashEraseSector()。
* LE25FU406C 絕對地址為0x000000 ~ 0x07FFFF(共0x80000,512kB)
* 一個扇區大小為65536(0x10000,64KB),所以第0扇區絕對地址為0x000000 ~ 0x00FFFF
*/
//這裡呼叫bAHI_FullFlashProgram,實際最終呼叫的是FlashTable的vZSPIflashPP函式,也就是自定義的vSPIflashPP
if(bAHI_FullFlashProgram(0x0000E0, 64, write)){
vPrintf("向扇區0、1寫入資料成功!\n");
}
else{
vPrintf("向扇區0、1寫入資料失敗!\n");
return;
}
vAHI_DelayXms(5);
while (1) {
//從扇區0讀取64個位元組資料
//這裡呼叫bAHI_FullFlashRead
//實際最終呼叫的是FlashTable的vZSPIflashRead函式,也就是自定義的vSPIflashRead
bAHI_FullFlashRead(0x0000E0, 64, read);
vPrintf("\n");
vAHI_DelayXms(2000);
}
}
PUBLIC void AppWarmStart (void)
{
AppColdStart();
}
效果圖:
相關文章
- flash外掛怎麼安裝 電腦安裝flash外掛步驟
- [外掛擴充套件]ajax圖片上傳外掛,支援拖放,無flash,採用fineuploader修改,後期會加入圖片剪下套件
- Air201模組入門:掌握SPI讀寫外部Flash的技巧AI
- NXP ECSPI controller簡介Controller
- WIN10在哪開啟Flash外掛 win10系統flash外掛怎麼啟用Win10
- 前端手勢控制圖片外掛書寫四(圖片上傳及Ios圖片方向問題)前端iOS
- 樹莓派4B-SPI讀寫flash-FM25CL16B(同時支援FM25CL64等其它系列Flash)樹莓派
- win10系統flash外掛崩潰怎麼辦_win10 flash外掛出現異常修復方法Win10
- flash外掛對電腦有影響嗎 新電腦有沒有必要裝flash
- win10自帶flash怎麼更新 window10系統flash外掛如何更新Win10
- [外掛擴充套件]幻燈片 | 滾動圖片 外掛套件
- 記一次 spinor flash 讀速度優化優化
- flash helper service可以解除安裝嗎 win10怎麼徹底刪除flash外掛Win10
- 讀寫
- 黑客稱Flash外掛才是瀏覽器漏洞禍首黑客瀏覽器
- discuz 配置讀寫分離(主寫從讀)
- octobercms 圖片裁剪外掛
- 讀寫鎖
- POI讀寫
- 讀取本地圖片地圖
- 資料讀寫壓力大,讀寫分離
- Python中檔案的讀寫、寫讀和追加寫讀三種模式的特點Python模式
- [外掛擴充套件]圖片輪播外掛套件
- 編寫node 外掛
- egg外掛編寫
- eggjs外掛編寫JS
- 編寫jq外掛
- win10 edge瀏覽器如何安裝flash_win10 edge瀏覽器安裝flash外掛教程Win10瀏覽器
- Win10系統刪除Adobe Flash Player外掛的方法Win10
- 圖片隱寫總結
- 讀寫鎖 ReentrantReadWriteLock
- NTFS讀寫工具
- python 讀寫 excelPythonExcel
- Sanic Cookies 讀寫Cookie
- python讀寫csvPython
- Pythonopen讀和寫Python
- [外掛擴充套件]廣告圖片漂浮外掛套件
- Mac如何讀寫NTFS硬碟?NTFSTool讓Mac讀寫NTFS硬碟Mac硬碟