//////////////////////////////////////////////////////////////////////////////// /// 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的地址,取值(0,1,2……) /// @param count sector的个数,取值(0,1,2……) /// @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地址,取值(0,1,2……) /// @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的块地址,取值(0,1,2……) /// @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; }