这里代码包含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);
}