最近公司採購了一批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芯片需要注意的地方就全部寫完了!看完的朋友如果感覺有幫助,請留下您的腳印哦!