/** ****************************************************************************** * @file eeprom.c * @author ECS - Zed Kazharov * @version V1.0.0 * @date 10-Jan-2023 * @brief Virtual EEPROM in FLASH memory * * Beschreibung * * ****************************************************************************** */ #include "eeprom.h" #include "stdio.h" #include "string.h" /********************************************************/ // Eeprom state related defines /*****************EEPROM_EMULATOR************************/ typedef struct { // Schnittstellenparameter uint32_t baudrate; uint16_t parityMode; uint16_t stopBits; uint16_t slaveAddress; // Cell Parameter uint16_t ovpAlarm; uint16_t lvpAlarm; uint16_t ovpStart; uint16_t ovpStop; uint16_t lvpStart; uint16_t lvpStop; uint16_t vShutdownStart; uint16_t vShutdownStop; int16_t otShutdownStart; int16_t otShutdownStop; int16_t utpChargeStart; int16_t utpChargeStop; int16_t utpDischargeStart; int16_t utpDischargeStop; uint16_t lvpTime; uint16_t defaultBalVoltage; // tempco int16_t refTemp; int16_t ovpAlarmTempco; int16_t lvpAlarmTempco; int16_t ovpStartTempco; int16_t ovpStopTempco; int16_t lvpStartTempco; int16_t lvpStopTempco; int16_t vShutdownStartTempco; int16_t vShutdownStopTempco; int16_t balancerVoltageTempco; uint16_t lockKey; }eeprom_data_t; typedef struct { // Geräteinformation uint32_t SN; uint8_t deviceInfoWritten; uint8_t resv[3]; }device_info_t; typedef struct { // Eeprom Status Infos uint32_t writeCounter; uint16_t structureSize; uint16_t revisionInfo; uint8_t firstStartId; }eeprom_state_t; typedef struct { // Eeprom Status Infos uint16_t cycleCounter; uint16_t minVoltage; uint16_t maxVoltage; int16_t minTemperature; int16_t maxTemperature; uint16_t criticalOverTempTime; uint16_t criticalUnderTempTime; uint16_t criticalOvervoltageTime; uint16_t criticalUndervoltageTime; }log_data_t; // fasse zu einer Struktur zusammen um nachher einfach darauf zugreifen zu können typedef struct { eeprom_data_t changedData; eeprom_state_t eepromState; device_info_t deviceInfo; log_data_t logData; }eeprom_stored_data_t; // Flash related defines #define USER_FLASH_BASE_ADRESS FLASH_BASE #define USER_FLASH_SIZE FLASH_SIZE //#define USER_FLASH_END ((USER_FLASH_BASE_ADRESS + USER_FLASH_SIZE) - 1) #define USER_FLASH_END (USER_FLASH_BASE_ADRESS + USER_FLASH_SIZE) #define USER_FLASH_PAGE_SIZE (0x800) // Eeprom emulator related defines #define NUMBER_OF_PAGES (2) #define USER_EEPROM_BASE_ADRESS (USER_FLASH_END - (USER_FLASH_PAGE_SIZE * NUMBER_OF_PAGES)) // Data to store reated defines #define SIZEOF_DEFAULT_EEPROM_DATA (sizeof(eeprom_data_t)) #define SIZEOF_CHANGED_EEPROM_DATA (sizeof(eeprom_data_t)) #define SIZEOF_DEVICE_INFO (sizeof(device_info_t)) #define SIZEOF_EEPROM_STATE (sizeof(eeprom_state_t)) #define SIZE_OF_DATA_TO_STORE (SIZEOF_CHANGED_EEPROM_DATA + SIZEOF_DEVICE_INFO + SIZEOF_EEPROM_STATE) // Adress related defines #define EEPROM_ADRESS_FIRST_START_ID (USER_EEPROM_BASE_ADRESS - 1 + SIZE_OF_DATA_TO_STORE - 1 - SIZEOF_DEVICE_INFO - 1 - 1) #define FIRST_START_ID (1) static uint32_t GetPage(uint32_t Address); static HAL_StatusTypeDef getEEPROMData(uint32_t address, uint8_t * data, uint32_t len); // muss modulo 8 noch hinzufügen wg 8 byte alignement static uint64_t eepromData[(SIZE_OF_DATA_TO_STORE / 8) + 1]; static uint64_t eepromLogData[(sizeof(log_data_t) / 8) + 1]; static FLASH_EraseInitTypeDef EraseInitStruct = {0}; extern uint16_t savedLockKey; static const eeprom_data_t defaultEepromData = { // Schnittstellenparameter MB_BAUDRATE_DEFAULT, MB_PARITY_MODE_DEFAULT, MB_STOPBIT_MODE_DEFAULT, /*uint16_t stopbitmode, reserviert;*/ MB_SLAVE_ADDRESS_DEFAULT, /*uint16_t slave_adress;*/ OVP_ALARM_VOLTAGE_DEFAULT, LVP_ALARM_VOLTAGE_DEFAULT, OVP_START_VOLTAGE_DEFAULT, OVP_STOPP_VOLTAGE_DEFAULT, LVP_START_VOLTAGE_DEFAULT, LVP_STOPP_VOLTAGE_DEFAULT, VOLTAGE_SHUTDOWN_START_VOLTAGE_DEFAULT, VOLTAGE_SHUTDOWN_STOPP_VOLTAGE_DEFAULT, OVERTEMPPROTECTION_START_DEFAULT, OVERTEMPPROTECTION_STOP_DEFAULT, UNDERTEMPPROTECTION_CHARGE_START_DEFAULT, UNDERTEMPPROTECTION_CHARGE_STOP_DEFAULT, UNDERTEMPPROTECTION_DISCHARGE_START_DEFAULT, UNDERTEMPPROTECTION_DISCHARGE_STOP_DEFAULT, LVP_TIME_DEFAULT, BAL_VOLTAGE_DEFAULT, BASIS_TEMP_DEFAULT, OVP_ALARM_TEMPCO_DEFAULT, LVP_ALARM_TEMPCO_DEFAULT, OVP_START_TEMPCO_DEFAULT, OVP_STOPP_TEMPCO_DEFAULT, LVP_START_TEMPCO_DEFAULT, LVP_STOPP_TEMPCO_DEFAULT, V_SHUTDOWN_START_TEMPCO_DEFAULT, V_SHUTDOWN_STOPP_TEMPCO_DEFAULT, BAL_TEMPCO_DEFAULT, 0, //Lockkey, Default keiner! }; /** * @brief Gets the page of a given address * @param Addr: Address of the FLASH Memory * @retval The page of a given address */ static uint32_t GetPage(uint32_t Addr) { return (Addr - FLASH_BASE) / FLASH_PAGE_SIZE; } static HAL_StatusTypeDef getEEPROMData(uint32_t address, uint8_t * data, uint32_t len) { uint32_t i = 0; uint8_t daten; if((address + len) > USER_FLASH_END) { return HAL_ERROR; } for(i = 0; i < len; i ++) { data[i] = *((uint8_t *) (address + i)); } return HAL_OK; } bool EEPROM_isFirstStart() { uint8_t firstStartCatcher; if(getEEPROMData(EEPROM_ADRESS_FIRST_START_ID, (uint8_t *)&firstStartCatcher, 1) != HAL_OK) return HAL_ERROR; if(firstStartCatcher != FIRST_START_ID) { printf ("First start detected\n"); return true; } else { printf ("previous config present\n"); return false; } } HAL_StatusTypeDef EEPROM_fullRestore(sys_data_t * data, bool keepSN) { eeprom_stored_data_t * dataToStore; uint32_t PageError; uint32_t Address; uint32_t x; printf("EEPROM FULL RESTORE!\n"); /****************LESE_DEFAULT_WERTE************************/ dataToStore = (eeprom_stored_data_t *) eepromData; memcpy( (void *) &dataToStore->changedData, (void*) &defaultEepromData, sizeof(dataToStore->changedData)) ; // Eeprom Status Infos dataToStore->eepromState.writeCounter ++; dataToStore->eepromState.structureSize = sizeof(eeprom_stored_data_t); dataToStore->eepromState.revisionInfo = 0; dataToStore->eepromState.firstStartId = FIRST_START_ID; /****************PAGE_LÖSCHEN********************/ HAL_FLASH_Unlock(); // check for PG bit set if so clear bit FLASH_WaitForLastOperation(1000); if(READ_BIT(FLASH->CR, FLASH_CR_PG)) { CLEAR_BIT(FLASH->CR, FLASH_CR_PG); } /* Fill EraseInit structure*/ //Speicherung in vorletzter page, deshalb diese löschen. //Log Daten kommen in die letzte page EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Page = FLASH_PAGE_NB - 2; //GetPage(USER_EEPROM_BASE_ADRESS); EraseInitStruct.NbPages = 1; /* erase Sektoren daten d+rfen nicht im instuction cache liegen */ if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) { while (1) { // ERROR HAL_FLASH_GetError() kann info geben } } /****************IM_FLASH_SPEICHERN********************/ /* programmiere uint64_t */ Address = USER_EEPROM_BASE_ADRESS; x = 0; while (Address < (USER_EEPROM_BASE_ADRESS + SIZE_OF_DATA_TO_STORE)) { if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, eepromData[x]) == HAL_OK) { Address = Address + 8; x ++; } else { /* Error occurred while writing data in Flash memory. User can add here some code to deal with this error */ while (1) { // ERROR } } } /* Lock the Flash */ HAL_FLASH_Lock(); /****************AUSLESEN_UND_PRÜFEN********************/ return EEPROM_readConfig(data); } HAL_StatusTypeDef EEPROM_storeConfig(sys_data_t * data,bool withSN, bool saveNewKey) { eeprom_stored_data_t * dataToStore; uint32_t PageError; uint32_t Address; uint32_t x; /****************LESE_WERTE_AUS_SYSDATA*********************/ printf("EEPROM STORE CONFIG!\n"); dataToStore = (eeprom_stored_data_t *) eepromData; // Schnittstellenparameter dataToStore->changedData.baudrate = data->s.baudrate; dataToStore->changedData.parityMode = data->s.parityMode; dataToStore->changedData.stopBits = data->s.stopBits; dataToStore->changedData.slaveAddress = data->s.slaveAddress; // Cell Parameter dataToStore->changedData.ovpAlarm = data->s.ovpAlarm; dataToStore->changedData.lvpAlarm = data->s.lvpAlarm; dataToStore->changedData.ovpStart = data->s.ovpStart; dataToStore->changedData.ovpStop = data->s.ovpStop; dataToStore->changedData.lvpStart = data->s.lvpStart; dataToStore->changedData.lvpStop = data->s.lvpStop; dataToStore->changedData.vShutdownStart = data->s.vShutdownStart; dataToStore->changedData.vShutdownStop = data->s.vShutdownStop; dataToStore->changedData.otShutdownStart = data->s.otShutdownStart; dataToStore->changedData.otShutdownStop = data->s.otShutdownStop; dataToStore->changedData.utpChargeStart = data->s.utpChargeStart; dataToStore->changedData.utpChargeStop = data->s.utpChargeStop; dataToStore->changedData.utpDischargeStart = data->s.utpDischargeStart; dataToStore->changedData.utpDischargeStop = data->s.utpDischargeStop; dataToStore->changedData.lvpTime = data->s.lvpTime; dataToStore->changedData.defaultBalVoltage = data->s.defaultBalVoltage; // tempco dataToStore->changedData.refTemp = data->s.refTemp; dataToStore->changedData.ovpAlarmTempco = data->s.ovpAlarmTempco; dataToStore->changedData.lvpAlarmTempco = data->s.lvpAlarmTempco; dataToStore->changedData.ovpStartTempco = data->s.ovpStartTempco; dataToStore->changedData.ovpStopTempco = data->s.ovpStopTempco; dataToStore->changedData.lvpStartTempco = data->s.lvpStartTempco; dataToStore->changedData.lvpStopTempco = data->s.lvpStopTempco; dataToStore->changedData.vShutdownStartTempco = data->s.vShutdownStartTempco; dataToStore->changedData.vShutdownStopTempco = data->s.vShutdownStopTempco; dataToStore->changedData.balancerVoltageTempco = data->s.balancerVoltageTempco; if (saveNewKey) { dataToStore->changedData.lockKey = data->s.newLockKey; } else { dataToStore->changedData.lockKey = savedLockKey; } // Eeprom Status Infos dataToStore->eepromState.writeCounter ++ ; dataToStore->eepromState.structureSize = sizeof(eeprom_stored_data_t); dataToStore->eepromState.revisionInfo = 0; dataToStore->eepromState.firstStartId = FIRST_START_ID; if (withSN) { printf("Writing SN!\n"); dataToStore->deviceInfo.SN = data->s.deviceSn; } /****************PAGE_LÖSCHEN********************/ HAL_FLASH_Unlock(); // check for PG bit set if so clear bit FLASH_WaitForLastOperation(1000); if(READ_BIT(FLASH->CR, FLASH_CR_PG)) { CLEAR_BIT(FLASH->CR, FLASH_CR_PG); } /* Fill EraseInit structure*/ EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Page = FLASH_PAGE_NB - 2; EraseInitStruct.NbPages = 1; /* erase Sektoren daten dürfen nicht im instuction cache liegen */ if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) { while (1) { // ERROR HAL_FLASH_GetError() kann info geben } } /****************IM_FLASH_SPEICHERN********************/ /* programmiere uint64_t */ Address = USER_EEPROM_BASE_ADRESS; x = 0; while (Address < (USER_EEPROM_BASE_ADRESS + SIZE_OF_DATA_TO_STORE)) { if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, eepromData[x]) == HAL_OK) { Address = Address + 8; x ++; } else { /* Error occurred while writing data in Flash memory. User can add here some code to deal with this error */ while (1) { // ERROR } } } /* Lock the Flash */ HAL_FLASH_Lock(); /****************AUSLESEN_UND_PRÜFEN********************/ return EEPROM_readConfig(data); } HAL_StatusTypeDef EEPROM_storeLogData() { uint32_t PageError; uint32_t Address; uint32_t x; log_data_t * logData; /****************LESE_WERTE_AUS_SYSDATA*********************/ printf("EEPROM STORE LOG DATA!\n"); //Zeiger auf Resevierten Ram Speicher, der für das speichern der Daten zuständig ist logData = (log_data_t *) eepromLogData; logData->cycleCounter = sysData.s.cycleCounter; logData->maxVoltage = sysData.s.maxVoltage; logData->minVoltage = sysData.s.minVoltage; logData->maxTemperature = sysData.s.maxTemperature; logData->minTemperature = sysData.s.minTemperature; logData->criticalOvervoltageTime = sysData.s.criticalOverVoltageTime; logData->criticalUndervoltageTime = sysData.s.criticalUnderVoltageTime; logData->criticalOverTempTime = sysData.s.criticalOverTempTime; logData->criticalUnderTempTime = sysData.s.criticalUnderTempTime; /****************PAGE_LÖSCHEN********************/ HAL_FLASH_Unlock(); // check for PG bit set if so clear bit FLASH_WaitForLastOperation(1000); if(READ_BIT(FLASH->CR, FLASH_CR_PG)) { CLEAR_BIT(FLASH->CR, FLASH_CR_PG); } /* Fill EraseInit structure*/ EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Page = FLASH_PAGE_NB - 1; // Page löschen EraseInitStruct.NbPages = 1; /* erase Sektoren daten dürfen nicht im instuction cache liegen */ if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) { printf("Error while deleting log data area in flash\n"); return HAL_ERROR; } /****************IM_FLASH_SPEICHERN********************/ /* programmiere uint64_t */ uint32_t startAdress = USER_EEPROM_BASE_ADRESS + FLASH_PAGE_SIZE; Address = startAdress; x = 0; while (Address < (startAdress + sizeof(log_data_t))) { if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, eepromLogData[x]) == HAL_OK) { Address = Address + 8; x ++; } else { printf("Error while saving data to flash\n"); return HAL_ERROR; } } /* Lock the Flash */ HAL_FLASH_Lock(); return HAL_OK; } HAL_StatusTypeDef EEPROM_ResetLogData() { uint32_t PageError; uint32_t Address; uint32_t x; log_data_t * logData; /****************LESE_WERTE_AUS_SYSDATA*********************/ printf("EEPROM STORE LOG DATA!\n"); //Zeiger auf Resevierten Ram Speicher, der für das speichern der Daten zuständig ist logData = (log_data_t *) eepromLogData; logData->cycleCounter = 0; logData->maxVoltage = 0; logData->minVoltage = UINT16_MAX; logData->maxTemperature = INT16_MIN; logData->minTemperature = INT16_MAX; logData->criticalOvervoltageTime = 0; logData->criticalUndervoltageTime = 0; logData->criticalOverTempTime = 0; logData->criticalUnderTempTime = 0; /****************PAGE_LÖSCHEN********************/ HAL_FLASH_Unlock(); // check for PG bit set if so clear bit FLASH_WaitForLastOperation(1000); if(READ_BIT(FLASH->CR, FLASH_CR_PG)) { CLEAR_BIT(FLASH->CR, FLASH_CR_PG); } /* Fill EraseInit structure*/ EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.Page = FLASH_PAGE_NB - 1; // Page löschen EraseInitStruct.NbPages = 1; /* erase Sektoren daten dürfen nicht im instuction cache liegen */ if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK) { printf("Error while deleting log data area in flash\n"); return HAL_ERROR; } /****************IM_FLASH_SPEICHERN********************/ /* programmiere uint64_t */ uint32_t startAdress = USER_EEPROM_BASE_ADRESS + FLASH_PAGE_SIZE; Address = startAdress; x = 0; while (Address < (startAdress + sizeof(log_data_t))) { if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, Address, eepromLogData[x]) == HAL_OK) { Address = Address + 8; x ++; } else { printf("Error while saving data to flash\n"); return HAL_ERROR; } } /* Lock the Flash */ HAL_FLASH_Lock(); return HAL_OK; } HAL_StatusTypeDef EEPROM_readConfig(sys_data_t * data) { eeprom_stored_data_t * dataToStore; /****************WERTE_AUS_FLASH_LESEN********************/ if(getEEPROMData(USER_EEPROM_BASE_ADRESS, (uint8_t *)eepromData, sizeof(eepromData)) != HAL_OK) return HAL_ERROR; dataToStore = (eeprom_stored_data_t *) eepromData; // Schnittstellenparameter data->s.baudrate = dataToStore->changedData.baudrate; data->s.parityMode = dataToStore->changedData.parityMode; data->s.stopBits = dataToStore->changedData.stopBits; data->s.slaveAddress = dataToStore->changedData.slaveAddress; // // Cell Parameter data->s.ovpAlarm = dataToStore ->changedData.ovpAlarm; data->s.lvpAlarm = dataToStore ->changedData.lvpAlarm; data->s.ovpStart = dataToStore ->changedData.ovpStart; data->s.ovpStop = dataToStore ->changedData.ovpStop; data->s.lvpStart = dataToStore ->changedData.lvpStart; data->s.lvpStop = dataToStore ->changedData.lvpStop; data->s.vShutdownStart = dataToStore->changedData.vShutdownStart; data->s.vShutdownStop = dataToStore->changedData.vShutdownStop; data->s.otShutdownStart = dataToStore->changedData.otShutdownStart; data->s.otShutdownStop = dataToStore->changedData.otShutdownStop; data->s.utpChargeStart = dataToStore->changedData.utpChargeStart; data->s.utpChargeStop = dataToStore->changedData.utpChargeStop; data->s.utpDischargeStart = dataToStore->changedData.utpDischargeStart; data->s.utpDischargeStop = dataToStore->changedData.utpDischargeStop; data->s.lvpTime = dataToStore->changedData.lvpTime; data->s.defaultBalVoltage = dataToStore->changedData.defaultBalVoltage; // tempco data->s.refTemp = dataToStore ->changedData.refTemp; data->s.ovpAlarmTempco = dataToStore ->changedData.ovpAlarmTempco; data->s.lvpAlarmTempco = dataToStore ->changedData.lvpAlarmTempco; data->s.ovpStartTempco = dataToStore ->changedData.ovpStartTempco; data->s.ovpStopTempco = dataToStore->changedData.ovpStopTempco; data->s.lvpStartTempco = dataToStore->changedData.lvpStartTempco; data->s.lvpStopTempco = dataToStore->changedData.lvpStopTempco; data->s.vShutdownStartTempco = dataToStore->changedData.vShutdownStartTempco; data->s.vShutdownStopTempco = dataToStore->changedData.vShutdownStopTempco; data->s.balancerVoltageTempco = dataToStore->changedData.balancerVoltageTempco; savedLockKey = dataToStore->changedData.lockKey; if (savedLockKey != 0) sysData.s.writeLocked = 1 ; // Geräteinformation data->s.deviceSn = dataToStore->deviceInfo.SN; // prüfe Eeprom Status Infos if(dataToStore->eepromState.structureSize != sizeof(eeprom_stored_data_t)) return HAL_ERROR; if(dataToStore->eepromState.revisionInfo != 0) return HAL_ERROR; if(dataToStore->eepromState.firstStartId != FIRST_START_ID) return HAL_ERROR; return HAL_OK; } HAL_StatusTypeDef EEPROM_readLogData() { log_data_t * logData; /****************WERTE_AUS_FLASH_LESEN********************/ if(getEEPROMData(USER_EEPROM_BASE_ADRESS + FLASH_PAGE_SIZE, (uint8_t *)eepromLogData, sizeof(eepromLogData)) != HAL_OK) return HAL_ERROR; logData = (log_data_t *) eepromLogData; sysData.s.cycleCounter = logData->cycleCounter; sysData.s.maxVoltage = logData->maxVoltage; sysData.s.minVoltage = logData->minVoltage; sysData.s.maxTemperature = logData->maxVoltage; sysData.s.minTemperature = logData->minTemperature; sysData.s.criticalOverVoltageTime = logData->criticalOvervoltageTime; sysData.s.criticalUnderVoltageTime = logData->criticalUndervoltageTime; sysData.s.criticalOverTempTime = logData->criticalOverTempTime; sysData.s.criticalUnderTempTime = logData->criticalUnderTempTime; return HAL_OK; }