天天看點

電子工程師名片——SPI Flash

使用了MX25L512的SPI接口的Flash

電子工程師名片——SPI Flash

電路連接配接圖:

電子工程師名片——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

電子工程師名片——SPI Flash

因為WP#是高電平,是以沒有硬體保護,再來看軟體保護。

2)Software Protection

Software Protection Mode(SPM):by using BP0-BP1 bits to set the part of flash protected from data change

電子工程師名片——SPI Flash

通過下面幾幅圖可知,在WP#高電平情況下write status register可以改變SRWD、BP0、BP1的值為0,進而去掉軟體寫保護。

電子工程師名片——SPI Flash
電子工程師名片——SPI Flash

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接口波形不對

電子工程師名片——SPI Flash

雖然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);
}