/*** * @file BSP_EE24.c * This file contains functions to interact with an EEPROM driver and perform * read and write operations on it. The driver uses I2C protocol and supports * multiple partitions, which can be used to store different types of data. */ #include "BSP_EE24.h" #include "ee24.h" #include "i2c.h" #include "cmsis_os2.h" #include "gpio.h" #define BSP_EE24_I2C &hi2c2 #define BSP_EE24_ADDRESS EE24_ADDRESS_DEFAULT #define BSP_EE24_TIMEOUT 500 #define BSP_EE24_MUTEXT_TIMEOUT osWaitForever // Main Pariton Table static BSP_EE24_Partion PartionTable[__BSP_EE24_PART_MAX__] = { [BSP_EE24_PART_HEAD_PARTION] = { .address = -1, .len = sizeof(BSP_EE24_TableHeader) }, [BSP_EE24_PART_GLOBAL_LIGHT] = { .address = -1, .len = 64, }, [BSP_EE24_PART_RESERVED] = { .address = -1, .len = 128, } }; static const uint32_t PartionTableVersion = 1; static EE24_HandleTypeDef hee24 = {0}; static osMutexId_t ee24_lock; void BSP_EE24_TableMigrate(uint32_t ee_version); /** * Initializes the EEPROM Partition Table. * * This function calculates the addresses of each element in the Partition Table * based on their lengths and the previous element's address. It assumes that the * Partition Table is ordered by ascending addresses, and that there are no gaps * between elements. */ void BSP_EE24_InitTable() { uint32_t address = 0; // Start at address 0 for (int i = 0; i < __BSP_EE24_PART_MAX__; i++) { if (PartionTable[i].len > 0) { PartionTable[i].address = address; address += PartionTable[i].len; } } } /** * Initializes the EEPROM driver and performs any necessary migrations. */ bool BSP_EE24_Init(void) { BSP_EE24_InitTable(); // Initialize the EE24 driver with the I2C interface and address bool status = EE24_Init(&hee24,BSP_EE24_I2C,BSP_EE24_ADDRESS); if(!status) { return status; } // os mutext ee24_lock = osMutexNew(NULL); // wc control high disables write HAL_GPIO_WritePin(EEPROM_WC_GPIO_Port, EEPROM_WC_Pin, GPIO_PIN_SET); // Read the Partition Table header from the EEPROM BSP_EE24_TableHeader header = {0}; status = BSP_EE24_PartRead(BSP_EE24_PART_HEAD_PARTION, (uint8_t*)&header, sizeof(header)); if(!status) { return status; } // Check if the Partition Table version is different from the expected version uint32_t fw_table_version = PartionTableVersion; uint32_t ee_table_version = header.version; if(ee_table_version != fw_table_version) { BSP_EE24_TableMigrate(ee_table_version); if(!status) { return status; } } return true; } /** * Reads data from the EEPROM. * This function is blocking for the operation to complete. * * @param[in] Address The starting address of the data to be read. * @param[out] Data A pointer to a buffer where the data will be stored. * @param[in] Len The number of bytes to be read. * @return true if the operation was successful, false otherwise. */ bool BSP_EE24_Read(uint32_t Address, uint8_t *Data, size_t Len) { osMutexAcquire(ee24_lock,BSP_EE24_MUTEXT_TIMEOUT); bool status = EE24_Read(&hee24,Address,Data,Len,BSP_EE24_TIMEOUT); osMutexRelease(ee24_lock); return status; } /** * Writes data to the EEPROM. * This function is blocking for the operation to complete. * * @param[in] Address The starting address of the data to be written. * @param[out] Data A pointer to a buffer containing the data to be written. * @param[in] Len The number of bytes to be written. * @return true if the operation was successful, false otherwise. */ bool BSP_EE24_Write(uint32_t Address, uint8_t *Data, size_t Len) { osMutexAcquire(ee24_lock,BSP_EE24_MUTEXT_TIMEOUT); HAL_GPIO_WritePin(EEPROM_WC_GPIO_Port, EEPROM_WC_Pin, GPIO_PIN_RESET); // low enables write; bool status = EE24_Write(&hee24,Address,Data,Len,BSP_EE24_TIMEOUT); HAL_GPIO_WritePin(EEPROM_WC_GPIO_Port, EEPROM_WC_Pin, GPIO_PIN_SET); // high disables write; osMutexRelease(ee24_lock); return status; } /** * Reads data from a specific partition in the EEPROM. * This function is blocking for the operation to complete. * * @param[in] part The identifier of the partition to read from. * Must be one of the BSP_EE24_PART_* constants. * @param[out] Data A pointer to a buffer where the data will be stored. * @param[in] LenBuffer The maximum number of bytes to be read from the partition. * @return true if the operation was successful, false otherwise. */ bool BSP_EE24_PartRead(BSP_EE24_PartionEntry_e part, uint8_t *Data, size_t LenBuffer) { // Check if the partition is valid and has data to read if (!(part < __BSP_EE24_PART_MAX__ && PartionTable[part].len > 0)) { return false; } // Read the Partion address uint32_t Address = PartionTable[part].address; // Calculate the length to be read uint32_t Len = 0; if (PartionTable[part].len < LenBuffer) { Len = PartionTable[part].len; } else { Len = LenBuffer; } return BSP_EE24_Read(Address,Data,Len); } /** * Writes data to a specific partition in the EEPROM. * This function is blocking for the operation to complete. * * @param[in] part The identifier of the partition to write to. * Must be one of the BSP_EE24_PART_* constants. * @param[out] Data A pointer to a buffer containing the data to be written. * @param[in] LenBuffer The maximum number of bytes to be written to the partition. * @return true if the operation was successful, false otherwise. */ bool BSP_EE24_PartWrite(BSP_EE24_PartionEntry_e part, uint8_t *Data, size_t LenBuffer) { // Check if the partition is valid and has data to read if (!(part < __BSP_EE24_PART_MAX__ && PartionTable[part].len > 0)) { return false; } // Read the Partion address uint32_t Address = PartionTable[part].address; // Calculate the length to be read uint32_t Len = 0; if (PartionTable[part].len < LenBuffer) { Len = PartionTable[part].len; } else { Len = LenBuffer; } return BSP_EE24_Write(Address,Data,Len); } static inline size_t MIN_MEM(size_t a, size_t b) { return((a) < (b) ? a : b); } /** * Clear a new or undefined eeprom */ void BSP_EE24_FullClear() { size_t len = 0; for (int i = 1; i < __BSP_EE24_PART_MAX__; i++) { len += PartionTable[i].len; } BSP_EE24_TableHeader header = { .version = PartionTableVersion, .used_len = len, .reserved = {0}, }; // write header BSP_EE24_PartWrite(BSP_EE24_PART_HEAD_PARTION, (uint8_t*)&header, sizeof(header)); // Calculate the start address and length of the clear operation uint32_t clear_start = PartionTable[BSP_EE24_PART_HEAD_PARTION].address + PartionTable[BSP_EE24_PART_HEAD_PARTION].len; uint32_t clear_len = header.used_len - PartionTable[BSP_EE24_PART_HEAD_PARTION].len; // Use a 16-byte buffer to perform the write operation in chunks of 16 bytes uint8_t clear_buffer[16] = {0}; while (clear_start < header.used_len) { size_t chunk_size = MIN_MEM(clear_len, sizeof(clear_buffer)); BSP_EE24_Write(clear_start, clear_buffer, chunk_size); clear_start += chunk_size; } } /** * migrate form diffrent versions of the eeprom */ void BSP_EE24_TableMigrate(uint32_t ee_version) { if(ee_version == PartionTableVersion) { // current fw version, do nothing return; } switch (ee_version) { default: // undefined write zeros. BSP_EE24_FullClear(); break; } }