/********************************************************************** * NAME: eeprom.c * * AUTHOR: Philip Johansson * * PURPOSE: Virtual EEPROM driver * * INFORMATION: * * This file mainly has two functions of which one brings the settings * * from EEPROM and the other stores them * * * * All values we want in EEPROM have to be added to the EEPROM_ID_t * * struct as well as defined in eeprom_Arr with a pointer to the data * * * * GLOBAL VARIABLES: * * Variable Type Description * * -------- ---- ----------- * * * **********************************************************************/ #include "config/eeprom.h" #include "drivers/adc.h" #include "drivers/uart1_inverter.h" #include "system_variables.h" #include "utilities.h" #include "stm32f4xx_revo.h" #include "Scheduler/scheduler.h" #include "drivers/failsafe_toggles.h" #include "drivers/motormix.h" #include "drivers/motors.h" /* Reads the EEPROM version from EEPROM - Is compared to EEPROM_SYS_VERSION */ uint8_t stored_eeprom_identifier; /* Buffer where we temporarily store profiles we not use as we erase eeprom before write */ uint8_t eeprom_profile_tmp_a[EEPROM_PROFILE_SIZE]; uint8_t eeprom_profile_tmp_b[EEPROM_PROFILE_SIZE]; /* The two temporary buffers are addressed through this array */ uint8_t * eeprom_profile_tmp_Arr[2] = { eeprom_profile_tmp_a, eeprom_profile_tmp_b }; /* Created CRC */ uint8_t calculated_crc; uint8_t read_crc; /* Defines which profile is active. Should not be changed other than calling setActiveProfile() */ ACTIVE_PROFILE active_profile = 1; // Between 1 .. 3 /* List of all EEPROM lists */ uint8_t eeprom_blocksize_Arr[4] = { EEPROM_HEADER_COUNT, EEPROM_SYS_COUNT, EEPROM_PROFILE_COUNT, EEPROM_FOOTER_COUNT }; /* General EEPROM data info. All data addressed needs both size and pointer */ typedef struct { uint32_t writeTypeId; uint32_t size; //Size of the data void * dataPtr; //pointer to the data, that should be saved to EEPROM } EEPROM_DATA_t; /* Data pointers and sizes for header content */ EEPROM_DATA_t eeprom_header_Arr[EEPROM_HEADER_COUNT] = { [EEPROM_VERSION] = { .size = sizeof(stored_eeprom_identifier), .dataPtr = &stored_eeprom_identifier, } }; /* Data pointers and sizes for sys content */ EEPROM_DATA_t eeprom_sys_Arr[EEPROM_SYS_COUNT] = { [EEPROM_ACTIVE_PROFILE] = { .size = sizeof(active_profile), .dataPtr = &active_profile, }, [EEPROM_ADC_SCALES] = { .size = sizeof(adcScaleStruct_t), .dataPtr = &adcScaleStruct_t, }, [EEPROM_UART1_RX_INV] = { .size = sizeof(bool), .dataPtr = &uart1_rx_inverter, }, /* Motor calibrate */ [EEPROM_MOTORCALIBRATE] = { .size = sizeof(bool), .dataPtr = &perfromMotorCalibration, }, /* Task eeprom values */ [EEPROM_PERIOD_SYSTEM] = { .size = sizeof(SystemTasks[TASK_SYSTEM].desiredPeriod), .dataPtr = &(SystemTasks[TASK_SYSTEM].desiredPeriod), }, [EEPROM_PERIOD_GYROPID] = { .size = sizeof(SystemTasks[TASK_GYROPID].desiredPeriod), .dataPtr = &(SystemTasks[TASK_GYROPID].desiredPeriod), }, [EEPROM_PERIOD_ACCELEROMETER] = { .size = sizeof(SystemTasks[TASK_ACCELEROMETER].desiredPeriod), .dataPtr = &(SystemTasks[TASK_ACCELEROMETER].desiredPeriod), }, [EEPROM_PERIOD_ATTITUDE] = { .size = sizeof(SystemTasks[TASK_ATTITUDE].desiredPeriod), .dataPtr = &(SystemTasks[TASK_ATTITUDE].desiredPeriod), }, [EEPROM_PERIOD_RX] = { .size = sizeof(SystemTasks[TASK_RX].desiredPeriod), .dataPtr = &(SystemTasks[TASK_RX].desiredPeriod), }, [EEPROM_PERIOD_RX_CLI] = { .size = sizeof(SystemTasks[TASK_RX_CLI].desiredPeriod), .dataPtr = &(SystemTasks[TASK_RX_CLI].desiredPeriod), }, [EEPROM_PERIOD_SERIAL] = { .size = sizeof(SystemTasks[TASK_SERIAL].desiredPeriod), .dataPtr = &(SystemTasks[TASK_SERIAL].desiredPeriod), }, [EEPROM_PERIOD_BATTERY] = { .size = sizeof(SystemTasks[TASK_BATTERY].desiredPeriod), .dataPtr = &(SystemTasks[TASK_BATTERY].desiredPeriod), }, #ifdef BARO [EEPROM_PERIOD_BARO] = { .size = sizeof(SystemTasks[TASK_BARO].desiredPeriod), .dataPtr = &(SystemTasks[TASK_BARO].desiredPeriod), }, #endif #ifdef COMPASS [EEPROM_PERIOD_COMPASS] = { .size = sizeof(SystemTasks[TASK_COMPASS].desiredPeriod), .dataPtr = &(SystemTasks[TASK_COMPASS].desiredPeriod), }, #endif #ifdef GPS [EEPROM_PERIOD_GPS] = { .size = sizeof(SystemTasks[TASK_GPS].desiredPeriod), .dataPtr = &(SystemTasks[TASK_GPS].desiredPeriod), }, #endif #ifdef SONAR [EEPROM_PERIOD_SONAR] = { .size = sizeof(SystemTasks[TASK_SONAR].desiredPeriod), .dataPtr = &(SystemTasks[TASK_SONAR].desiredPeriod), }, #endif #if defined(BARO) || defined(SONAR) [EEPROM_PERIOD_ALTITUDE] = { .size = sizeof(SystemTasks[TASK_ALTITUDE].desiredPeriod), .dataPtr = &(SystemTasks[TASK_ALTITUDE].desiredPeriod), }, #endif #if BEEPER [EEPROM_PERIOD_BEEPER] = { .size = sizeof(SystemTasks[TASK_BEEPER].desiredPeriod), .dataPtr = &(SystemTasks[TASK_BEEPER].desiredPeriod), }, #endif /* Motormix values */ [EEPROM_MOTORMIX_CONFIG] = { .size = sizeof(mixerConfig_s), .dataPtr = &(mixerConfig), }, /* Flags eeprom values */ [EEPROM_FLAG_ARM] = { .size = sizeof(flags_Configuration_t), .dataPtr = &(flagConfigArr[FLAG_CONFIGURATION_ARM]), }, [EEPROM_FLAG_FLIGHTMODE_ACCELEROMETER] = { .size = sizeof(flags_Configuration_t), .dataPtr = &(flagConfigArr[FLAG_CONFIGURATION_FLIGHTMODE_ACCELEROMETER]), }, [EEPROM_FLAG_FLIGHTMODE_BAROMETER] = { .size = sizeof(flags_Configuration_t), .dataPtr = &(flagConfigArr[FLAG_CONFIGURATION_FLIGHTMODE_BAROMETER]), }, [EEPROM_FLAG_FLIGHTMODE_COMPASS] = { .size = sizeof(flags_Configuration_t), .dataPtr = &(flagConfigArr[FLAG_CONFIGURATION_FLIGHTMODE_COMPASS]), }, [EEPROM_FLAG_FLIGHTMODE_GPS] = { .size = sizeof(flags_Configuration_t), .dataPtr = &(flagConfigArr[FLAG_CONFIGURATION_FLIGHTMODE_GPS]), }, [EEPROM_FLAG_MIXERFULLSCALE] = { .size = sizeof(flags_Configuration_t), .dataPtr = &(flagConfigArr[FLAG_CONFIGURATION_MIXERFULLSCALE]), }, [EEPROM_FLAG_MIXERLOWSCALE] = { .size = sizeof(flags_Configuration_t), .dataPtr = &(flagConfigArr[FLAG_CONFIGURATION_MIXERLOWSCALE]), }, [EEPROM_FLAG_FLIGHTMODE_3] = { .size = sizeof(flags_Configuration_t), .dataPtr = &(flagConfigArr[FLAG_CONFIGURATION_FLIGHTMODE_3]), }, }; /* Data pointers and sizes for profile content */ EEPROM_DATA_t eeprom_profile_Arr[EEPROM_PROFILE_COUNT] = { [EEPROM_PID_ROLL_KP] = { .size = sizeof(pid_pitch_pk), .dataPtr = &pid_pitch_pk, } }; /* Data pointers and sizes for footer content */ EEPROM_DATA_t eeprom_footer_Arr[EEPROM_FOOTER_COUNT] = { [EEPROM_CRC] = { .size = sizeof(calculated_crc), .dataPtr = &calculated_crc, } }; /* List of all EEPROM content arrays */ EEPROM_DATA_t * eeprom_Arr_list[4] = { eeprom_header_Arr, eeprom_sys_Arr, eeprom_profile_Arr, eeprom_footer_Arr }; /*********************************************************************** * BRIEF: Reads Calculates the combined size of all elements * * in an EEPROM_DATA_t array * * INFORMATION: return value is in bytes * ***********************************************************************/ uint16_t eepromArrSize(EEPROM_DATA_t * data) { int size = 0; for (int j = 0; j < 4; j++) { if (data == eeprom_Arr_list[j]) for (int i = 0; i < eeprom_blocksize_Arr[j]; i++) { size += data[i].size; } } if (size == 0) Error_Handler(); // We should never get here return size; } /*********************************************************************** * BRIEF: Increments the checksum * * INFORMATION: XOR operator byte per byte * ***********************************************************************/ uint8_t incrementChecksum(uint8_t crc, const void *data, uint32_t length) { const uint8_t * addrIterator = (const uint8_t *)data; const uint8_t * addrEnd = addrIterator + length; for (;addrIterator != addrEnd; addrIterator++) crc ^= *addrIterator; return crc; } /*********************************************************************** * BRIEF: Stores one data type at the time from eepromArr to EEPROM * * INFORMATION: Writes byte per byte until end of data * ***********************************************************************/ void writeEepromExtension(uint32_t addr,EEPROM_DATA_t * data, uint32_t id) { for (int i = 0; i < data[id].size; i ++) HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, addr + i , *((uint8_t*)(data[id].dataPtr + i))); } /*********************************************************************** * BRIEF: Writes EEPROM data to FLASH. Requires the next active profile * * to be selected (current profile can be used as input) * * INFORMATION: passes all data directly from where they are defined * ***********************************************************************/ void writeEEPROM(uint8_t new_profile) { /* Add size and a pointer to the data for each value * Each value when saved will store the data that it points to. * When loaded the system will know what the value for each id should * point to and it can read the data directly to that value which is pointed to*/ uint32_t addrIterator = EEPROM_BASE_ADDR; uint8_t crc = 0; // Initializing the checksum to 0 uint8_t profile_counter = 0; uint8_t buff_counter = 0; ACTIVE_PROFILE old_profile = active_profile; HAL_FLASH_Unlock(); __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR ); //FLASH_Erase_Sector(((uint32_t)11U),VOLTAGE_RANGE_3); FLASH_Erase_Sector(EEPROM_SECTOR_ERASE, VOLTAGE_RANGE_3); stored_eeprom_identifier = (uint8_t)EEPROM_SYS_VERSION; for (int j = 0; j < 4; j++) { // We exclude reading of profiles not active to memory if (!((j == 2) && (profile_counter != ((uint8_t)active_profile - 1) ))) { if (j == 1) // Writing sys we store the NEW profile active_profile = new_profile; for (int i = 0; i < eeprom_blocksize_Arr[j]; i++) { if (eeprom_Arr_list[j] == eeprom_footer_Arr) calculated_crc = crc; writeEepromExtension(addrIterator, eeprom_Arr_list[j], i); addrIterator += eeprom_Arr_list[j][i].size; crc = incrementChecksum(crc, eeprom_Arr_list[j][i].dataPtr, eeprom_Arr_list[j][i].size); } if (j == 1) active_profile = old_profile; // restore the old profile } else { if (buff_counter >= 2) Error_Handler(); int eeprom_profile_arr_size = eepromArrSize(eeprom_profile_Arr); for (int i = 0; i < eeprom_profile_arr_size; i ++) HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, addrIterator + i , *((uint8_t*)(eeprom_profile_tmp_Arr[buff_counter] + i))); crc = incrementChecksum(crc, eeprom_profile_tmp_Arr[buff_counter], eepromArrSize(eeprom_profile_Arr)); buff_counter++; // move on to next buffer // Adding size of eeprom array addrIterator += eeprom_profile_arr_size; } // Halt iterator j @2 (profile) for 3 iterations (3 profiles) if ((j == 2) && (profile_counter < 2)) { profile_counter++; j--; // We do this to keep j = 2 for three iterations (looping through all profiles) } } HAL_FLASH_Lock(); } /*********************************************************************** * BRIEF: Restores one data type at the time from eepromArr from EEPROM * * INFORMATION: * ***********************************************************************/ void readEepromExtension(uint32_t addr, EEPROM_DATA_t * data, uint32_t id) { for (int i = 0; i < data[id].size; i++) *(uint8_t*)(data[id].dataPtr + i) = *( uint8_t*)(addr + i * sizeof(uint8_t)); } /*********************************************************************** * BRIEF: Copies a profile from EEPROM into a buffer * * INFORMATION: Run once for every buffer * ***********************************************************************/ void readEepromBuff(uint32_t addr, uint8_t * eeprom_profile_tmp, uint32_t length) { for (int i = 0; i < length; i++) *(uint8_t*)(eeprom_profile_tmp + i) = *(uint8_t*)(addr + i * sizeof(uint8_t)); } /*********************************************************************** * BRIEF: Verifies EEPROM only * * INFORMATION: compares EEPROM version and makes CRC checks * * Return value is true if okay * ***********************************************************************/ bool scanEEPROM(void) { uint8_t crc = 0; uint8_t old_crc = calculated_crc; // store to restore uint8_t profile_counter = 0; // To iterate through the profiles uint32_t addrIterator = EEPROM_BASE_ADDR; HAL_FLASH_Unlock(); HAL_Delay(100); for (int j = 0; j < 4; j++) // 3 to skip footer from CRC calculation { for (int i = 0; i < eeprom_blocksize_Arr[j]; i++) { // Store data only for Header (EEPROM version) and footer (CRC) while scanning if ((eeprom_Arr_list[j] == eeprom_header_Arr) || (eeprom_Arr_list[j] == eeprom_footer_Arr)) readEepromExtension(addrIterator, eeprom_Arr_list[j], i); // Checksum not incremented for footer if (eeprom_Arr_list[j] != eeprom_footer_Arr) crc = incrementChecksum(crc, (int*)addrIterator, eeprom_Arr_list[j][i].size); addrIterator += eeprom_Arr_list[j][i].size; } // Halt iterator j @2 (profile) for 3 iterations (3 profiles) if ((j == 2) && (profile_counter < 2)) { profile_counter++; j--; // We do this to keep j = 2 for three iterations (looping through all profiles) } } HAL_FLASH_Lock(); /* Check to see if CRC matches */ if ( (crc == calculated_crc) && (stored_eeprom_identifier == (uint8_t)EEPROM_SYS_VERSION) ) { return true; } else { // ERROR!!! CORRUPT EEPROM, RESETTING calculated_crc = old_crc; #ifdef USE_DEBUG_EEPROM Error_Handler(); #endif resetEEPROM(); // Reinitialize eeprom with default values. return true /* false */; } } /*********************************************************************** * BRIEF: Reads EEPROM data from FLASH * * INFORMATION: passes all data directly to where they are defined * ***********************************************************************/ bool readEEPROM() { bool success; uint8_t profile_counter = 0; uint8_t buff_counter = 0; uint32_t addrIterator = EEPROM_BASE_ADDR; /* This check has to be done as not to overwrite memory with bad data */ if ((success = scanEEPROM())) { HAL_FLASH_Unlock(); HAL_Delay(100); for (int j = 0; j < 3; j++) // 3 excludes the footer { // We exclude reading of profiles not active to memory if (!((j == 2) && (profile_counter != (uint8_t)(active_profile - 1)))) { for (int i = 0; i < eeprom_blocksize_Arr[j]; i++) { readEepromExtension(addrIterator, eeprom_Arr_list[j], i); addrIterator += eeprom_Arr_list[j][i].size; } } // The two not loaded profiles are stored to buffers else { if (buff_counter >= 2) Error_Handler(); // Import the data from eeprom to buffer readEepromBuff((uint32_t*)addrIterator, (uint8_t*)eeprom_profile_tmp_Arr[buff_counter], EEPROM_PROFILE_SIZE); buff_counter++; // Adding size of eeprom array addrIterator += eepromArrSize(eeprom_profile_Arr); } // Halt iterator j @2 (profile) for 3 iterations (3 profiles) if ((j == 2) && (profile_counter < 2)) { profile_counter++; j--; // We do this to keep j = 2 for three iterations (looping through all profiles) } } HAL_FLASH_Lock(); } else { Error_Handler(); } return success; } /*********************************************************************** * BRIEF: Choose a profile between 1 .. 3 * * INFORMATION: The current changes will be saved * ***********************************************************************/ void setActiveProfile(ACTIVE_PROFILE new_profile) { // Error handler if (new_profile < 1 || new_profile > 3) Error_Handler(); writeEEPROM(new_profile); readEEPROM(); } /*********************************************************************** * BRIEF: Writes current profile values to all EEPROM profiles * * INFORMATION: used when EEPROM is corrupt or there is a version * * mismatch * ***********************************************************************/ void resetEEPROM(void) { /* check so that the profile buffer sizes are not smaller than the size of one profile */ if (EEPROM_PROFILE_SIZE < eepromArrSize(eeprom_profile_Arr) ) Error_Handler(); // We need to increment the EEPROM_PROFILE_SIZE uint32_t bufferIterator = 0; //Loop through all the values in the EEPROM profile for (int j = 0; j < EEPROM_PROFILE_COUNT; j++) { //for each value loop on its byte size and then write byte by byte to the buffers for (int i = 0; i < eeprom_profile_Arr[i].size; i++) { *(uint8_t*)(eeprom_profile_tmp_Arr[0] + bufferIterator) = *(uint8_t*)(eeprom_profile_Arr[j].dataPtr + i); *(uint8_t*)(eeprom_profile_tmp_Arr[1] + bufferIterator) = *(uint8_t*)(eeprom_profile_Arr[j].dataPtr + i); bufferIterator++; } } writeEEPROM(active_profile); } /*********************************************************************** * BRIEF: Writes EEPROM data to FLASH without the need of setting next * * active profile * * INFORMATION: Keeps the current profile active * ***********************************************************************/ void saveEEPROM() { writeEEPROM(active_profile); } void * getDataAddresFromID(uint16_t id, uint8_t dataType) { void * toReturn = NULL; //switch on the dataType to return it will return from a different array of data //one for system vars another for the profile vars etc switch(dataType) { case EEPROM_VALUE_TYPE_SYSTEM: toReturn = eeprom_sys_Arr[id].dataPtr; break; case EEPROM_VALUE_TYPE_PROFILE: toReturn = eeprom_profile_Arr[id].dataPtr; break; case EEPROM_VALUE_TYPE_HEADER: toReturn = eeprom_header_Arr[id].dataPtr; break; case EEPROM_VALUE_TYPE_FOOTER: toReturn = eeprom_footer_Arr[id].dataPtr; break; default: break; } return toReturn; } void defaultEEPROM(void) { //Erase the secotr HAL_FLASH_Unlock(); __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR ); FLASH_Erase_Sector(EEPROM_SECTOR_ERASE, VOLTAGE_RANGE_3); HAL_FLASH_Lock(); //Reboot the system HAL_NVIC_SystemReset(); } int getActiveProfile() { return active_profile; }