關於AT25DF041B的flash芯片的讀寫驅動

最近公司採購了一批AT25DF041B的外掛FLASH芯片用來存儲數據,說讓我負責該芯片的驅動程序的編寫。但是我拿到芯片發現這芯片的代碼資料幾乎沒有,MD,完全從頭摸索,浪費了我3天!之前一直用W25Q系列的flash芯片,本以爲都是spi的驅動,但是還是有一些差別的需要自己去摸索!好了,廢話不多說,迴歸正題!

芯片信息:

供電電壓:1.65V - 3.6V Supply

支持的spi模式:SPI Modes 0 and 3

最大操作頻率:104MHz Maximum Operating Frequency

頁大小:256 Bytes

硬件連接:

這款芯片有8個腿,其中的WP和HOLD引腳可以直接懸空用即可!

 

接下來講解大家最想要的信息,軟件如何驅動它?

(1)讀取AT25DF041B芯片的flash的ID

經常寫flash驅動的工程師都知道,想驅動一款芯片,最先要做的事情就是先把該芯片的ID給讀出來!只有先讀出來芯片ID,然後再寫其他驅動纔有意義,因爲只有讀出了ID,至少說明你的spi時序沒問題,硬件連接沒問題,片子是好用的,MCU也沒問題!接下來爲使用這款片子才能無後顧之憂!那麼怎麼讀他的ID呢?查詢手冊發現:

從上圖我們得知,要想讀它的ID,只需要通過spi發送0x9F即可!等發送完0x9F之後,隨即發送4個空字節(一般是0xFF),芯片便會將自己的ID返回給spi主設備!代碼如下所示:

/*******************************************************************************
* Function Name  : SPI_FLASH_ReadID
* Description    : Reads FLASH identification.
* Input          : None
* Output         : None
* Return         : FLASH identification
*******************************************************************************/
u32 SPI_FLASH_ReadDeviceID(void)
{
    u32 Temp = 0;
    u8 temp1,temp2,temp3,temp4;

  /* Select the FLASH: Chip Select low */
    SPI_FLASH_CS_LOW();    
  /* Send "RDID " instruction */
    SPI_FLASH_SendByte(0x9F);
    
  /* Read a byte from the FLASH */
    temp1 = SPI_FLASH_SendByte(Dummy_Byte);
    temp2 = SPI_FLASH_SendByte(Dummy_Byte);
    temp3 = SPI_FLASH_SendByte(Dummy_Byte);
    temp4 = SPI_FLASH_SendByte(Dummy_Byte);    
  /* Deselect the FLASH: Chip Select high */
  SPI_FLASH_CS_HIGH();

    Temp = (temp1<<24)|(temp2<<16)|(temp3 << 8)|(temp4);
  return Temp;
}

通過以上函數,就可以將我們的芯片ID給讀出來了,如果還是沒有讀到自己ID的小夥伴,清檢查下你的硬件連接或spi程序配置吧!

(2)flash讀寫測試

我之前搞這東西,就在flash讀寫上面浪費了我3天時間,因爲這芯片真的很奇葩。接下來看它爲什麼奇葩。。

按照我之前一直使用W25Qxx的flash芯片讀寫經驗,再用到這上面發現時鐘無法進行讀寫。畢竟按照正常人的思維,使用flash寫之前,應該先進行擦除,然後再進行寫,然後讀!套路都懂,可就是讀不出來,爲什麼呢?於是就蹲在實驗室,抱着示波器反覆修改自己的spi讀寫速率,或是修改cs拉低之後的延時,發現都沒什麼卵用!都想要放棄了,後來晚上抽了3個小時,硬着頭皮翻閱芯片器件手冊,52頁的pdf文檔全部看完,終於發現了一個驚天大祕密,發現原來該芯片在上電後的讀寫擦之前,需要先解鎖。MD,心中頓時一萬隻草泥馬!雖然很氣,但是還是爲自己的問題得以解決感覺很高興!(希望看完有收穫的朋友看完下面點個贊或者留個言,謝謝!

就是上面這段英文,說芯片在上電或者復位之後,所有的扇區的保護寄存器默認被置1,也就是處於鎖定的狀態,想要寫入或者擦除前,請先解鎖!

2.1 flash解鎖

我用的解鎖是把該flash芯片進行了全局解鎖,代碼如下所示:

void Global_Unlock()
{
  SPI_FLASH_WriteEnable();
  SPI_FLASH_WaitForWriteEnd();

  SPI_FLASH_CS_LOW();
  /* Send "Write to Memory " instruction */
  SPI_FLASH_SendByte(0x01);
  /* Send WriteAddr high nibble address byte to write to */
  SPI_FLASH_SendByte(0x00);
  SPI_FLASH_CS_HIGH();
}

CS使能之後先發送一個0x01,隨即再發送一個0x00,CS再失能就OK了,雖然簡單,但是如果不仔細翻閱手冊,根本不知道。

有了這一步,就可以對flash進行快樂的讀寫嘍!

2.2 FLASH按頁寫:

void SPI_FLASH_PageWrite(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{
  /* Enable the write access to the FLASH */
  SPI_FLASH_WriteEnable();
    
    //Delay(100);
  /* Select the FLASH: Chip Select low */
  SPI_FLASH_CS_LOW();
  /* Send "Write to Memory " instruction */
  SPI_FLASH_SendByte(AT25DF041_PageProgram);  
  /* Send WriteAddr high nibble address byte to write to */
  SPI_FLASH_SendByte((WriteAddr ) >> 16);   //& 0xFF0000
  /* Send WriteAddr medium nibble address byte to write to */
  SPI_FLASH_SendByte((WriteAddr) >> 8);    // & 0xFF00
  /* Send WriteAddr low nibble address byte to write to */
  SPI_FLASH_SendByte(WriteAddr);  // & 0xFF

  if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
  {
     NumByteToWrite = SPI_FLASH_PerWritePageSize;
     //printf("\n\r Err SPI_FLASH_PageWrite too large!");
  }

  /* while there is data to be written on the FLASH */
  while (NumByteToWrite--)
  {
    /* Send the current byte */
    SPI_FLASH_SendByte(*pBuffer);
    /* Point on the next byte to be written */
    pBuffer++;
  }

  /* Deselect the FLASH: Chip Select high */
  SPI_FLASH_CS_HIGH();
  /* Wait the end of Flash writing */
  SPI_FLASH_WaitForWriteEnd();
}

2.3 FLASH批量讀:

void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)
{
  /* Select the FLASH: Chip Select low */
  SPI_FLASH_CS_LOW();
  /* Send "Read from Memory " instruction */
  SPI_FLASH_SendByte(AT25DF041_ReadData);  //0x03   AT25DF041_ReadData

  /* Send ReadAddr high nibble address byte to read from */
  SPI_FLASH_SendByte((ReadAddr) >> 16);  // & 0xFF0000
  /* Send ReadAddr medium nibble address byte to read from */
  SPI_FLASH_SendByte((ReadAddr) >> 8);   //& 0xFF00
  /* Send ReadAddr low nibble address byte to read from */
  SPI_FLASH_SendByte(ReadAddr & 0xFF);   //& 0xFF

    //SPI_FLASH_SendByte(Dummy_Byte);   
    
  while (NumByteToRead--) /* while there is data to be read */
  {
    /* Read a byte from the FLASH */
    *pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
    /* Point to the next location where the byte read will be saved */
    pBuffer++;
  }

  /* Deselect the FLASH: Chip Select high */
  SPI_FLASH_CS_HIGH();
}

2.4 FLASH按頁擦除:

void Page_Erase(u16 PageNum) 
{
    SPI_FLASH_WriteEnable();
    SPI_FLASH_WaitForWriteEnd();
    SPI_FLASH_CS_LOW();
    SPI_FLASH_SendByte(0x81);
    //SPI_FLASH_SendByte(0xff & ((PageNum & 0x700)>>8));
    SPI_FLASH_SendByte(PageNum >> 8);
    
    SPI_FLASH_SendByte(PageNum & 0xff);
    SPI_FLASH_SendByte(Dummy_Byte);
    SPI_FLASH_CS_HIGH();
    SPI_FLASH_WaitForWriteEnd(); 
}

至此AT25DF041B芯片需要注意的地方就全部寫完了!看完的朋友如果感覺有幫助,請留下您的腳印哦!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章