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

518 lines
14 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

////////////////////////////////////////////////////////////////////////////////
/// 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;
}