ardupilot/libraries/AP_HAL_F4Light/hardware/osd/osd_eeprom.cpp

102 lines
2.7 KiB
C++

/*
(c) 2017 night_ghost@ykoctpa.ru
EEPROM emulation for OSD needs. Uses 1 16K page of flash to provide 2K of eeprom so it does wear
leveling of 8, excluding the case when we should write 0xff value, but OSD never writes it
in time of page erase all data buffered in RAM so will be lost in case of unexpected power off, but there is no in-flight writes
*/
#include "osd_eeprom.h"
#include <AP_HAL/AP_HAL.h>
extern const AP_HAL::HAL& hal;
#include <utility>
#include <util.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
uint32_t OSD_EEPROM::ee_ptr=0;
static uint8_t data[EEPROM_SIZE] IN_CCM; // buffer for all data to be cached
void OSD_EEPROM::init(){
for(uint16_t i=0;i<EEPROM_SIZE; i++){ // read out all to buffer
data[i] = _read(i);
}
}
uint8_t OSD_EEPROM::read(uint16_t addr){
return data[addr];
}
void OSD_EEPROM::write(uint16_t addr, uint8_t val){
data[addr]=val;
_write(addr, val); //
}
uint8_t OSD_EEPROM::_read(uint16_t addr){
for(uint8_t i=PAGE_SIZE/EEPROM_SIZE; i!=0;){
// look most recent value from last stage
i--;
uint32_t ea = EEPROM_PAGE + i*EEPROM_SIZE + addr;
uint8_t val = read_8(ea);
if(val != 0xFF) {
ee_ptr=ea; // remember last read address
return val; // first non-FF is a value
}
}
ee_ptr = EEPROM_PAGE + addr;
return 0xff; // got to begin and still FF - really FF
}
void OSD_EEPROM::_write(uint16_t addr, uint8_t val){
uint8_t cv = _read(addr);
if(cv == val) return; // already is
if( /* we can write - there is no '0' where we need '1' */ (~cv & val)==0 ){
FLASH_Unlock_dis();
write_8(ee_ptr, val); // just overwrite last value
goto done;
}
if(val != 0xFF){ // the only way to write FF is to clear all - but OSD don't writes it
for(uint8_t i=0; i<PAGE_SIZE/EEPROM_SIZE; i++){
// look 0xFF
uint32_t ea = EEPROM_PAGE + i*EEPROM_SIZE + addr;
cv = read_8(ea);
if(cv == 0xFF) { // empty
FLASH_Unlock_dis();
write_8(ea, val);
goto done;
}
}
}
// no empty slots - so need to erase page
// 1st - erase page. power loss here cause data loss! In execution time CPU is frozen!
printf("\nEEprom_OSD erase page %d\n ", (uint16_t)((EEPROM_PAGE & 0x00ffffff) / 0x4000) ); // clear high byte of address and count 16K blocks
FLASH_Unlock_dis();
erasePageByAddress(EEPROM_PAGE);
// 2rd write data back to the beginning of Flash page
for(uint16_t i=0;i<EEPROM_SIZE; i++){
write_8(EEPROM_PAGE+i, data[i]);
}
done:
FLASH_Lock_check();
}