dc32-retro-tech-addon/firmware/retro_tech_fw/user/src/eeprom.c

86 lines
2.2 KiB
C

/*
* Created on: Jul 27, 2024
*
* code taken from example WCH code, which was likely stolen from somewhere else.
* directly uses i2c peripheral in shitty way. no time to make this better.
* modified to support multiple "pages" (addresses) for 02/04/08/16 EEPROMs.
*
* ensure i2c bus has been configured before using these functions.
*/
#define EEPROM_BASE_ADDR 0xa0
#include <ch32v00x.h>
#include <stdint.h>
#include "eeprom.h"
#include "i2c.h"
static inline uint8_t page_to_i2caddr(uint8_t page)
{
page &= 0x7; // limit page to 3 bits (8 pages)
page <<= 1; // shift page to required position
page |= EEPROM_BASE_ADDR; // merge top address bits to form address
return page;
}
/*********************************************************************
* @fn eeprom_read_byte
*
* @brief Read one data from EEPROM.
* @param page - Which 256-byte EEPROM page.
* @param addr - First read address.
* @param data - Pointer to byte(s) to write.
* @param len - Count of data to write.
*/
void eeprom_read_bytes(uint8_t page, uint8_t addr, uint8_t *data, uint8_t len)
{
page = page_to_i2caddr(page);
i2c_read_addr1b(page, addr, data, len);
}
/*********************************************************************
* @fn eeprom_write_bytes
*
* @brief Write data to EEPROM.
* Note that some EEPROMs have buffers smaller than the page size.
*
* @param page - Which 256-byte EEPROM page.
* @param addr - Starting write address.
* @param data - Pointer to byte(s) to write.
* @param len - Count of data to write.
*/
void eeprom_write_bytes(uint8_t page, uint8_t addr, uint8_t *data, uint8_t len)
{
page = page_to_i2caddr(page);
// disable systick interrupt
NVIC_DisableIRQ(SysTicK_IRQn);
// write the data
#ifdef EEPROM_WP_PORT
EEPROM_WP_PORT->BCR = EEPROM_WP_PIN;
#endif
while (!i2c_addr_scan(page));
i2c_write_addr1b(page, addr, data, len);
while (!i2c_addr_scan(page));
#ifdef EEPROM_WP_PORT
EEPROM_WP_PORT->BSHR = EEPROM_WP_PIN;
#endif
// clear systick timer
SysTick->CNT = 0;
SysTick->SR = 0;
// re-enable systick interrupt
NVIC_EnableIRQ(SysTicK_IRQn);
}