这里代码包含EEPROM和FLASH代码,代码如下:
需要注意的是FLASH需要先擦除才能重新写入,不能频繁擦除否则会卡死
/*
* Eeprom.h
*
* Created on: 2023年10月12日
* Author: 86183
*/
#ifndef EEPROM_H_
#define EEPROM_H_
#include "hal_data.h"
#include "stdio.h"
#include "base.h"
#define AT24C02 255
#define EEPROM_PAGESIZE 8
#define I2C_Register_SR1 ((u8)0x14)
#define EE_TYPE AT24C02
void i2c_callback(i2c_master_callback_args_t * p_args);
void I2C_EE_Init(void);
void I2C_EE_ByteWrite(u8 address, u8 byte);
void I2C_EE_Writepage(u8* ptr_write , u8 WriteAddr,u8 len);
void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr,u8 NumByteToWrite);
void I2C_EE_BufferRead(u8* ptr_read,u8 address,u8 byte);
void I2C_EE_WaitState(void);
void I2C_EE_Writedrase(void);
#endif
#ifndef __FLASH_H
#define __FLASH_H
#include "hal_data.h"
#include "stdio.h"
#include "base.h"
#define W25Qx_Enable() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_11, BSP_IO_LEVEL_LOW);
#define W25Qx_Disable() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_11, BSP_IO_LEVEL_HIGH);
#define W25Q128FV_FLASH_SIZE 0x1000000 /* 64 MBits => 8MBytes */
#define W25Q128FV_SECTOR_SIZE 0x10000 /* 256 sectors of 64KBytes */
#define W25Q128FV_SUBSECTOR_SIZE 0x1000 /* 4096 subsectors of 4kBytes */
#define W25Q128FV_PAGE_SIZE 0x100 /* 65536 pages of 256 bytes */
#define W25Q64_ERASE_WRITE_LADD 0x7FF000 //进行精细删写操作的时候,后扇区临时储存地址
#define W25Q64_ERASE_WRITE_FADD 0x7FE000 //进行精细删写操作的时候,前扇区临时储存地址
#define W25Q128FV_DUMMY_CYCLES_READ 4
#define W25Q128FV_DUMMY_CYCLES_READ_QUAD 10
#define W25Q128FV_BULK_ERASE_MAX_TIME 250000
#define W25Q128FV_SECTOR_ERASE_MAX_TIME 3000
#define W25Q128FV_SUBSECTOR_ERASE_MAX_TIME 800
#define W25Qx_TIMEOUT_VALUE 1000
/* Reset Operations */
#define RESET_ENABLE_CMD 0x66
#define RESET_MEMORY_CMD 0x99
#define ENTER_QPI_MODE_CMD 0x38
#define EXIT_QPI_MODE_CMD 0xFF
/* Identification Operations */
#define READ_ID_CMD 0x90
#define DUAL_READ_ID_CMD 0x92
#define QUAD_READ_ID_CMD 0x94
#define READ_JEDEC_ID_CMD 0x9F
/* Read Operations */
#define READ_CMD 0x03
#define FAST_READ_CMD 0x0B
#define DUAL_OUT_FAST_READ_CMD 0x3B
#define DUAL_INOUT_FAST_READ_CMD 0xBB
#define QUAD_OUT_FAST_READ_CMD 0x6B
#define QUAD_INOUT_FAST_READ_CMD 0xEB
/* Write Operations */
#define WRITE_ENABLE_CMD 0x06
#define WRITE_DISABLE_CMD 0x04
/* Register Operations */
#define READ_STATUS_REG1_CMD 0x05
#define READ_STATUS_REG2_CMD 0x35
#define READ_STATUS_REG3_CMD 0x15
#define WRITE_STATUS_REG1_CMD 0x01
#define WRITE_STATUS_REG2_CMD 0x31
#define WRITE_STATUS_REG3_CMD 0x11
/* Program Operations */
#define PAGE_PROG_CMD 0x02
#define QUAD_INPUT_PAGE_PROG_CMD 0x32
/* Erase Operations */
#define SECTOR_ERASE_CMD 0x20
#define CHIP_ERASE_CMD 0xC7
#define PROG_ERASE_RESUME_CMD 0x7A
#define PROG_ERASE_SUSPEND_CMD 0x75
/* Flag Status Register */
#define W25Q128FV_FSR_BUSY ((u8)0x01) /*!< busy */
#define W25Q128FV_FSR_WREN ((u8)0x02) /*!< write enable */
#define W25Q128FV_FSR_QE ((u8)0x02) /*!< quad enable */
#define W25Qx_OK ((u8)0x00)
#define W25Qx_ERROR ((u8)0x01)
#define W25Qx_BUSY ((u8)0x02)
#define W25Qx_TIMEOUT ((u8)0x04)
#define W25Qx_SPIERROR ((u8)0x08)
u8 BSP_W25Qx_Init(void);
void BSP_W25Qx_Reset(void);
u8 BSP_W25Qx_GetStatus(void);
u8 BSP_W25Qx_WriteEnable(void);
u8 BSP_W25Qx_WriteDisable(void);
void BSP_W25Qx_Read_ID(u8 *ID_0);
u8 Flash_Read(u8* pData, u32 ReadAddr, u32 Size);
/*********************************************************
*目前可以看到该写入方式为与原本位置存储数据进行与运算,
*例如:原本该位置存储为1001,写入1100,写入后真实存储数据为1000
*因此该方法应改为先写入空数据1111(255),然后再写入需存储数据
*目前想法为读取两端数据重新写入,然后这些片区全部擦除,再写入
*********************************************************/
u8 Flash_Write(u8* pData, u32 WriteAddr, u32 Size);
/*********************************************************
*擦除原有位置数据,写入新的数据
*即为读取同片区数据,片区擦除,再写入
*********************************************************/
u8 Flash_Clear_Write(u8* pData,u32 WriteAddr, u32 Size);
u8 BSP_W25Qx_Erase_Block(u32 Address);
u8 BSP_W25Qx_Erase_Chip(void);
#endif
#include "Flash.h"
#include "Spi.h"
u8 BSP_W25Qx_Init(void)
{
BSP_W25Qx_Reset();
return BSP_W25Qx_GetStatus();
}
void BSP_W25Qx_Reset(void)
{
u8 cmd[2] = {RESET_ENABLE_CMD,RESET_MEMORY_CMD};
W25Qx_Enable();
spi_send(cmd,2);
W25Qx_Disable();
}
u8 BSP_W25Qx_GetStatus(void)
{
u8 cmd[] = {READ_STATUS_REG1_CMD};
u8 status;
W25Qx_Enable();
spi_send(cmd,1);
Spi_read(&status,1);
W25Qx_Disable();
if((status & W25Q128FV_FSR_BUSY) != 0)
{
return W25Qx_BUSY;
}
else
{
return W25Qx_OK;
}
}
u8 BSP_W25Qx_WriteEnable(void)
{
u8 cmd[] = {WRITE_ENABLE_CMD};
W25Qx_Enable();
spi_send(cmd,1);
W25Qx_Disable();
while(BSP_W25Qx_GetStatus() == W25Qx_BUSY)
{
R_BSP_SoftwareDelay (50U, BSP_DELAY_UNITS_MICROSECONDS);
}
return W25Qx_OK;
}
u8 BSP_W25Qx_WriteDisable(void)
{
u8 cmd[] = {WRITE_DISABLE_CMD};
W25Qx_Enable();
spi_send(cmd,1);
W25Qx_Disable();
while(BSP_W25Qx_GetStatus() == W25Qx_BUSY)
{
R_BSP_SoftwareDelay (50U, BSP_DELAY_UNITS_MICROSECONDS);
}
return W25Qx_OK;
}
void BSP_W25Qx_Read_ID(u8 *ID_0)
{
u8 cmd[4] = {READ_ID_CMD,0x00,0x00,0x00};
W25Qx_Enable();
Spi_write_read(cmd,4,ID_0,4);
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
W25Qx_Disable();
}
u8 Flash_Read(u8* pData, u32 ReadAddr, u32 Size)
{
u8 cmd[4];
_Bool retbool=false;
cmd[0] = READ_CMD;
cmd[1] = (uint8_t)(ReadAddr >> 16);
cmd[2] = (uint8_t)(ReadAddr >> 8);
cmd[3] = (uint8_t)(ReadAddr);
W25Qx_Enable();
retbool|=spi_send(cmd,4);
retbool|=Spi_read(pData, Size);
W25Qx_Disable();
if(!retbool)
{
return W25Qx_SPIERROR;
}
return W25Qx_OK;
}
u8 Flash_Clear_Write(u8* pData,u32 WriteAddr, u32 Size) //WriteAddr需要写入数据的首地址
{
u8 Mid_data[2*W25Q128FV_PAGE_SIZE]; //用来储存前后扇区数据的数组,最多需要循环16次
u8 retnum=0; //返回值,是否正确
u32 start_addr,end_addr,end_size,start_size; //开始地址,结束地址,结束的尺寸,开始的尺寸
u32 i=0;
u32 j=0; //用来跑循环
start_addr = 0;
end_addr =0;
if(Size==0) //如果没有数据,则直接返回,不用进行后续操作
{
return 0;
}
while(start_addr <= WriteAddr) //Size需要写入的数据的大小
{ //pData需要写入的数据
start_addr += W25Q128FV_SUBSECTOR_SIZE; //这个循环是用来找到最开始的块地址,每一页4096字节,16页
}
start_addr-=W25Q128FV_SUBSECTOR_SIZE; //现在start_addr是最开始的块地址
start_size=WriteAddr-start_addr; //现在start_size是牵连的数据有多少,后面擦除会被一起擦除,然后最后重新写入
while(end_addr < WriteAddr+Size)
{
end_addr += W25Q128FV_SUBSECTOR_SIZE; //这个循环是用来找到最后面的块地址,每一页4096字节,16页
}
end_size=end_addr-(WriteAddr+Size); //现在end_size是最后面的数据有多少,后面擦除会被一起擦除,然后最后重新写入
end_addr-=end_size; //最后需要重新写入数据的地址
//start_addr需要重新写入的最开始的数据的首地址
//end_addr需要重新写入的最后面的数据的首地址
//end_size需要重新写入的最后面的数据的尺寸
//start_size需要重新写入的最开始的数据的尺寸
if(start_size!=0) //开始的尺寸如果为0,则不需要读出重新写入,不会被擦除
{
for(j=0;j<start_size;j+=(2*W25Q128FV_PAGE_SIZE))
{
retnum|=Flash_Read(Mid_data,start_addr+j,2*W25Q128FV_PAGE_SIZE); //读出数据
retnum|=Flash_Write(Mid_data,W25Q64_ERASE_WRITE_FADD+j,2*W25Q128FV_PAGE_SIZE); //写入数据
}
}
if(end_size!=0) //结尾的尺寸如果为0,则不需要读出重新写入,不会被擦除
{
for(j=0;j<end_size;j+=(2*W25Q128FV_PAGE_SIZE))
{
retnum|=Flash_Read(Mid_data,end_addr+j,2*W25Q128FV_PAGE_SIZE); //读出数据
retnum|=Flash_Write(Mid_data,W25Q64_ERASE_WRITE_LADD+j,2*W25Q128FV_PAGE_SIZE); //写入数据
}
}
for(i =start_addr;i<end_addr;i+=W25Q128FV_PAGE_SIZE) //从最开始的页到最后的页,擦除全部数据
{
retnum|=BSP_W25Qx_Erase_Block(i); //擦除这些页的数据
}
if(start_size!=0) //开始的尺寸如果为0,则不需要读出重新写入,不会被擦除
{
for(j=0;j<start_size-(2*W25Q128FV_PAGE_SIZE);j+=(2*W25Q128FV_PAGE_SIZE))
{
retnum|=Flash_Read(Mid_data,W25Q64_ERASE_WRITE_FADD+j,2*W25Q128FV_PAGE_SIZE); //读取数据
retnum|=Flash_Write(Mid_data,start_addr+j,2*W25Q128FV_PAGE_SIZE); //写入数据
}
retnum|=Flash_Read(Mid_data,W25Q64_ERASE_WRITE_FADD+j,start_size-j);
retnum|=Flash_Write(Mid_data,start_addr+j,start_size-j);
}
if(end_size!=0) //结尾的尺寸如果为0,则不需要读出重新写入,不会被擦除
{
for(j=0;j<end_size-(2*W25Q128FV_PAGE_SIZE);j+=(2*W25Q128FV_PAGE_SIZE))
{
retnum|=Flash_Read(Mid_data,W25Q64_ERASE_WRITE_LADD+j,2*W25Q128FV_PAGE_SIZE); //读取数据
retnum|=Flash_Write(Mid_data,end_addr+j,2*W25Q128FV_PAGE_SIZE); //写入数据
}
retnum|=Flash_Read(Mid_data,W25Q64_ERASE_WRITE_LADD+j,end_size-j);
retnum|=Flash_Write(Mid_data,end_addr+j,end_size-j);
}
retnum|=Flash_Write(pData,WriteAddr,Size); //写入数据
return retnum;
}
u8 Flash_Write(u8* pData, u32 WriteAddr, u32 Size)
{
u8 cmd[4];
_Bool retbool=false;
u32 end_addr, current_size, current_addr;
current_addr = 0;
while (current_addr <= WriteAddr)
{
current_addr += W25Q128FV_PAGE_SIZE;
}
current_size = current_addr - WriteAddr;
if (current_size > Size)
{
current_size = Size;
}
current_addr = WriteAddr;
end_addr = WriteAddr + Size;
do
{
cmd[0] = PAGE_PROG_CMD;
cmd[1] = (u8)(current_addr >> 16);
cmd[2] = (u8)(current_addr >> 8);
cmd[3] = (u8)(current_addr);
BSP_W25Qx_WriteEnable();
W25Qx_Enable();
retbool=spi_send(cmd,4);
if(!retbool)
{
return W25Qx_SPIERROR;
}
retbool=spi_send(pData,current_size);
if(!retbool)
{
return W25Qx_SPIERROR;
}
W25Qx_Disable();
BSP_W25Qx_WriteDisable();
while(BSP_W25Qx_GetStatus() == W25Qx_BUSY)
{
R_BSP_SoftwareDelay (50U, BSP_DELAY_UNITS_MICROSECONDS);
}
current_addr += current_size;
pData += current_size;
current_size = ((current_addr + W25Q128FV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128FV_PAGE_SIZE;
}while (current_addr < end_addr);
return W25Qx_OK;
}
u8 BSP_W25Qx_Erase_Block(u32 Address)
{
uint8_t cmd[4];
cmd[0] = SECTOR_ERASE_CMD;
cmd[1] = (uint8_t)(Address >> 16);
cmd[2] = (uint8_t)(Address >> 8);
cmd[3] = (uint8_t)(Address);
BSP_W25Qx_WriteEnable();
W25Qx_Enable();
spi_send(cmd,4);
W25Qx_Disable();
while(BSP_W25Qx_GetStatus() == W25Qx_BUSY)
{
R_BSP_SoftwareDelay (50U, BSP_DELAY_UNITS_MICROSECONDS);
}
return W25Qx_OK;
}
u8 BSP_W25Qx_Erase_Chip(void)
{
u8 cmd[4];
cmd[0] = CHIP_ERASE_CMD;
BSP_W25Qx_WriteEnable();
W25Qx_Enable();
spi_send(cmd,1);
W25Qx_Disable();
while(BSP_W25Qx_GetStatus() != W25Qx_BUSY)
{
R_BSP_SoftwareDelay (50U, BSP_DELAY_UNITS_MICROSECONDS);
}
return W25Qx_OK;
}
/*
* Eeprom.c
*
* Created on: 2023年10月12日
* Author: 86183
*/
#include "Eeprom.h"
#include "tftlcd.h"
u16 timeout_ms = 500;
i2c_master_event_t g_i2c_callback_event;
static volatile bool iic_complete = false;
void i2c_callback (i2c_master_callback_args_t * p_args)
{
g_i2c_callback_event = p_args->event;
}
void I2C_EE_Init()
{
R_IIC_MASTER_Open(&g_i2c_master0_ctrl, &g_i2c_master0_cfg);
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
}
void I2C_EE_ByteWrite(u8 address, u8 byte)
{
iic_complete = false;
u8 send_buffer[2] = {};
send_buffer[0] = address;
send_buffer[1] = byte;
R_IIC_MASTER_Write(&g_i2c_master0_ctrl, &send_buffer[0], 2, false);
while ((I2C_MASTER_EVENT_TX_COMPLETE != g_i2c_callback_event) && timeout_ms)
{
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
timeout_ms--;
}
timeout_ms = 500;
}
void I2C_EE_Writepage(u8* ptr_write , u8 WriteAddr,u8 len)
{
u8 send_buffer[9] = {};
send_buffer[0] = WriteAddr;
for(u8 i = 0;i<len;i++)
{
send_buffer[1+i] = *(ptr_write+i);
}
R_IIC_MASTER_Write(&g_i2c_master0_ctrl, &send_buffer[0], len+1 , false);
while ((I2C_MASTER_EVENT_TX_COMPLETE != g_i2c_callback_event) && timeout_ms)
{
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MILLISECONDS);
timeout_ms--;
}
timeout_ms = 500;
I2C_EE_WaitState();
}
void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr,u8 NumByteToWrite)
{
u8 NumOfPage = 0; //共有几页
u8 NumOfSingle = 0; //最后一页有多少字节
u8 Addr = 0; //写入地址在当前页的第几位
u8 count = 0; //当前页的剩余位数
Addr = WriteAddr % EEPROM_PAGESIZE; //写入地址在当前页的第几位
count = EEPROM_PAGESIZE - Addr; //当前页的剩余位数
NumOfPage = NumByteToWrite / EEPROM_PAGESIZE; //共有几页
NumOfSingle = NumByteToWrite % EEPROM_PAGESIZE; //最后一页有多少字节
if (Addr == 0)
{
if (NumOfPage == 0)
{
I2C_EE_Writepage(pBuffer, WriteAddr, NumOfSingle);
}
else
{
while (NumOfPage--)
{
I2C_EE_Writepage(pBuffer, WriteAddr, EEPROM_PAGESIZE);
WriteAddr += EEPROM_PAGESIZE;
pBuffer += EEPROM_PAGESIZE;
}
if (NumOfSingle!=0)
{
I2C_EE_Writepage(pBuffer, WriteAddr, NumOfSingle);
}
}
}
else
{
if (NumOfPage== 0)
{
I2C_EE_Writepage(pBuffer, WriteAddr, NumOfSingle);
}
else
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / EEPROM_PAGESIZE;
NumOfSingle = NumByteToWrite % EEPROM_PAGESIZE;
if (count != 0)
{
I2C_EE_Writepage(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
}
while (NumOfPage--)
{
I2C_EE_Writepage(pBuffer, WriteAddr, EEPROM_PAGESIZE);
WriteAddr += EEPROM_PAGESIZE;
pBuffer += EEPROM_PAGESIZE;
}
if (NumOfSingle != 0)
{
I2C_EE_Writepage(pBuffer, WriteAddr, NumOfSingle);
}
}
}
}
void I2C_EE_BufferRead(u8* ptr_read,u8 address,u8 byte)
{
R_IIC_MASTER_Write(&g_i2c_master0_ctrl, &address, 1, true);
while ((I2C_MASTER_EVENT_TX_COMPLETE != g_i2c_callback_event) && timeout_ms)
{
R_BSP_SoftwareDelay(400U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
timeout_ms = 500;
R_BSP_SoftwareDelay(250U, BSP_DELAY_UNITS_MICROSECONDS);
R_IIC_MASTER_Read(&g_i2c_master0_ctrl, ptr_read, byte, false);
while ((I2C_MASTER_EVENT_RX_COMPLETE != g_i2c_callback_event) && timeout_ms)
{
R_BSP_SoftwareDelay(4U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
timeout_ms = 500;
}
void I2C_EE_WaitState(void)
{
while (timeout_ms)
{
R_BSP_SoftwareDelay(9U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
timeout_ms = 500;
}
void I2C_EE_Writedrase()
{
u8 I2c_Buf_Write[256] = {};
for(int i = 0 ; i<256 ; i++)
{
I2c_Buf_Write[i] = 0xff;
}
I2C_EE_BufferWrite(I2c_Buf_Write, 0x00 , 255);
}