first commit
This commit is contained in:
150
simple_eeprom.h
Normal file
150
simple_eeprom.h
Normal file
@@ -0,0 +1,150 @@
|
||||
#ifndef __SIMPLE_EEPROM_H
|
||||
#define __SIMPLE_EEPROM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ch32v003fun.h"
|
||||
|
||||
// config
|
||||
#define EEPROM_PAGE_SIZE 64 // size in bytes
|
||||
#define EEPROM_HALFWORD_SIZE 2 // size of halfword in bytes
|
||||
#define EEPROM_MAX_ENTRIES (EEPROM_PAGE_SIZE / EEPROM_HALFWORD_SIZE)
|
||||
|
||||
typedef enum {
|
||||
EEPROM_OK = 0,
|
||||
EEPROM_ERROR_WRITE,
|
||||
EEPROM_ERROR_ERASE,
|
||||
EEPROM_ERROR_VERIFY
|
||||
} eeprom_status_t;
|
||||
|
||||
// ######## internal variables
|
||||
// import from .ld, halal by
|
||||
// https://sourceware.org/binutils/docs/ld/Source-Code-Reference.html
|
||||
extern char _reserved_nv_start[];
|
||||
extern char _reserved_nv_end[];
|
||||
|
||||
#define EEPROM_BASE (FLASH_BASE + (uint32_t)(uintptr_t)_reserved_nv_start)
|
||||
|
||||
static void flash_unlock(void) {
|
||||
if (FLASH->CTLR & 0x80) {
|
||||
FLASH->KEYR = FLASH_KEY1;
|
||||
FLASH->KEYR = FLASH_KEY2;
|
||||
}
|
||||
}
|
||||
|
||||
static void flash_lock(void) { FLASH->CTLR = 0x80; }
|
||||
|
||||
static void flash_unlock_fast_mode(void) {
|
||||
if (FLASH->CTLR & 0x8000) {
|
||||
FLASH->MODEKEYR = FLASH_KEY1;
|
||||
FLASH->MODEKEYR = FLASH_KEY2;
|
||||
}
|
||||
}
|
||||
|
||||
static void flash_wait_busy(void) { while (FLASH->STATR & FLASH_STATR_BSY); }
|
||||
|
||||
static eeprom_status_t flash_erase_page(void) {
|
||||
uint16_t *page_addr = (uint16_t *)EEPROM_BASE;
|
||||
|
||||
flash_unlock_fast_mode();
|
||||
flash_wait_busy();
|
||||
|
||||
// erase page
|
||||
FLASH->CTLR = CR_PAGE_ER;
|
||||
FLASH->ADDR = (uint32_t)page_addr;
|
||||
FLASH->CTLR = CR_STRT_Set | CR_PAGE_ER;
|
||||
flash_wait_busy();
|
||||
|
||||
// verify erase
|
||||
for (int i = 0; i < EEPROM_MAX_ENTRIES; i++) {
|
||||
if (page_addr[i] != 0xFFFF) {
|
||||
return EEPROM_ERROR_ERASE;
|
||||
}
|
||||
}
|
||||
|
||||
// disable fast mode
|
||||
FLASH->CTLR = 0x8000;
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
static int find_next_free_slot(void) {
|
||||
uint16_t *word = (uint16_t *)EEPROM_BASE;
|
||||
for (int i = 0; i < EEPROM_MAX_ENTRIES; i++) {
|
||||
if (word[i] == 0xFFFF) { // look for erased entries
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return EEPROM_MAX_ENTRIES;
|
||||
}
|
||||
|
||||
eeprom_status_t eeprom_write(uint16_t data) {
|
||||
flash_unlock();
|
||||
|
||||
// find next available slot
|
||||
int slot = find_next_free_slot();
|
||||
uint16_t *word = (uint16_t *)EEPROM_BASE + slot;
|
||||
|
||||
// page is full, erase it
|
||||
if (slot >= EEPROM_MAX_ENTRIES) {
|
||||
eeprom_status_t status = flash_erase_page();
|
||||
if (status != EEPROM_OK) {
|
||||
flash_lock();
|
||||
return status;
|
||||
}
|
||||
word = (uint16_t *)EEPROM_BASE; // reset to start of page
|
||||
}
|
||||
|
||||
// write data
|
||||
FLASH->CTLR = CR_PG_Set;
|
||||
*word = data; // write full 16-bit value
|
||||
flash_wait_busy();
|
||||
|
||||
// verify write
|
||||
if (*word != data) {
|
||||
flash_lock();
|
||||
return EEPROM_ERROR_VERIFY;
|
||||
}
|
||||
|
||||
flash_lock();
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
uint16_t eeprom_read(void) {
|
||||
uint16_t *word =
|
||||
(uint16_t *)(EEPROM_BASE + EEPROM_PAGE_SIZE - EEPROM_HALFWORD_SIZE);
|
||||
|
||||
// scan back from the end until we find a non-erased value
|
||||
for (int i = 0; i < EEPROM_MAX_ENTRIES; i++) {
|
||||
uint16_t val = *word;
|
||||
if (val != 0xFFFF) {
|
||||
return val;
|
||||
}
|
||||
word--;
|
||||
}
|
||||
|
||||
return 0xFFFF; // nothing found
|
||||
}
|
||||
|
||||
eeprom_status_t eeprom_init(void) {
|
||||
uint16_t *page = (uint16_t *)EEPROM_BASE;
|
||||
|
||||
// check empty/partial page
|
||||
bool needs_erase = true;
|
||||
for (int i = 0; i < EEPROM_MAX_ENTRIES; i++) {
|
||||
if (page[i] != 0xFFFF) {
|
||||
needs_erase = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_erase) {
|
||||
return flash_erase_page();
|
||||
}
|
||||
|
||||
return EEPROM_OK;
|
||||
}
|
||||
|
||||
eeprom_status_t eeprom_wipe(void) { return flash_erase_page(); }
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user