使用了MX25L512的SPI接口的Flash
電路連接配接圖:
總的大小512kb,即64kB,sector的大小為256 Bytes,block的大小為4k Bytes
調試時出現的問題:
1、Flash隻能讀資料,不能寫資料
根源在于Flash的軟體寫保護沒有去掉,這樣,寫、擦除,甚至寫狀态寄存器都不能執行。
1)Hardware Protection
Hardware Protection Mode(HPM):by using WP# going low to protect the BP0-BP1 bits and SRWD bit from data change
因為WP#是高電平,是以沒有硬體保護,再來看軟體保護。
2)Software Protection
Software Protection Mode(SPM):by using BP0-BP1 bits to set the part of flash protected from data change
通過下面幾幅圖可知,在WP#高電平情況下write status register可以改變SRWD、BP0、BP1的值為0,進而去掉軟體寫保護。
3)代碼實作去除保護
//在所有需要修改的操作之前必須去除軟體保護BP0,BP1
//FLASH的狀态寄存器
//bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
//SRWD 0 0 0 BP1 BP0 WEL WIP
// 1=status write disable 1=write enable 1=write in process
#define MASK_CLEAR_BPX 0x73 //掩碼,設定使能寫狀态寄存器,清除BP1、BP0
void SPI_WRITE_STATUS() //主要是清除保護,可以寫資料
{
unsigned char status=0;
SPI_WRITE_ENABLE(); //設定狀态器WEL位為1,在進行寫狀态寄存器之前必須寫使能
status=SPI_READ_STATUS();
NSSMD0=0;
SPI0DAT=FLASH_WRITE_STATUS;
while(!SPIF);
SPIF=0;
SPI0DAT=status&MASK_CLEAR_BPX;
while(!SPIF);
SPIF=0;
NSSMD0=1;//cs must go high at the byte boundary,otherwise instruction will be reject and not executed
do //query until WIP convert from 1 to 0 when write status register cycle is finished
{
status=SPI_READ_STATUS();
status=status&0x01;
}while(status);
}
2、sector大小為256 Bytes,但是連續寫256 Bytes,隻有最後的32 Bytes寫進去了
在測試MX25L512的扇區的時候,老是遇到一個問題,寫入256個位元組,但是讀出的是最後32個Bytes,前面的總是0xFF,于是就懷疑是不是扇區
的大小沒有datasheet所說的那麼大呢?最後測試發現扇區的大小隻有32Bytes,如果連續寫入的位元組數大于32 Bytes,就會把除最後32 Bytes之外
的資料丢棄,隻寫最後的32 Bytes。仔細翻看datasheet,發現MX25L512MC-12G的扇區為256 Bytes,而MX25L512IE的扇區隻有32Bytes原來具體
晶片規格和元件字尾名也有關系。
說明:sector是讀寫資料的最小單元,block是擦除的最小單元。(有時候sector概念類似于page,要看具體的晶片)
扇區被擦除後内部的資料變為0xFF。
3、SPI接口波形不對
雖然C8051F320已經交叉配置為序列槽和SPI接口,但是實際情況是還是要在輸出的管腳PushPull,
P0MDOUT=0x1D;//0001 1101
#ifndef _SPI_CMD_H_
#define _SPI_CMD_H_
#include"misc.h"
//MX25L512的flash說明///
//page:256byte
//sector:4kbyte
//注意MX25L512MC-12G page為256 bytes
//MX25L512IE.. page為32 bytes
///
#define FLASH_READ_ID 0x9F //讀裝置ID
#define FLASH_WRITE_ENABLE 0x06 //寫使能
#define FLASH_WRITE_DISABLE 0x04 //寫禁止
#define FLASH_READ_STATUS 0x05 //讀狀态寄存器
#define FLASH_WRITE_STATUS 0x01 //寫狀态寄存器
#define FLASH_READ_DATA 0x03 //讀資料
#define FLASH_WRITE_DATA 0x02 //寫資料
#define FLASH_SECTOR_ERASE 0x20 //擦除一個扇區
extern unsigned char xdata buff[256];//緩沖區全局變量,可以儲存一個page的256位元組
//在頭檔案中隻是申明一下,不能定義,定義變量要在相應的C檔案中定義
//以上不然會報錯:multiple public definitions
void SPI_READ_ID();
void SPI_WRITE_ENABLE();
void SPI_WRITE_DISABLE();
unsigned char SPI_READ_STATUS();
void SPI_WRITE_STATUS();
void SPI_SECTOR_ERASE(unsigned char sectors);
void SPI_READ_Page(unsigned char sectors,unsigned char pages);
void SPI_WRITE_Page(unsigned char *str,unsigned char sectors,unsigned char pages);
void FillDBR();
#endif
#include"SPI_CMD.h"
//#define SPI0INT(x) {SPI0DAT=x;while(!SPIF);SPIF=0;}
//可以用這個定義來取代以下一大段的代碼
//SPI0DAT=FLASH_READ_ID;
//while(!SPIF); ----->SPI0DAT=FLASH_READ_ID;
//SPIF=0;
void SPI_READ_ID()
{
NSSMD0=0;
SPI0DAT=FLASH_READ_ID;
while(!SPIF);
SPIF=0;
SPI0DAT=0; //dummy write to output serial clock
while(!SPIF); //wait for value to be read
SPIF=0;
sendChar(SPI0DAT);
SPI0DAT=0;
while(!SPIF);
SPIF=0;
sendChar(SPI0DAT);
SPI0DAT=0;
while(!SPIF);
SPIF=0;
sendChar(SPI0DAT);
NSSMD0=1;
}
void SPI_WRITE_ENABLE()
{
NSSMD0=0;
SPI0DAT=FLASH_WRITE_ENABLE;
while(!SPIF);
SPIF=0;
NSSMD0=1;
}
void SPI_WRITE_DISABLE()
{
NSSMD0=0;
SPI0DAT=FLASH_WRITE_DISABLE;
while(!SPIF);
SPIF=0;
NSSMD0=1;
}
unsigned char SPI_READ_STATUS()
{
NSSMD0=0;
SPI0DAT=FLASH_READ_STATUS;//可以将類似的這種形式做成一個宏定義
while(!SPIF);
SPIF=0;
SPI0DAT=0;
while(!SPIF);
SPIF=0;
NSSMD0=1;
return SPI0DAT;
}
//在所有需要修改的操作之前必須去除軟體保護BP0,BP1
//FLASH的狀态寄存器
//bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
//SRWD 0 0 0 BP1 BP0 WEL WIP
// 1=status write disable 1=write enable 1=write in process
#define MASK_CLEAR_BPX 0x73 //掩碼,設定使能寫狀态寄存器,清除BP1、BP0
void SPI_WRITE_STATUS() //主要是清除保護,可以寫資料
{
unsigned char status=0;
SPI_WRITE_ENABLE(); //設定狀态器WEL位為1,在進行寫狀态寄存器之前必須寫使能
status=SPI_READ_STATUS();
NSSMD0=0;
SPI0DAT=FLASH_WRITE_STATUS;
while(!SPIF);
SPIF=0;
SPI0DAT=status&MASK_CLEAR_BPX;
while(!SPIF);
SPIF=0;
NSSMD0=1;//cs must go high at the byte boundary,otherwise instruction will be reject and not executed
do //query until WIP convert from 1 to 0 when write status register cycle is finished
{
status=SPI_READ_STATUS();
status=status&0x01;
}while(status);
}
void SPI_SECTOR_ERASE(unsigned char sectors)
{
unsigned char status=0;
SPI_WRITE_ENABLE();
NSSMD0=0;
SPI0DAT=FLASH_SECTOR_ERASE;
while(!SPIF);
SPIF=0;
//any address in the sector,but i choose the first address of sector
SPI0DAT=0x00; //high address
while(!SPIF);
SPIF=0;
SPI0DAT=sectors<<4; //middle address
while(!SPIF);
SPIF=0;
SPI0DAT=0x00; //low address
while(!SPIF);
SPIF=0;
NSSMD0=1;
do //query until WIP convert from 1 to 0 when write status register cycle is finished
{
status=SPI_READ_STATUS();
status=status&0x01;
}while(status);
}
unsigned char xdata buff[256];
//讀一頁256 bytes
void SPI_READ_Page(unsigned char sectors,unsigned char pages)
{
unsigned int i=0;
NSSMD0=0;
SPI0DAT=FLASH_READ_DATA; //command
while(!SPIF);
SPIF=0;
SPI0DAT=0x00; //read address
while(!SPIF);
SPIF=0;
SPI0DAT=(sectors<<4) + pages;
while(!SPIF);
SPIF=0;
SPI0DAT=0x00;
while(!SPIF);
SPIF=0;
for(i=0;i<256;i++) //read a page 256 bytes
{ //實測每頁的資料隻有32byte,是以一次連續寫32byte
SPI0DAT=0; //read datas out
while(!SPIF);
SPIF=0;
buff[i]=SPI0DAT;
}
NSSMD0=1;
}
//寫一頁256 bytes
void SPI_WRITE_Page(unsigned char *str,unsigned char sectors,unsigned char pages)
{
unsigned int i=0;
unsigned char status=0;
SPI_WRITE_ENABLE(); //在改變資料之前都要進行寫使能操作
NSSMD0=0;
SPI0DAT=FLASH_WRITE_DATA; //write command
while(!SPIF);
SPIF=0;
SPI0DAT=0x00; //write address
while(!SPIF); //最高位址預設為0x00,是以不用傳他的參數
SPIF=0;
SPI0DAT=(sectors<<4) + pages;
while(!SPIF);
SPIF=0;
SPI0DAT=0x00;
while(!SPIF);
SPIF=0;
for(i=0;i<256;i++) //write a page 256 bytes
{
SPI0DAT=str[i]; //write data in
while(!SPIF);
SPIF=0;
}
NSSMD0=1;
do //query until WIP convert from 1 to 0 when write cycle is finished
{
status=SPI_READ_STATUS();
status=status&0x01;
}while(status);
}