-
Notifications
You must be signed in to change notification settings - Fork 70
Description
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();
}