Skip to content

CH32V103 EEPROM Lib IssuesΒ #213

@KenRouKoro

Description

@KenRouKoro

The EEPROM library is not fully successful when running on CH32V103X8T6. Currently, it can successfully read and write the first 2 bytes, but cannot read or write the following 24 bytes, which are always read as 255.

After studying the CH32V103 Flash in depth, I found that the ch32v10x library within the ch32 package in current CH32 platformio and arduino_core_ch32 projects lacks many components compared to the official library. Specifically in the Flash section, the FLASH_ROM_ERASE and FLASH_ROM_WRITE methods are missing. I have tried to create a simulated EEPROM library (not Arduino standard) for reference, which uses the last 128 bytes of the ch32v103. The 128-byte size matches exactly the quick programming size of the ch32v103.

eeprom_emulation.h

#ifndef EEPROM_EMULATION_H
#define EEPROM_EMULATION_H

#include "Arduino.h"
#include "ch32v10x_flash.h"
#include "debug.h"

#ifdef __cplusplus
extern "C" {
#endif

/* EEPROM emulation configuration */
#define EEPROM_SIZE                 128                    // EEPROM size in bytes
#define EEPROM_START_ADDR          ((uint32_t)0x0800FF80) // Flash start address (last 128 bytes)
#define EEPROM_END_ADDR            ((uint32_t)0x08010000) // Flash end address
#define EEPROM_BUFFER_SIZE         EEPROM_SIZE            // Write buffer size

/* Status definitions */
typedef enum
{
    EEPROM_OK = 0,
    EEPROM_ERROR,
    EEPROM_ADDR_OUT_OF_RANGE,
    EEPROM_FLASH_ERROR
} EEPROM_Status;

/* Function declarations */

/**
 * @brief  Initialize EEPROM emulation
 * @param  None
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_Init(void);

/**
 * @brief  Read one byte from EEPROM
 * @param  addr: Address offset (0-127)
 * @retval Read data
 */
uint8_t EEPROM_ReadByte(uint16_t addr);

/**
 * @brief  Read multiple bytes from EEPROM
 * @param  addr: Start address offset (0-127)
 * @param  data: Data buffer pointer
 * @param  len: Read length
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_ReadBytes(uint16_t addr, uint8_t* data, uint16_t len);

/**
 * @brief  Write one byte to write buffer (not immediately to Flash)
 * @param  addr: Address offset (0-127)
 * @param  data: Data to write
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_WriteByteToBuffer(uint16_t addr, uint8_t data);

/**
 * @brief  Write multiple bytes to write buffer (not immediately to Flash)
 * @param  addr: Start address offset (0-127)
 * @param  data: Data buffer pointer
 * @param  len: Write length
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_WriteBytesToBuffer(uint16_t addr, const uint8_t* data, uint16_t len);

/**
 * @brief  Manually execute write operation (write buffer data to Flash)
 * @param  None
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_Commit(void);

/**
 * @brief  Check if buffer has uncommitted data
 * @param  None
 * @retval 1: Has pending writes, 0: No pending writes
 */
uint8_t EEPROM_HasPendingWrites(void);

/**
 * @brief  Clear write buffer (discard uncommitted data)
 * @param  None
 * @retval None
 */
void EEPROM_ClearBuffer(void);

/**
 * @brief  Format EEPROM area (erase all data)
 * @param  None
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_Format(void);

#ifdef __cplusplus
}
#endif

#endif /* EEPROM_EMULATION_H */

eeprom_emulation.cpp

#include "eeprom_emulation.h"
#include <string.h>

/* Private variables */
static uint8_t eeprom_buffer[EEPROM_BUFFER_SIZE];  // Write buffer
static uint8_t buffer_dirty = 0;                   // Buffer dirty flag
static uint8_t eeprom_initialized = 0;             // Initialization flag

/* Private function declarations */
static EEPROM_Status EEPROM_EraseFlash(void);
static EEPROM_Status EEPROM_WriteFlash(void);
static uint8_t EEPROM_IsAddressValid(uint16_t addr);

/**
 * @brief  Check if address is valid
 * @param  addr: Address offset
 * @retval 1: Valid, 0: Invalid
 */
static uint8_t EEPROM_IsAddressValid(uint16_t addr)
{
    return (addr < EEPROM_SIZE) ? 1 : 0;
}

/**
 * @brief  Erase EEPROM Flash area
 * @param  None
 * @retval EEPROM_Status Operation status
 */
static EEPROM_Status EEPROM_EraseFlash(void)
{
    FLASH_Status status;
    
    // Use fast erase API
    status = FLASH_ROM_ERASE(EEPROM_START_ADDR, EEPROM_SIZE);
    
    if(status != FLASH_COMPLETE)
    {
        return EEPROM_FLASH_ERROR;
    }
    
    return EEPROM_OK;
}

/**
 * @brief  Write buffer data to Flash
 * @param  None
 * @retval EEPROM_Status Operation status
 */
static EEPROM_Status EEPROM_WriteFlash(void)
{
    FLASH_Status status;
    
    // Erase Flash area first
    if(EEPROM_EraseFlash() != EEPROM_OK)
    {
        return EEPROM_FLASH_ERROR;
    }
    
    // Use fast write API
    status = FLASH_ROM_WRITE(EEPROM_START_ADDR, (uint32_t*)eeprom_buffer, EEPROM_SIZE);
    
    if(status != FLASH_COMPLETE)
    {
        return EEPROM_FLASH_ERROR;
    }
    
    return EEPROM_OK;
}

/**
 * @brief  Initialize EEPROM emulation
 * @param  None
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_Init(void)
{
    uint16_t i;
    
    // Read current data from Flash to buffer
    for(i = 0; i < EEPROM_SIZE; i++)
    {
        eeprom_buffer[i] = *((uint8_t*)(EEPROM_START_ADDR + i));
    }
    
    buffer_dirty = 0;
    eeprom_initialized = 1;
    
    return EEPROM_OK;
}

/**
 * @brief  Read one byte from EEPROM
 * @param  addr: Address offset (0-127)
 * @retval Read data
 */
uint8_t EEPROM_ReadByte(uint16_t addr)
{
    if(!eeprom_initialized)
    {
        EEPROM_Init();
    }
    
    if(!EEPROM_IsAddressValid(addr))
    {
        return 0xFF; // Return 0xFF for invalid addresses
    }
    
    // Read from buffer if there's uncommitted data
    if(buffer_dirty)
    {
        return eeprom_buffer[addr];
    }
    
    // Read directly from Flash
    return *((uint8_t*)(EEPROM_START_ADDR + addr));
}

/**
 * @brief  Read multiple bytes from EEPROM
 * @param  addr: Start address offset (0-127)
 * @param  data: Data buffer pointer
 * @param  len: Read length
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_ReadBytes(uint16_t addr, uint8_t* data, uint16_t len)
{
    uint16_t i;
    
    if(!eeprom_initialized)
    {
        EEPROM_Init();
    }
    
    if(!EEPROM_IsAddressValid(addr) || !EEPROM_IsAddressValid(addr + len - 1))
    {
        return EEPROM_ADDR_OUT_OF_RANGE;
    }
    
    if(data == NULL)
    {
        return EEPROM_ERROR;
    }
    
    for(i = 0; i < len; i++)
    {
        data[i] = EEPROM_ReadByte(addr + i);
    }
    
    return EEPROM_OK;
}

/**
 * @brief  Write one byte to write buffer (not immediately to Flash)
 * @param  addr: Address offset (0-127)
 * @param  data: Data to write
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_WriteByteToBuffer(uint16_t addr, uint8_t data)
{
    if(!eeprom_initialized)
    {
        EEPROM_Init();
    }
    
    if(!EEPROM_IsAddressValid(addr))
    {
        return EEPROM_ADDR_OUT_OF_RANGE;
    }
    
    // Write to buffer
    eeprom_buffer[addr] = data;
    buffer_dirty = 1;
    
    return EEPROM_OK;
}

/**
 * @brief  Write multiple bytes to write buffer (not immediately to Flash)
 * @param  addr: Start address offset (0-127)
 * @param  data: Data buffer pointer
 * @param  len: Write length
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_WriteBytesToBuffer(uint16_t addr, const uint8_t* data, uint16_t len)
{
    uint16_t i;
    
    if(!eeprom_initialized)
    {
        EEPROM_Init();
    }
    
    if(!EEPROM_IsAddressValid(addr) || !EEPROM_IsAddressValid(addr + len - 1))
    {
        return EEPROM_ADDR_OUT_OF_RANGE;
    }
    
    if(data == NULL)
    {
        return EEPROM_ERROR;
    }
    
    for(i = 0; i < len; i++)
    {
        eeprom_buffer[addr + i] = data[i];
    }
    
    buffer_dirty = 1;
    
    return EEPROM_OK;
}

/**
 * @brief  Manually execute write operation (write buffer data to Flash)
 * @param  None
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_Commit(void)
{
    if(!eeprom_initialized)
    {
        return EEPROM_ERROR;
    }
    
    if(!buffer_dirty)
    {
        return EEPROM_OK; // No data to write
    }
    
    // Write to Flash
    if(EEPROM_WriteFlash() != EEPROM_OK)
    {
        return EEPROM_FLASH_ERROR;
    }
    
    buffer_dirty = 0;
    
    return EEPROM_OK;
}

/**
 * @brief  Check if buffer has uncommitted data
 * @param  None
 * @retval 1: Has pending writes, 0: No pending writes
 */
uint8_t EEPROM_HasPendingWrites(void)
{
    return buffer_dirty;
}

/**
 * @brief  Clear write buffer (discard uncommitted data)
 * @param  None
 * @retval None
 */
void EEPROM_ClearBuffer(void)
{
    uint16_t i;
    
    if(!eeprom_initialized)
    {
        EEPROM_Init();
        return;
    }
    
    // Reload data from Flash to buffer
    for(i = 0; i < EEPROM_SIZE; i++)
    {
        eeprom_buffer[i] = *((uint8_t*)(EEPROM_START_ADDR + i));
    }
    
    buffer_dirty = 0;
}

/**
 * @brief  Format EEPROM area (erase all data)
 * @param  None
 * @retval EEPROM_Status Operation status
 */
EEPROM_Status EEPROM_Format(void)
{
    uint16_t i;
    
    if(!eeprom_initialized)
    {
        EEPROM_Init();
    }
    
    // Clear buffer (set to 0xFF)
    for(i = 0; i < EEPROM_SIZE; i++)
    {
        eeprom_buffer[i] = 0xFF;
    }
    
    buffer_dirty = 1;
    
    // Write to Flash immediately
    return EEPROM_Commit();
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions