MW22-02A/BSP/Driver/w25q128/fatfs_flash_spi.c

518 lines
14 KiB
C
Raw Permalink Normal View History

2025-05-21 01:55:40 +00:00
////////////////////////////////////////////////////////////////////////////////
/// flash底层驱动
///
///
/// fatfs文件系统用的flsh底层驱动支持w25qxx系列spiflash
/// @file fatfs_flash_spi.c
/// @author gkl
/// @date 2017-04-25
/// @version v0.1
////////////////////////////////////////////////////////////////////////////////
#include "fatfs_flash_spi.h"
#include "w25q128.h"
/// 扇区大小
#define FLASH_SECTOR_SIZE 4096
/// 扇区数量
#ifdef FLASH_W25Q128
/// 16M 16*1024/4096
#define FLASH_SECTOR_COUNT 4096
#endif
#ifdef FLASH_W25Q256
/// 32M 32*1024/4096
#define FLASH_SECTOR_COUNT 8192
#endif
//#define FLASH_BLOCK_SIZE 65536
/// 同时擦除扇区个数
#define FLASH_BLOCK_SIZE 1
static volatile u_int32_t SPITimeout = SPIT_LONG_TIMEOUT;
static volatile DSTATUS TM_FATFS_FLASH_SPI_Stat = STA_NOINIT;
/// 超时函数
static u_int16_t SPI_TIMEOUT_UserCallback(void);
/// 申明函数
static void SPI_FLASH_SendByte(u_int8_t DataBuffer);
static void SPI_FLASH_WaitForWriteEnd(void);
static void SPI_FLASH_WriteEnable(void);
static u_int8_t SPI_FLASH_ReadByte();
static void SPI_FLASH_BufferRead(u_int8_t* pBuffer, u_int32_t ReadAddr, u_int32_t NumByteToRead);
static void SPI_FLASH_BufferWrite(u_int8_t* pBuffer, u_int32_t WriteAddr, u_int16_t WriteBytesNum);
static u_int32_t SPI_FLASH_ReadID();
static void SPI_FLASH_PageWrite(u_int8_t* pBuffer, u_int32_t WriteAddr, u_int16_t NumByteToWrite);
static void SPI_FLASH_SectorErase(u_int32_t SectorAddr);
static void SPI_Flash_GPIO_Init(void);
/// 初始化flsh芯片
/// 初始化单片机IO控制管脚读取JEDEC ID判断芯片是否工作正常
///
/// @param none
/// @param none
/// @return none
/// @note 修改日志
/// gkl与2017-04-25创建
DSTATUS TM_FATFS_FLASH_SPI_disk_initialize(void)
{
// 配置IO管脚初始化flsh芯片
SPI_Flash_GPIO_Init();
#ifdef FLASH_W25Q256
Enter4ByteAddrMode(); //new add 进入4Byte模式
#endif
#ifdef FLASH_W25Q128
Exit4ByteAddrMode(); //new add 退出4Byte模式
#endif
// 读取FLASH出厂唯一ID检测FLASH是否正常功能
if(sFLASH_ID == SPI_FLASH_ReadID()) {
// 正常,清除没有初始化标志
FLASH_INFO("FLASH read JEDEC ID:%02x",sFLASH_ID);
return TM_FATFS_FLASH_SPI_Stat &= ~STA_NOINIT;
} else {
FLASH_ERROR("FLASH read JEDEC ID failed! %02x",sFLASH_ID);
return TM_FATFS_FLASH_SPI_Stat |= STA_NOINIT;
}
}
/// 检测flash状态是否正常是否正常工作
/// 通过读取flash ID来判断芯片是否工作正常每种芯片的该ID号相同
///
/// @param none
/// @param none
/// @return none
/// @note 修改日志
/// gkl与2017-04-25创建
DSTATUS TM_FATFS_FLASH_SPI_disk_status(void)
{
FLASH_DEBUG_FUNC();
if(sFLASH_ID == SPI_FLASH_ReadID()) {
return TM_FATFS_FLASH_SPI_Stat &= ~STA_NOINIT;
} else {
return TM_FATFS_FLASH_SPI_Stat |= STA_NOINIT;
}
}
/// 获取flash相关信息
///
/// @param cmd 命名类型
/// @param *buff 获取到的数据返回值
/// @return 固定返回RES_OK状态
/// @note 修改日志
/// gkl与2017-04-25创建
DRESULT TM_FATFS_FLASH_SPI_disk_ioctl(BYTE cmd, char *buff)
{
FLASH_DEBUG_FUNC();
switch (cmd) {
// 扇区大小
case GET_SECTOR_SIZE :
*(WORD * )buff = FLASH_SECTOR_SIZE;
break;
// 同时擦除扇区个数
case GET_BLOCK_SIZE :
*(DWORD * )buff = FLASH_BLOCK_SIZE;
break;
// 扇区数量
case GET_SECTOR_COUNT:
*(DWORD * )buff = FLASH_SECTOR_COUNT;
break;
case CTRL_SYNC :
break;
default:
break;
}
return RES_OK;
}
/// 磁盘读取数据
///
/// @param *buff 存放读取数据的buff的地址
/// @param sector 读取sector的地址取值012……
/// @param count sector的个数取值012……
/// @return RES_OK 成功 RES_NOTRDY 芯片工作不正常
/// @note 修改日志
/// gkl与2017-04-25创建
DRESULT TM_FATFS_FLASH_SPI_disk_read(BYTE *buff, DWORD sector, UINT count)
{
FLASH_DEBUG_FUNC();
if ((TM_FATFS_FLASH_SPI_Stat & STA_NOINIT)) {
FLASH_ERROR("TM_FATFS_FLASH_SPI_disk_read");
return RES_NOTRDY;
}
// 左移12位将sector数转化为芯片内部存储空间的地址
SPI_FLASH_BufferRead(buff, sector<<12, count<<12);
return RES_OK;
}
/// 磁盘写数据
///
/// @param *buff 写数据buff的地址
/// @param sector 写数据开始sector地址取值012……
/// @param count 写的sector个数
/// @return 固定返回RES_OK
/// @note 修改日志
/// gkl与2017-04-25创建
DRESULT TM_FATFS_FLASH_SPI_disk_write(BYTE *buff, DWORD sector, UINT count)
{
u_int32_t write_addr;
u_int32_t erase_addr;
FLASH_DEBUG_FUNC();
// sector += 512; //new add 前面预留512个sector(512 * 4KB = 2MB)用作他用2M以后的空间用作文件系统
write_addr = sector<<12;
for (u_int8_t i=0; i < count; i++) {
erase_addr = sector<<12;
SPI_FLASH_SectorErase(erase_addr);
sector++;
}
SPI_FLASH_BufferWrite(buff,write_addr,count<<12); //一个sector=4K
return RES_OK;
}
/// 擦除一块sector
///
/// @param SectorAddr sector的块地址取值012……
/// @return none
/// @note 修改日志
/// gkl与2017-04-25创建
static void SPI_FLASH_SectorErase(u_int32_t SectorAddr)
{
SPI_FLASH_WriteEnable();
SPI_FLASH_CS_ENABLE;
SPI_FLASH_SendByte(W25X_Flash_SecErase_CMD);
#ifdef FLASH_W25Q256
SPI_FLASH_SendByte((u_int8_t)((SectorAddr&0xff000000)>>24)); //new add
SPI_FLASH_SendByte((u_int8_t)((SectorAddr&0x00ff0000)>>16));
SPI_FLASH_SendByte((u_int8_t)((SectorAddr&0x0000ff00)>>8));
SPI_FLASH_SendByte((u_int8_t)SectorAddr);
#endif
#ifdef FLASH_W25Q128
SPI_FLASH_SendByte((u_int8_t)((SectorAddr&0x00ff0000)>>16));
SPI_FLASH_SendByte((u_int8_t)((SectorAddr&0x0000ff00)>>8));
SPI_FLASH_SendByte((u_int8_t)SectorAddr);
#endif
SPI_FLASH_CS_DISABLE;
SPI_FLASH_WaitForWriteEnd();
}
/// 擦除整块芯片
/// 手册上说擦除整块需要1s-w25q128
/// @param none
/// @param none
/// @return none
/// @note 修改日志
/// gkl与2017-04-26创建
/// 测试会超时,没有通过
#if 0
static void SPI_FLASH_BulkErase()
{
SPI_FLASH_WriteEnable();
SPI_FLASH_WaitForWriteEnd();
SPI_FLASH_CS_ENABLE;
SPI_FLASH_SendByte(W25X_Flash_ChipErase_CMD);
// 发送完指令后cs必须拉高否则指令不执行
SPI_FLASH_CS_DISABLE;
// The BUSY bit is a 1 during the Chip Erase cycle and becomes a 0 when
// finished and the device is ready to accept
// other instructions again.
SPI_FLASH_WaitForWriteEnd();
}
#endif
/// flash底层驱动-页写
/// 最大支持一页256字节数据写入
///
/// @param pBuffer 指针指向存储写数据的buffer
/// @param WriteAddr 向flash内部写数据的地址
/// @param NumByteToRead 要写入的数据长度
/// @return none
/// @note 修改日志
/// gkl与2017-04-25创建
static void SPI_FLASH_PageWrite(u_int8_t* pBuffer, u_int32_t WriteAddr, u_int16_t NumByteToWrite)
{
if (NumByteToWrite > W25X_Flash_PAGEBYTE_LENGTH) {
NumByteToWrite = W25X_Flash_PAGEBYTE_LENGTH;
FLASH_ERROR("SPI_FLASH_PageWrite too large!");
}
SPI_FLASH_WriteEnable();
SPI_FLASH_CS_ENABLE;
SPI_FLASH_SendByte(W25X_Flash_PageProgram_CMD);
#ifdef FLASH_W25Q256
SPI_FLASH_SendByte((u_int8_t)((WriteAddr&0xff000000)>>24)); //new add
SPI_FLASH_SendByte((u_int8_t)((WriteAddr&0x00ff0000)>>16));
SPI_FLASH_SendByte((u_int8_t)((WriteAddr&0x0000ff00)>>8));
SPI_FLASH_SendByte((u_int8_t)WriteAddr);
#endif
#ifdef FLASH_W25Q128
SPI_FLASH_SendByte((u_int8_t)((WriteAddr&0x00ff0000)>>16));
SPI_FLASH_SendByte((u_int8_t)((WriteAddr&0x0000ff00)>>8));
SPI_FLASH_SendByte((u_int8_t)WriteAddr);
#endif
// while there is data to be written on the FLASH
while (NumByteToWrite--) {
SPI_FLASH_SendByte(*pBuffer);
pBuffer++;
}
SPI_FLASH_CS_DISABLE;
// 每次写入一定数量的数据都要延时等待写入结束
SPI_FLASH_WaitForWriteEnd();
}
/// 连续向芯片写数据
///
/// @param pBuffer 指针指向存储写数据的buffer
/// @param WriteAddr 向flash内部写数据的地址
/// @param NumByteToRead 要写入的数据长度
/// @return none
/// @note 修改日志
/// gkl与2017-04-25创建
static void SPI_FLASH_BufferWrite(u_int8_t* pBuffer, u_int32_t WriteAddr, u_int16_t NumByteToWrite)
{
u_int16_t PageByteRemain = 0;
PageByteRemain = SPI_FLASH_PageSize - WriteAddr%SPI_FLASH_PageSize;
if(NumByteToWrite <= PageByteRemain) {
PageByteRemain = NumByteToWrite;
}
while(1) {
SPI_FLASH_PageWrite(pBuffer,WriteAddr,PageByteRemain);
if(NumByteToWrite == PageByteRemain) {
break;
} else {
pBuffer += PageByteRemain;
WriteAddr += PageByteRemain;
NumByteToWrite -= PageByteRemain;
if (NumByteToWrite > SPI_FLASH_PageSize) {
PageByteRemain = SPI_FLASH_PageSize;
} else {
PageByteRemain = NumByteToWrite;
}
}
}
}
/// 连续从芯片读取数据
///
/// @param pBuffer 指针指向存储接收数据的buffer
/// @param ReadAddr 从flash内部读取数据的地址
/// @param NumByteToRead 要读取的数据长度
/// @return none
/// @note 修改日志
/// gkl与2017-04-25创建
static void SPI_FLASH_BufferRead(u_int8_t* pBuffer, u_int32_t ReadAddr, u_int32_t NumByteToRead)
{
SPI_FLASH_CS_ENABLE;
#ifdef FLASH_W25Q256
SPI_FLASH_SendByte(W25X_Flash_ReadData_CMD);
SPI_FLASH_SendByte((u_int8_t)((ReadAddr&0xff000000)>>24)); //new add
SPI_FLASH_SendByte((u_int8_t)((ReadAddr&0x00ff0000)>>16));
SPI_FLASH_SendByte((u_int8_t)((ReadAddr&0x0000ff00)>>8));
SPI_FLASH_SendByte((u_int8_t)ReadAddr);
#endif
#ifdef FLASH_W25Q128
SPI_FLASH_SendByte(W25X_Flash_ReadData_CMD);
SPI_FLASH_SendByte((u_int8_t)((ReadAddr&0x00ff0000)>>16));
SPI_FLASH_SendByte((u_int8_t)((ReadAddr&0x0000ff00)>>8));
SPI_FLASH_SendByte((u_int8_t)ReadAddr);
#endif
// while there is data to be read
while (NumByteToRead--) {
*pBuffer = SPI_FLASH_ReadByte();
// Point to the next location where the byte read will be saved
pBuffer++;
}
SPI_FLASH_CS_DISABLE;
}
/// 读取FLASH出厂唯一ID
///
/// @param NULL
/// @param NULL
/// @return 返回u32型ID值
/// @note 修改日志
/// gkl与2017-04-25创建
static u_int32_t SPI_FLASH_ReadID()
{
int nID = 0;
SPI_FLASH_CS_ENABLE;
SPI_FLASH_SendByte(W25X_Flash_JedecDeviceID_CMD);
nID = SPI_FLASH_ReadByte();
nID <<= 8;
nID |= SPI_FLASH_ReadByte();
nID <<= 8;
nID |= SPI_FLASH_ReadByte();
SPI_FLASH_CS_DISABLE;
return nID;
}
/// 读取一个字节数据
///
/// @param none
/// @param none
/// @return 读取到的值
/// @note 修改日志
/// gkl与2017-04-25创建
static u_int8_t SPI_FLASH_ReadByte()
{
u_int8_t retValue = 0;
// 时钟线拉高,恢复时钟线为高电平
SPI_FLASH_CLK_HIGH;
for (u_int8_t i= 0; i < 8; i++) {
retValue <<= 1;
SPI_FLASH_CLK_HIGH;
if (SPI_FLASH_DO_READ) {
retValue |= 0x01;
} else {
retValue &= 0xFE;
}
// 时钟线拉低,产生下降沿读出数据
SPI_FLASH_CLK_LOW;
}
SPI_FLASH_CLK_HIGH;
return retValue;
}
/// 写一个字节数据
///
/// @param byte 需写到flash中的数
/// @param none
/// @return 没有用返回值
/// @note 修改日志
/// gkl与2017-04-25创建
static void SPI_FLASH_SendByte(u_int8_t DataBuffer)
{
// 时钟线拉低,恢复时钟线为低电平
SPI_FLASH_CLK_LOW;
for (u_int8_t i = 0; i < 8; i++) {
SPI_FLASH_CLK_LOW;
if (DataBuffer & 0x80) {
SPI_FLASH_DI_HIGH;
} else {
SPI_FLASH_DI_LOW;
}
DataBuffer <<= 1;
// 时钟线拉高,产生上升沿写入数据
SPI_FLASH_CLK_HIGH;
}
SPI_FLASH_CLK_LOW;
// 一字节数据传送完毕MOSI数据线置高表示空闲状态
SPI_FLASH_DI_HIGH;
}
/// 写使能
///
/// @param none
/// @param none
/// @return none
/// @note 修改日志
/// gkl与2017-04-25创建
static void SPI_FLASH_WriteEnable(void)
{
SPI_FLASH_CS_ENABLE;
SPI_FLASH_SendByte(W25X_Flash_WriteEnable_CMD);
SPI_FLASH_CS_DISABLE;
}
/// 等待芯片操作完成
/// 通过读取芯片状态寄存器判断busy来判断芯片上一指令是否操作完成是否可以进行下一指令操作
/// 如果芯片处于busy状态则一直等待超时打印错误信息
///
/// @param none
/// @param none
/// @return none
/// @note 修改日志
/// gkl与2017-04-25创建
static void SPI_FLASH_WaitForWriteEnd(void)
{
u_int8_t FLASH_Status = 0xFF;
SPITimeout = SPIT_LONG_TIMEOUT;
// Loop as long as the memory is busy with a write cycle
do {
SPI_FLASH_CS_ENABLE;
SPI_FLASH_SendByte(W25X_Flash_ReadSR_CMD);
FLASH_Status = SPI_FLASH_ReadByte();
SPI_FLASH_CS_DISABLE;
if ((SPITimeout--) == 0) {
SPI_TIMEOUT_UserCallback();
return;
}
} while ((FLASH_Status & W25X_FLASH_WRITE_BUSYBIT) == 0x01);
FLASH_INFO("time:%d",SPITimeout);
}
/// 出错函数
///
/// @param none
/// @param none
/// @return none
/// @note 修改日志
/// gkl与2017-04-25创建
static uint16_t SPI_TIMEOUT_UserCallback(void)
{
// Block communication and all processes
FLASH_ERROR("SPI Timeout error!");
return 0;
}
/// 初始化flsh gpio管脚
///
/// @param none
/// @param none
/// @return none
/// @note 修改日志
/// gkl与2017-04-26创建
static void SPI_Flash_GPIO_Init(void)
{
drv_gpio_open(PORTB, 4, OUTPUT, 1);//WP
drv_gpio_open(PORTB, 3, OUTPUT, 1);//DI
drv_gpio_open(PORTB, 2, OUTPUT, 1);//CLK
drv_gpio_open(PORTA, 29, OUTPUT, 1);//HOLD
drv_gpio_open(PORTA, 28, OUTPUT, 1);//CS
drv_gpio_open(PORTA, 27, INPUT, 1); //DO 输入 内部上拉
SPI_FLASH_CS_DISABLE;
SPI_FLASH_HOLD_HIGH;
SPI_FLASH_CLK_HIGH;
SPI_FLASH_WP_ENABLE;
SPI_FLASH_DI_LOW;
}
///
///
/// @param none
/// @param none
/// @return none
/// @note 修改日志
/// gkl与2017-04-26创建
int GetGBKCode_from_EXFlash(unsigned char* pBuffer,const unsigned char * c)
{
unsigned char High8bit,Low8bit;
unsigned int pos;
High8bit=*c;
Low8bit=*(c+1);
pos = ((High8bit-0xa0-16)*94+Low8bit-0xa0-1)*2*16;
SPI_FLASH_BufferRead(pBuffer,4096+pos,32);
return 0;
}