1
0
Fork 0
mirror of https://github.com/EdgeTX/edgetx.git synced 2025-07-26 09:45:16 +03:00

EEPROM on Sky9x

This commit is contained in:
Bertrand Songis 2015-04-14 08:57:25 +02:00 committed by bsongis
parent c6cf0f915e
commit 1964ac207c
14 changed files with 476 additions and 571 deletions

View file

@ -81,3 +81,29 @@ void eeLoadModelHeaders()
}
}
#endif
void eeReadAll()
{
// TODO merge eepromOpen and eepromCheck
if (!eepromOpen() || eepromCheck() < 0 || !eeLoadGeneral()) {
eeErase(true);
}
else {
eeLoadModelHeaders();
}
stickMode = g_eeGeneral.stickMode;
#if defined(CPUARM)
for (uint8_t i=0; languagePacks[i]!=NULL; i++) {
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
currentLanguagePackIdx = i;
currentLanguagePack = languagePacks[i];
}
}
#endif
#if !defined(CPUARM)
eeLoadModel(g_eeGeneral.currModel);
#endif
}

View file

@ -55,7 +55,6 @@ void eeDirty(uint8_t msk);
void eeCheck(bool immediately);
void eeReadAll();
bool eeModelExists(uint8_t id);
void eeLoadModelName(uint8_t id, char *name);
void eeLoadModel(uint8_t id);
bool eeConvert();
void eeErase(bool warn);

View file

@ -40,160 +40,117 @@
#include "opentx.h"
#include "timers.h"
volatile uint32_t Spi_complete; // TODO in the driver ?
#define EEPROM_SIZE (4*1024*1024/8)
#define EEPROM_BLOCK_SIZE (4*1024)
#define EEPROM_MARK 0x84697771 /* thanks ;) */
#define EEPROM_FILE_SIZE (8*1024)
#define EEPROM_BUFFER_SIZE 256
#define EEPROM_FAT_SIZE 128
#define EEPROM_MAX_FILES (EEPROM_SIZE / EEPROM_FILE_SIZE)
#define FIRST_FILE_AVAILABLE (1+MAX_MODELS)
// Logic for storing to EEPROM/loading from EEPROM
// If main needs to wait for the eeprom, call mainsequence without actioning menus
// General configuration
// 'main' set flag STORE_GENERAL
// 'eeCheck' sees flag STORE_GENERAL, copies data, starts 2 second timer, clears flag STORE_GENERAL
// 'eeCheck' sees 2 second timer expire, locks copy, initiates write, enters WRITE_GENERAL mode
// 'eeCheck' completes write, unlocks copy, exits WRITE_GENERAL mode
// 'main' set flag STORE_MODEL(n)
// 'main' set flag STORE_MODEL_TRIM(n)
// 'main' needs to load a model
// These may not be needed, or might just be smaller
// TODO in the driver ?
uint8_t Spi_tx_buf[24] ;
uint8_t Spi_rx_buf[24] ;
struct t_file_entry File_system[MAX_MODELS+1] ;
// TODO check everything here
uint8_t Eeprom32_process_state = E32_IDLE;
uint8_t Eeprom32_state_after_erase ;
uint8_t Eeprom32_write_pending ;
uint8_t Eeprom32_file_index ;
uint8_t *Eeprom32_buffer_address ;
uint8_t *Eeprom32_source_address ;
uint32_t Eeprom32_address ;
uint32_t Eeprom32_data_size ;
#define EE_NOWAIT 1
uint32_t get_current_block_number( uint32_t block_no, uint16_t *p_size, uint32_t *p_seq ) ;
void write32_eeprom_block( uint32_t eeAddress, register uint8_t *buffer, uint32_t size, uint32_t immediate=0 ) ;
// New file system
// Start with 16 model memories, initial test uses 34 and 35 for these
// Blocks 0 and 1, general
// Blocks 2 and 3, model 1
// Blocks 4 and 5, model 2 etc
// Blocks 32 and 33, model 16
uint8_t Current_general_block ; // 0 or 1 is active block
uint8_t Other_general_block_blank ;
struct t_eeprom_buffer
PACK(struct EepromHeaderFile
{
struct t_eeprom_header header ;
union t_eeprom_data
uint8_t exists:1;
uint8_t index:7;
});
PACK(struct EepromHeader
{
EEGeneral general_data ;
ModelData model_data ;
uint8_t bytes[4096-sizeof(t_eeprom_header)];
} data ;
} Eeprom_buffer ;
uint32_t mark;
EepromHeaderFile files[EEPROM_MAX_FILES];
});
void eeDeleteModel(uint8_t id)
EepromHeader eepromHeader;
EepromWriteState eepromWriteState = EEPROM_IDLE;
uint8_t eepromWriteFileIndex = FIRST_FILE_AVAILABLE;
uint16_t eepromWriteSize;
uint8_t * eepromWriteSourceAddr;
uint32_t eepromWriteDestinationAddr;
uint16_t eepromFatAddr = 0;
uint16_t eepromPreviousFatAddr;
uint8_t eepromWriteBuffer[EEPROM_BUFFER_SIZE];
#define COMMAND_BLOCK_ERASE 0x20
#define COMMAND_WRITE 0x02
#define COMMAND_READ 0x03
void eepromWaitSpiComplete()
{
eeCheck(true);
memset(modelHeaders[id].name, 0, sizeof(g_model.header.name));
Eeprom32_source_address = (uint8_t *)&g_model ; // Get data from here
Eeprom32_data_size = 0 ; // This much
Eeprom32_file_index = id + 1 ; // This file system entry
Eeprom32_process_state = E32_BLANKCHECK ;
eeWaitFinished();
while (!Spi_complete) {
SIMU_SLEEP(5/*ms*/);
}
Spi_complete = false;
}
bool eeCopyModel(uint8_t dst, uint8_t src)
void eepromWaitReadStatus()
{
// eeCheck(true) should have been called before entering here
uint16_t size = File_system[src+1].size ;
read32_eeprom_data( (File_system[src+1].block_no << 12) + sizeof( struct t_eeprom_header), ( uint8_t *)&Eeprom_buffer.data.model_data, size) ;
if (size > sizeof(g_model.header.name))
memcpy(modelHeaders[dst].name, Eeprom_buffer.data.model_data.header.name, sizeof(g_model.header.name));
else
memset(modelHeaders[dst].name, 0, sizeof(g_model.header.name));
Eeprom32_source_address = (uint8_t *)&Eeprom_buffer.data.model_data; // Get data from here
Eeprom32_data_size = sizeof(g_model) ; // This much
Eeprom32_file_index = dst + 1 ; // This file system entry
Eeprom32_process_state = E32_BLANKCHECK ;
eeWaitFinished();
return true;
while (eepromReadStatus() & 1) {
SIMU_SLEEP(5/*ms*/);
}
}
void eeSwapModels(uint8_t id1, uint8_t id2)
void eepromEraseBlock(uint32_t address, bool blocking=true)
{
// eeCheck(true) should have been called before entering here
// TRACE("eepromEraseBlock(%d)", address);
uint16_t id2_size = File_system[id2+1].size;
uint32_t id2_block_no = File_system[id2+1].block_no;
#if defined(SIMU)
static uint8_t erasedBlock[EEPROM_BLOCK_SIZE] = { 0xff };
eeprom_pointer = address;
eeprom_buffer_data = (char *)erasedBlock;
eeprom_buffer_size = EEPROM_BLOCK_SIZE;
eeprom_read_operation = false;
Spi_complete = false;
sem_post(eeprom_write_sem);
#else
eeprom_write_enable();
uint8_t * p = Spi_tx_buf;
*p = COMMAND_BLOCK_ERASE;
*(p+1) = address >> 16;
*(p+2) = address >> 8;
*(p+3) = address;
spi_PDC_action(p, 0, 0, 4, 0);
#endif
eeCopyModel(id2, id1);
// block_no(id1) has been shifted now, but we have the size
// TODO flash saving with function above ...
if (id2_size > sizeof(g_model.header.name)) {
read32_eeprom_data( (id2_block_no << 12) + sizeof( struct t_eeprom_header), ( uint8_t *)&Eeprom_buffer.data.model_data, id2_size);
memcpy(modelHeaders[id1].name, Eeprom_buffer.data.model_data.header.name, sizeof(g_model.header.name));
if (blocking) {
eepromWaitSpiComplete();
eepromWaitReadStatus();
}
else {
memset(modelHeaders[id1].name, 0, sizeof(g_model.header.name));
}
Eeprom32_source_address = (uint8_t *)&Eeprom_buffer.data.model_data; // Get data from here
Eeprom32_data_size = id2_size ; // This much
Eeprom32_file_index = id1 + 1 ; // This file system entry
Eeprom32_process_state = E32_BLANKCHECK ;
eeWaitFinished();
}
// Read eeprom data starting at random address
void read32_eeprom_data(uint32_t eeAddress, register uint8_t *buffer, uint32_t size)
void eepromRead(uint32_t address, uint8_t * buffer, uint32_t size, bool blocking=true)
{
#ifdef SIMU
// TRACE("eepromRead(%d, %p, %d)", address, buffer, size);
#if defined(SIMU)
assert(size);
eeprom_pointer = eeAddress;
eeprom_pointer = address;
eeprom_buffer_data = (char*)buffer;
eeprom_buffer_size = size;
eeprom_read_operation = true;
Spi_complete = false;
sem_post(eeprom_write_sem);
#else
register uint8_t *p = Spi_tx_buf ;
*p = 3 ; // Read command
*(p+1) = eeAddress >> 16 ;
*(p+2) = eeAddress >> 8 ;
*(p+3) = eeAddress ; // 3 bytes address
uint8_t * p = Spi_tx_buf;
*p = COMMAND_READ;
*(p+1) = address >> 16;
*(p+2) = address >> 8;
*(p+3) = address;
spi_PDC_action(p, 0, buffer, 4, size);
#endif
while (!Spi_complete) {
#ifdef SIMU
sleep(5/*ms*/);
#endif
if (blocking) {
eepromWaitSpiComplete();
}
}
void write32_eeprom_block( uint32_t eeAddress, register uint8_t *buffer, uint32_t size, uint32_t immediate )
void eepromWrite(uint32_t address, uint8_t * buffer, uint32_t size, bool blocking=true)
{
#ifdef SIMU
// TRACE("eepromWrite(%d, %p, %d)", address, buffer, size);
#if defined(SIMU)
assert(size);
eeprom_pointer = eeAddress;
eeprom_pointer = address;
eeprom_buffer_data = (char*)buffer;
eeprom_buffer_size = size+1;
eeprom_read_operation = false;
@ -201,137 +158,159 @@ void write32_eeprom_block( uint32_t eeAddress, register uint8_t *buffer, uint32_
sem_post(eeprom_write_sem);
#else
eeprom_write_enable();
register uint8_t *p = Spi_tx_buf;
*p = 2; // Write command
*(p + 1) = eeAddress >> 16;
*(p + 2) = eeAddress >> 8;
*(p + 3) = eeAddress; // 3 bytes address
uint8_t * p = Spi_tx_buf;
*p = COMMAND_WRITE;
*(p+1) = address >> 16;
*(p+2) = address >> 8;
*(p+3) = address;
spi_PDC_action(p, buffer, 0, 4, size);
#endif
if (immediate)
return;
while (!Spi_complete) {
#ifdef SIMU
sleep(5/*ms*/);
#endif
if (blocking) {
eepromWaitSpiComplete();
eepromWaitReadStatus();
}
}
uint8_t byte_checksum( uint8_t *p, uint32_t size )
bool eepromOpen()
{
uint32_t csum ;
csum = 0 ;
while( size )
{
csum += *p++ ;
size -= 1 ;
eepromFatAddr = 0;
while (eepromFatAddr < EEPROM_FILE_SIZE) {
eepromRead(eepromFatAddr, (uint8_t *)&eepromHeader, sizeof(eepromHeader.mark));
if (eepromHeader.mark == EEPROM_MARK) {
eepromRead(eepromFatAddr, (uint8_t *)&eepromHeader, sizeof(eepromHeader));
return true;
}
return csum ;
eepromFatAddr += EEPROM_FAT_SIZE;
}
return false;
}
uint32_t ee32_check_header( struct t_eeprom_header *hptr )
bool eepromCheck()
{
uint8_t csum ;
csum = byte_checksum( ( uint8_t *) hptr, 7 ) ;
if ( csum == hptr->hcsum )
{
return 1 ;
}
return 0 ;
return true;
}
// Pass in an even block number, this and the next block will be checked
// to see which is the most recent, the block_no of the most recent
// is returned, with the corresponding data size if required
// and the sequence number if required
uint32_t get_current_block_number( uint32_t block_no, uint16_t *p_size, uint32_t *p_seq )
uint32_t readFile(int index, uint8_t * data, uint32_t size)
{
struct t_eeprom_header b0 ;
struct t_eeprom_header b1 ;
uint32_t sequence_no ;
uint16_t size ;
read32_eeprom_data( block_no << 12, ( uint8_t *)&b0, sizeof(b0) ) ; // Sequence # 0
read32_eeprom_data( (block_no+1) << 12, ( uint8_t *)&b1, sizeof(b1) ) ; // Sequence # 1
if ( ee32_check_header( &b0 ) == 0 )
{
b0.sequence_no = 0 ;
b0.data_size = 0 ;
b0.flags = 0 ;
uint16_t fileSize;
uint32_t address = eepromHeader.files[index].index * EEPROM_FILE_SIZE;
eepromRead(address, (uint8_t *)&fileSize, sizeof(fileSize));
if (size < fileSize) {
fileSize = size;
}
if (fileSize > 0) {
eepromRead(address + sizeof(fileSize), data, fileSize);
size -= fileSize;
}
if (size > 0) {
memset(data + fileSize, 0, size);
}
return fileSize;
}
size = b0.data_size ;
sequence_no = b0.sequence_no ;
if ( ee32_check_header( &b0 ) == 0 )
void eepromIncFatAddr()
{
if ( ee32_check_header( &b1 ) != 0 )
{
size = b1.data_size ;
sequence_no = b1.sequence_no ;
block_no += 1 ;
}
else
{
size = 0 ;
sequence_no = 1 ;
}
}
else
{
if ( ee32_check_header( &b1 ) != 0 )
{
if ( b1.sequence_no > b0.sequence_no )
{
size = b1.data_size ;
sequence_no = b1.sequence_no ;
block_no += 1 ;
}
eepromPreviousFatAddr = eepromFatAddr;
eepromFatAddr += EEPROM_FAT_SIZE;
if (eepromFatAddr >= EEPROM_FILE_SIZE) {
eepromFatAddr = 0;
}
}
if ( size == 0xFFFF )
void writeFile(int index, uint8_t * data, uint32_t size)
{
size = 0 ;
uint8_t blockIndex = eepromHeader.files[eepromWriteFileIndex].index;
eepromHeader.files[eepromWriteFileIndex].exists = 0;
eepromHeader.files[eepromWriteFileIndex].index = eepromHeader.files[index].index;
eepromHeader.files[index].exists = (size > 0);
eepromHeader.files[index].index = blockIndex;
eepromWriteSourceAddr = data;
eepromWriteSize = size;
eepromWriteDestinationAddr = blockIndex * EEPROM_FILE_SIZE;
eepromWriteState = EEPROM_START_WRITE;
eepromWriteFileIndex += 1;
if (eepromWriteFileIndex >= EEPROM_MAX_FILES) {
eepromWriteFileIndex = FIRST_FILE_AVAILABLE;
}
if ( p_size )
{
*p_size = size ;
eepromIncFatAddr();
}
void eeDeleteModel(uint8_t index)
{
eeCheck(true);
memclear(&modelHeaders[index], sizeof(ModelHeader));
writeFile(index+1, (uint8_t *)&g_model, 0);
eepromWriteWait();
}
bool eeCopyModel(uint8_t dst, uint8_t src)
{
eeCheck(true);
uint32_t eepromWriteSourceAddr = eepromHeader.files[src+1].index * EEPROM_FILE_SIZE;
uint32_t eepromWriteDestinationAddr = eepromHeader.files[dst+1].index * EEPROM_FILE_SIZE;
// erase blocks
eepromEraseBlock(eepromWriteDestinationAddr);
eepromEraseBlock(eepromWriteDestinationAddr+EEPROM_BLOCK_SIZE);
// write model
for (int pos=0; pos<EEPROM_FILE_SIZE; pos+=EEPROM_BUFFER_SIZE) {
eepromRead(eepromWriteSourceAddr+pos, eepromWriteBuffer, EEPROM_BUFFER_SIZE);
eepromWrite(eepromWriteDestinationAddr+pos, eepromWriteBuffer, EEPROM_BUFFER_SIZE);
}
// write FAT
eepromHeader.files[dst+1].exists = 1;
eepromIncFatAddr();
eepromWriteState = EEPROM_WRITE_NEW_FAT;
eepromWriteWait();
modelHeaders[dst] = modelHeaders[src];
return true;
}
void eeSwapModels(uint8_t id1, uint8_t id2)
{
eeCheck(true);
{
EepromHeaderFile tmp = eepromHeader.files[id1+1];
eepromHeader.files[id1+1] = eepromHeader.files[id2+1];
eepromHeader.files[id2+1] = tmp;
}
eepromIncFatAddr();
eepromWriteState = EEPROM_WRITE_NEW_FAT;
eepromWriteWait();
{
ModelHeader tmp = modelHeaders[id1];
modelHeaders[id1] = modelHeaders[id2];
modelHeaders[id2] = tmp;
}
if ( sequence_no == 0xFFFFFFFF )
{
sequence_no = 0 ;
}
if ( p_seq )
{
*p_seq = sequence_no ;
}
// Block_needs_erasing = erase ;
return block_no ;
}
// For conversions ...
void loadGeneralSettings()
uint32_t loadGeneralSettings()
{
memset(&g_eeGeneral, 0, sizeof(g_eeGeneral));
uint16_t size = min<int>(File_system[0].size, sizeof(g_eeGeneral));
if (size) {
read32_eeprom_data((File_system[0].block_no << 12) + sizeof(struct t_eeprom_header), (uint8_t *)&g_eeGeneral, size);
}
return readFile(0, (uint8_t *)&g_eeGeneral, sizeof(g_eeGeneral));
}
void loadModel(int index)
uint32_t loadModel(uint32_t index)
{
memset(&g_model, 0, sizeof(g_model));
int size = min<int>(File_system[index+1].size, sizeof(g_model));
if (size > 256) { // if loaded a fair amount
read32_eeprom_data((File_system[index+1].block_no << 12) + sizeof(struct t_eeprom_header), (uint8_t *)&g_model, size) ;
return readFile(index+1, (uint8_t *)&g_model, sizeof(g_model));
}
void writeGeneralSettings()
{
writeFile(0, (uint8_t *)&g_eeGeneral, sizeof(g_eeGeneral));
}
void writeModel(int index)
{
writeFile(index+1, (uint8_t *)&g_model, sizeof(g_model));
}
bool eeLoadGeneral()
@ -360,28 +339,19 @@ void eeLoadModel(uint8_t id)
pauseMixerCalculations();
uint16_t size = File_system[id+1].size ;
memset(&g_model, 0, sizeof(g_model));
uint32_t size = loadModel(id);
#if defined(SIMU)
if (sizeof(struct t_eeprom_header) + sizeof(g_model) > 4096)
TRACE("Model data size can't exceed %d bytes (%d bytes)", int(4096-sizeof(struct t_eeprom_header)), (int)sizeof(g_model));
else if (size > 0 && size != sizeof(g_model))
if (sizeof(uint16_t) + sizeof(g_model) > EEPROM_FILE_SIZE)
TRACE("Model data size can't exceed %d bytes (%d bytes)", int(EEPROM_FILE_SIZE-sizeof(uint16_t)), (int)sizeof(g_model));
if (size > 0 && size != sizeof(g_model))
TRACE("Model data read=%d bytes vs %d bytes\n", size, (int)sizeof(ModelData));
#endif
if (size > sizeof(g_model)) {
size = sizeof(g_model) ;
}
if(size < 256) { // if not loaded a fair amount
if (size < EEPROM_BUFFER_SIZE) { // if not loaded a fair amount
modelDefault(id) ;
eeCheck(true);
}
else {
read32_eeprom_data((File_system[id+1].block_no << 12) + sizeof(struct t_eeprom_header), (uint8_t *)&g_model, size) ;
}
AUDIO_FLUSH();
flightReset();
@ -403,7 +373,7 @@ void eeLoadModel(uint8_t id)
frskySendAlarms();
#endif
#if defined(CPUARM) && defined(SDCARD)
#if defined(SDCARD)
referenceModelAudioFiles();
#endif
@ -415,82 +385,47 @@ void eeLoadModel(uint8_t id)
bool eeModelExists(uint8_t id)
{
return ( File_system[id+1].size > 0 ) ;
return (eepromHeader.files[id+1].exists);
}
void eeLoadModelName(uint8_t id, char *name)
{
memclear(name, sizeof(g_model.header.name));
if (id < MAX_MODELS) {
id += 1;
if (File_system[id].size > sizeof(g_model.header.name) ) {
read32_eeprom_data((File_system[id].block_no << 12)+8, (uint8_t *)name, sizeof(g_model.header.name));
}
}
}
#if defined(CPUARM)
void eeLoadModelHeader(uint8_t id, ModelHeader * header)
{
memclear(header, sizeof(ModelHeader));
if (id < MAX_MODELS) {
id += 1;
if (File_system[id].size > sizeof(ModelHeader)) {
read32_eeprom_data((File_system[id].block_no << 12)+8, (uint8_t *)header, sizeof(ModelHeader));
}
}
}
#endif
void fill_file_index()
{
for (uint32_t i = 0 ; i < MAX_MODELS + 1 ; i += 1 )
{
File_system[i].block_no = get_current_block_number( i * 2, &File_system[i].size, &File_system[i].sequence_no ) ;
}
readFile(id+1, (uint8_t *)header, sizeof(ModelHeader));
}
void eeReadAll()
void eepromFormat()
{
fill_file_index() ;
eepromFatAddr = 0;
eepromHeader.mark = EEPROM_MARK;
for (int i=0; i<EEPROM_MAX_FILES; i++) {
eepromHeader.files[i].exists = 0;
eepromHeader.files[i].index = i+1;
}
eepromEraseBlock(0);
eepromWrite(0, (uint8_t *)&eepromHeader, sizeof(eepromHeader));
}
if (!eeLoadGeneral() )
void eeErase(bool warn)
{
generalDefault();
modelDefault(0);
if (warn) {
ALERT(STR_EEPROMWARN, STR_BADEEPROMDATA, AU_BAD_EEPROM);
}
MESSAGE(STR_EEPROMWARN, STR_EEPROMFORMATTING, NULL, AU_EEPROM_FORMATTING);
/* we remove all models */
for (uint32_t i=0; i<MAX_MODELS; i++)
eeDeleteModel(i);
eepromFormat();
eeDirty(EE_GENERAL);
eeDirty(EE_MODEL);
}
else {
eeLoadModelHeaders() ;
eeCheck(true);
}
// TODO common!
stickMode = g_eeGeneral.stickMode;
#if defined(CPUARM)
for (uint8_t i=0; languagePacks[i]!=NULL; i++) {
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
currentLanguagePackIdx = i;
currentLanguagePack = languagePacks[i];
}
}
#endif
}
void eeWaitFinished()
void eepromWriteWait(EepromWriteState state/* = EEPROM_IDLE*/)
{
while (Eeprom32_process_state != E32_IDLE) {
ee32_process();
while (eepromWriteState != state) {
eepromWriteProcess();
#ifdef SIMU
sleep(5/*ms*/);
#endif
@ -500,154 +435,119 @@ void eeWaitFinished()
void eeCheck(bool immediately)
{
if (immediately) {
eeWaitFinished();
eepromWriteWait();
}
if (s_eeDirtyMsk & EE_GENERAL) {
s_eeDirtyMsk -= EE_GENERAL;
Eeprom32_source_address = (uint8_t *)&g_eeGeneral ; // Get data from here
Eeprom32_data_size = sizeof(g_eeGeneral) ; // This much
Eeprom32_file_index = 0 ; // This file system entry
Eeprom32_process_state = E32_BLANKCHECK ;
writeGeneralSettings();
if (immediately)
eeWaitFinished();
eepromWriteWait();
else
return;
}
if (s_eeDirtyMsk & EE_MODEL) {
s_eeDirtyMsk -= EE_MODEL;
Eeprom32_source_address = (uint8_t *)&g_model ; // Get data from here
Eeprom32_data_size = sizeof(g_model) ; // This much
Eeprom32_file_index = g_eeGeneral.currModel + 1 ; // This file system entry
Eeprom32_process_state = E32_BLANKCHECK ;
writeModel(g_eeGeneral.currModel);
if (immediately)
eeWaitFinished();
eepromWriteWait();
}
}
void ee32_process()
void eepromWriteProcess()
{
register uint8_t *p ;
register uint8_t *q ;
register uint32_t x ;
register uint32_t eeAddress ;
if ( Eeprom32_process_state == E32_BLANKCHECK ) {
eeAddress = File_system[Eeprom32_file_index].block_no ^ 1 ;
eeAddress <<= 12 ; // Block start address
Eeprom32_address = eeAddress ; // Where to put new data
Eeprom32_process_state = E32_READSENDING ;
if (eepromWriteState > EEPROM_START_WRITE && Spi_complete) {
eepromWriteState = EepromWriteState(eepromWriteState + 1);
Spi_complete = false;
}
if (Eeprom32_process_state == E32_READSENDING) {
#ifdef SIMU
Eeprom32_process_state = E32_WRITESTART ;
#else
eeAddress = Eeprom32_address ;
eeprom_write_enable() ;
p = Spi_tx_buf ;
*p = 0x20 ; // Block Erase command
*(p+1) = eeAddress >> 16 ;
*(p+2) = eeAddress >> 8 ;
*(p+3) = eeAddress ; // 3 bytes address
spi_PDC_action( p, 0, 0, 4, 0 ) ;
Eeprom32_process_state = E32_ERASESENDING ;
Eeprom32_state_after_erase = E32_WRITESTART ;
#endif
// TRACE("eepromWriteProcess(state=%d)", eepromWriteState);
switch (eepromWriteState) {
case EEPROM_ERASING_FILE_BLOCK1_WAIT:
case EEPROM_ERASING_FILE_BLOCK2_WAIT:
case EEPROM_WRITING_BUFFER_WAIT:
case EEPROM_ERASING_FAT_BLOCK_WAIT:
case EEPROM_WRITING_NEW_FAT_WAIT:
case EEPROM_OVERWRITING_OLD_FAT_WAIT:
if ((eepromReadStatus() & 1) == 0)
eepromWriteState = EepromWriteState(eepromWriteState + 1);
break;
case EEPROM_START_WRITE:
eepromWriteState = EEPROM_ERASING_FILE_BLOCK1;
eepromEraseBlock(eepromWriteDestinationAddr, false);
break;
case EEPROM_ERASE_FILE_BLOCK2:
eepromWriteState = EEPROM_ERASING_FILE_BLOCK2;
eepromEraseBlock(eepromWriteDestinationAddr + EEPROM_BLOCK_SIZE, false);
break;
case EEPROM_WRITE_BUFFER:
{
int size = min<int>(EEPROM_BUFFER_SIZE-2, eepromWriteSize);
*((uint16_t *)eepromWriteBuffer) = eepromWriteSize;
memcpy(eepromWriteBuffer+2, eepromWriteSourceAddr, size);
eepromWriteState = EEPROM_WRITING_BUFFER;
eepromWrite(eepromWriteDestinationAddr, eepromWriteBuffer, 2+size, false);
eepromWriteSourceAddr += size;
eepromWriteDestinationAddr += 2+size;
eepromWriteSize -= size;
break;
}
if (Eeprom32_process_state == E32_WRITESTART) {
uint32_t total_size ;
p = Eeprom32_source_address;
q = (uint8_t *) &Eeprom_buffer.data;
if (p != q) {
for (x = 0; x < Eeprom32_data_size; x += 1) {
*q++ = *p++; // Copy the data to temp buffer
}
}
Eeprom_buffer.header.sequence_no = ++File_system[Eeprom32_file_index].sequence_no;
File_system[Eeprom32_file_index].size = Eeprom_buffer.header.data_size = Eeprom32_data_size;
Eeprom_buffer.header.flags = 0;
Eeprom_buffer.header.hcsum = byte_checksum((uint8_t *) &Eeprom_buffer, 7);
total_size = Eeprom32_data_size + sizeof(struct t_eeprom_header);
eeAddress = Eeprom32_address; // Block start address
x = total_size / 256; // # sub blocks
x <<= 8; // to offset address
eeAddress += x; // Add it in
p = (uint8_t *) &Eeprom_buffer;
p += x; // Add offset
x = total_size % 256; // Size of last bit
if (x == 0) // Last bit empty
case EEPROM_WRITE_NEXT_BUFFER:
{
x = 256;
p -= x;
eeAddress -= x;
int size = min<int>(EEPROM_BUFFER_SIZE, eepromWriteSize);
if (size > 0) {
memcpy(eepromWriteBuffer, eepromWriteSourceAddr, size);
eepromWriteState = EEPROM_WRITING_BUFFER;
eepromWrite(eepromWriteDestinationAddr, eepromWriteBuffer, size, false);
eepromWriteSourceAddr += size;
eepromWriteDestinationAddr += size;
eepromWriteSize -= size;
break;
}
Eeprom32_buffer_address = p;
Eeprom32_address = eeAddress;
write32_eeprom_block(eeAddress, p, x, EE_NOWAIT);
Eeprom32_process_state = E32_WRITESENDING ;
else if (eepromFatAddr == 0 || eepromFatAddr == EEPROM_BLOCK_SIZE) {
eepromWriteState = EEPROM_ERASING_FAT_BLOCK;
eepromEraseBlock(eepromFatAddr, false);
break;
}
}
/* no break */
if ( Eeprom32_process_state == E32_WRITESENDING )
{
if ( Spi_complete )
{
Eeprom32_process_state = E32_WRITEWAITING ;
case EEPROM_WRITE_NEW_FAT:
eepromWriteState = EEPROM_WRITING_NEW_FAT;
eepromWrite(eepromFatAddr, (uint8_t *)&eepromHeader, sizeof(eepromHeader), false);
break;
case EEPROM_OVERWRITE_OLD_FAT:
memset(eepromWriteBuffer, 0, EEPROM_FAT_SIZE);
eepromWriteState = EEPROM_OVERWRITING_OLD_FAT;
eepromWrite(eepromPreviousFatAddr, eepromWriteBuffer, EEPROM_FAT_SIZE, false);
break;
case EEPROM_END_WRITE:
eepromWriteState = EEPROM_IDLE;
break;
default:
break;
}
}
if ( Eeprom32_process_state == E32_WRITEWAITING )
uint16_t eeModelSize(uint8_t i_fileSrc)
{
x = eeprom_read_status() ;
if ( ( x & 1 ) == 0 )
{
if ( ( Eeprom32_address & 0x0FFF ) != 0 ) // More to write
{
Eeprom32_address -= 256 ;
Eeprom32_buffer_address -= 256 ;
write32_eeprom_block( Eeprom32_address, Eeprom32_buffer_address, 256, EE_NOWAIT ) ;
Eeprom32_process_state = E32_WRITESENDING ;
}
else
{
File_system[Eeprom32_file_index].block_no ^= 1 ; // This is now the current block
#if 0
// now erase the other block
File_system[Eeprom32_file_index].block_no ^= 1 ; // This is now the current block
eeAddress = Eeprom32_address ^ 0x00001000 ; // Address of block to erase
eeprom_write_enable() ;
p = Spi_tx_buf ;
*p = 0x20 ; // Block Erase command
*(p+1) = eeAddress >> 16 ;
*(p+2) = eeAddress >> 8 ;
*(p+3) = eeAddress ; // 3 bytes address
spi_PDC_action( p, 0, 0, 4, 0 ) ;
Eeprom32_process_state = E32_ERASESENDING ;
Eeprom32_state_after_erase = E32_IDLE ;
#endif
Eeprom32_process_state = E32_IDLE ;
}
}
uint16_t result = 0;
if (eepromHeader.files[i_fileSrc+1].exists) {
uint32_t address = eepromHeader.files[i_fileSrc+1].index * EEPROM_FILE_SIZE;
eepromRead(address, (uint8_t *)&result, sizeof(uint16_t));
}
if ( Eeprom32_process_state == E32_ERASESENDING )
{
if ( Spi_complete )
{
Eeprom32_process_state = E32_ERASEWAITING ;
}
}
if ( Eeprom32_process_state == E32_ERASEWAITING )
{
x = eeprom_read_status() ;
if ( ( x & 1 ) == 0 )
{ // Command finished
Eeprom32_process_state = Eeprom32_state_after_erase ;
}
}
return result;
}
#if defined(SDCARD)
@ -658,6 +558,8 @@ const pm_char * eeBackupModel(uint8_t i_fileSrc)
DIR archiveFolder;
UINT written;
eeCheck(true);
if (!sdMounted()) {
return STR_NO_SDCARD;
}
@ -686,7 +588,7 @@ const pm_char * eeBackupModel(uint8_t i_fileSrc)
strcpy(statusLineMsg, PSTR("File "));
strcpy(statusLineMsg+5, &buf[sizeof(MODELS_PATH)]);
uint16_t size = File_system[i_fileSrc+1].size;
uint16_t size = eeModelSize(i_fileSrc);
*(uint32_t*)&buf[0] = O9X_FOURCC;
buf[4] = g_eeGeneral.version;
@ -699,15 +601,21 @@ const pm_char * eeBackupModel(uint8_t i_fileSrc)
return SDCARD_ERROR(result);
}
read32_eeprom_data( (File_system[i_fileSrc+1].block_no << 12) + sizeof( struct t_eeprom_header), ( uint8_t *)&Eeprom_buffer.data.model_data, size) ;
result = f_write(&archiveFile, (uint8_t *)&Eeprom_buffer.data.model_data, size, &written);
uint32_t address = eepromHeader.files[i_fileSrc+1].index * EEPROM_FILE_SIZE + 2;
while (size > 0) {
uint16_t blockSize = min<uint16_t>(size, EEPROM_BUFFER_SIZE);
eepromRead(address, eepromWriteBuffer, blockSize);
result = f_write(&archiveFile, eepromWriteBuffer, blockSize, &written);
if (result != FR_OK || written != blockSize) {
f_close(&archiveFile);
if (result != FR_OK || written != size) {
return SDCARD_ERROR(result);
}
size -= blockSize;
address += blockSize;
}
f_close(&archiveFile);
showStatusLine();
return NULL;
}
@ -717,6 +625,8 @@ const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name)
FIL restoreFile;
UINT read;
eeCheck(true);
if (!sdMounted()) {
return STR_NO_SDCARD;
}
@ -748,35 +658,44 @@ const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name)
return STR_INCOMPATIBLE;
}
uint16_t size = max((uint16_t)sizeof(g_model), *(uint16_t*)&buf[6]);
if (eeModelExists(i_fileDst)) {
eeDeleteModel(i_fileDst);
}
memset((uint8_t *)&Eeprom_buffer.data.model_data, 0, sizeof(g_model));
result = f_read(&restoreFile, ( uint8_t *)&Eeprom_buffer.data.model_data, size, &read);
f_close(&restoreFile);
uint16_t size = min<uint16_t>(sizeof(g_model), *(uint16_t*)&buf[6]);
uint32_t address = eepromHeader.files[i_fileDst+1].index * EEPROM_FILE_SIZE;
if (result != FR_OK || read != read) {
return STR_INCOMPATIBLE;
// erase blocks
eepromEraseBlock(address);
eepromEraseBlock(address+EEPROM_BLOCK_SIZE);
// write size
eepromWrite(address, (uint8_t *)&size, sizeof(size));
address += sizeof(size);
// write model
while (size > 0) {
uint16_t blockSize = min<uint16_t>(size, EEPROM_BUFFER_SIZE);
result = f_read(&restoreFile, eepromWriteBuffer, blockSize, &read);
if (result != FR_OK || read != blockSize) {
f_close(&g_oLogFile);
return SDCARD_ERROR(result);
}
eepromWrite(address, eepromWriteBuffer, blockSize);
size -= blockSize;
address += blockSize;
}
// TODO flash saving ...
if (read > sizeof(g_model.header.name))
memcpy(modelHeaders[i_fileDst].name, Eeprom_buffer.data.model_data.header.name, sizeof(g_model.header.name));
else
memset(modelHeaders[i_fileDst].name, 0, sizeof(g_model.header.name));
// write FAT
eepromHeader.files[i_fileDst+1].exists = 1;
eepromIncFatAddr();
eepromWriteState = EEPROM_WRITE_NEW_FAT;
eepromWriteWait();
Eeprom32_source_address = (uint8_t *)&Eeprom_buffer.data.model_data; // Get data from here
Eeprom32_data_size = sizeof(g_model); // This much
Eeprom32_file_index = i_fileDst + 1; // This file system entry
Eeprom32_process_state = E32_BLANKCHECK;
eeWaitFinished();
eeLoadModelHeader(i_fileDst, &modelHeaders[i_fileDst]);
#if defined(CPUARM)
if (version < EEPROM_VER) {
eeCheck(true);
ConvertModel(i_fileDst, version);
loadModel(g_eeGeneral.currModel);
}

View file

@ -40,69 +40,48 @@
#include <inttypes.h>
#include <stdint.h>
// States in Eeprom32_process_state
#define E32_IDLE 1
#define E32_ERASESENDING 2
#define E32_ERASEWAITING 3
#define E32_WRITESENDING 4
#define E32_WRITEWAITING 5
#define E32_READSENDING 6
#define E32_READWAITING 7
#define E32_BLANKCHECK 8
#define E32_WRITESTART 9
extern uint8_t Eeprom32_process_state ;
extern uint8_t *Eeprom32_source_address ;
extern uint8_t Eeprom32_file_index ;
extern uint32_t Eeprom32_data_size ;
extern void end_spi(); // TODO not public
extern void ee32_process( void ) ;
extern bool eeLoadGeneral( void ) ;
extern void eeWaitFinished();
extern void eeDeleteModel( uint8_t id ) ;
extern bool eeModelExists(uint8_t id) ;
extern bool eeCopyModel(uint8_t dst, uint8_t src);
extern void eeSwapModels(uint8_t id1, uint8_t id2);
bool eeLoadGeneral( void ) ;
void eeDeleteModel( uint8_t id ) ;
bool eeCopyModel(uint8_t dst, uint8_t src);
void eeSwapModels(uint8_t id1, uint8_t id2);
#define DISPLAY_PROGRESS_BAR(x)
struct t_file_entry
{
uint32_t block_no ;
uint32_t sequence_no ;
uint16_t size ;
uint8_t flags ;
} ;
struct t_eeprom_header
{
uint32_t sequence_no ; // sequence # to decide which block is most recent
uint16_t data_size ; // # bytes in data area
uint8_t flags ;
uint8_t hcsum ;
};
extern struct t_file_entry File_system[] ;
extern EEGeneral g_eeGeneral;
extern ModelData g_model;
extern uint8_t Spi_tx_buf[] ;
extern uint8_t Spi_rx_buf[] ;
void eeprom_write_enable();
uint32_t eeprom_read_status();
void read32_eeprom_data(uint32_t eeAddress, register uint8_t *buffer, uint32_t size);
uint32_t spi_PDC_action( register uint8_t *command, register uint8_t *tx, register uint8_t *rx, register uint32_t comlen, register uint32_t count );
#if defined(SDCARD)
const pm_char * eeBackupModel(uint8_t i_fileSrc);
const pm_char * eeRestoreModel(uint8_t i_fileDst, char *model_name);
#endif
void loadGeneralSettings();
void loadModel(int index);
uint32_t loadGeneralSettings();
uint32_t loadModel(uint32_t index);
enum EepromWriteState {
EEPROM_IDLE = 0,
EEPROM_START_WRITE,
EEPROM_ERASING_FILE_BLOCK1,
EEPROM_ERASING_FILE_BLOCK1_WAIT,
EEPROM_ERASE_FILE_BLOCK2,
EEPROM_ERASING_FILE_BLOCK2,
EEPROM_ERASING_FILE_BLOCK2_WAIT,
EEPROM_WRITE_BUFFER,
EEPROM_WRITING_BUFFER,
EEPROM_WRITING_BUFFER_WAIT,
EEPROM_WRITE_NEXT_BUFFER,
EEPROM_ERASING_FAT_BLOCK,
EEPROM_ERASING_FAT_BLOCK_WAIT,
EEPROM_WRITE_NEW_FAT,
EEPROM_WRITING_NEW_FAT,
EEPROM_WRITING_NEW_FAT_WAIT,
EEPROM_OVERWRITE_OLD_FAT,
EEPROM_OVERWRITING_OLD_FAT,
EEPROM_OVERWRITING_OLD_FAT_WAIT,
EEPROM_END_WRITE
};
extern EepromWriteState eepromWriteState;
void eepromWriteProcess();
void eepromWriteWait(EepromWriteState state = EEPROM_IDLE);
bool eepromOpen();
bool eepromCheck();
#endif

View file

@ -203,7 +203,7 @@ static void EeFsFree(blkid_t blk)
EeFsFlushFreelist();
}
int8_t EeFsck()
int8_t eepromCheck()
{
ENABLE_SYNC_WRITE(true);
@ -266,7 +266,7 @@ int8_t EeFsck()
return 0;
}
void EeFsFormat()
void eepromFormat()
{
ENABLE_SYNC_WRITE(true);
@ -288,7 +288,7 @@ void EeFsFormat()
ENABLE_SYNC_WRITE(false);
}
inline bool EeFsOpen()
bool eepromOpen()
{
eeprom_read_block((uint8_t *)&eeFs, 0, sizeof(eeFs));
@ -550,7 +550,6 @@ bool RlcFile::copy(uint8_t i_fileDst, uint8_t i_fileSrc)
}
#if defined(SDCARD)
extern FIL g_oLogFile;
const pm_char * eeBackupModel(uint8_t i_fileSrc)
{
char *buf = reusableBuffer.modelsel.mainname;
@ -1025,41 +1024,12 @@ void eeErase(bool warn)
}
MESSAGE(STR_EEPROMWARN, STR_EEPROMFORMATTING, NULL, AU_EEPROM_FORMATTING);
EeFsFormat();
eepromFormat();
theFile.writeRlc(FILE_GENERAL, FILE_TYP_GENERAL, (uint8_t*)&g_eeGeneral, sizeof(EEGeneral), true);
modelDefault(0);
theFile.writeRlc(FILE_MODEL(0), FILE_TYP_MODEL, (uint8_t*)&g_model, sizeof(g_model), true);
}
// TODO merge this code with eeprom_arm.cpp one
void eeReadAll()
{
if (!EeFsOpen() ||
EeFsck() < 0 ||
!eeLoadGeneral())
{
eeErase(true);
}
else {
eeLoadModelHeaders();
}
stickMode = g_eeGeneral.stickMode;
#if defined(CPUARM)
for (uint8_t i=0; languagePacks[i]!=NULL; i++) {
if (!strncmp(g_eeGeneral.ttsLanguage, languagePacks[i]->id, 2)) {
currentLanguagePackIdx = i;
currentLanguagePack = languagePacks[i];
}
}
#endif
#if !defined(CPUARM)
eeLoadModel(g_eeGeneral.currModel);
#endif
}
void eeCheck(bool immediately)
{
if (immediately) {

View file

@ -116,8 +116,8 @@ extern EeFs eeFs;
#define BLOCKS_OFFSET (RESV-BS)
#endif
int8_t EeFsck();
void EeFsFormat();
int8_t eepromCheck();
void eepromFormat();
uint16_t EeFsGetFree();
#if !defined(CPUARM)
@ -247,6 +247,10 @@ void loadGeneralSettings();
void loadModel(int index);
#endif
bool eepromOpen();
void eeLoadModelName(uint8_t id, char *name);
bool eeLoadGeneral();
// For EEPROM backup/restore
#if defined(CPUARM)
inline bool isEepromStart(const void * buffer)

View file

@ -244,10 +244,10 @@ void menuModelFlightModesAll(uint8_t event)
uint8_t att;
for (uint8_t i=0; i<MAX_FLIGHT_MODES; i++) {
#if defined(CPUARM)
coord_t y = MENU_HEADER_HEIGHT + 1 + (i-s_pgOfs)*FH;
if (y<MENU_HEADER_HEIGHT+1 || y>(LCD_LINES-1)*FH+MENU_HEADER_HEIGHT-FH) continue;
int8_t y = 1 + (1+i-s_pgOfs)*FH;
if (y<1*FH+1 || y>(LCD_LINES-1)*FH+1) continue;
#else
coord_t y = MENU_HEADER_HEIGHT + 1 + i*FH;
uint8_t y = 1 + (i+1)*FH;
#endif
att = (i==sub ? INVERS : 0);
FlightModeData *p = flightModeAddress(i);
@ -269,9 +269,9 @@ void menuModelFlightModesAll(uint8_t event)
#endif
}
if (p->fadeIn || p->fadeOut)
if (p->fadeIn || p->fadeOut) {
lcd_putc(LCD_W-FW-MENUS_SCROLLBAR_WIDTH, y, (p->fadeIn && p->fadeOut) ? '*' : (p->fadeIn ? 'I' : 'O'));
}
}
#if defined(CPUARM)

View file

@ -170,7 +170,7 @@ void displayTimers()
// Main timer
if (g_model.timers[0].mode) {
TimerState & timerState = timersStates[0];
uint8_t att = DBLSIZE | (timerState.val<0 ? BLINK|INVERS : 0);
LcdFlags att = DBLSIZE | (timerState.val<0 ? BLINK|INVERS : 0);
putsTimer(12*FW+2+10*FWNUM-4, FH*2, timerState.val, att, att);
uint8_t xLabel = (timerState.val >= 0 ? MAINTMR_LBL_COL : MAINTMR_LBL_COL-7);
#if defined(CPUARM)

View file

@ -83,8 +83,8 @@ void checkEeprom()
if (!usbPlugged()) {
// TODO merge these 2 branches
#if defined(PCBSKY9X)
if (Eeprom32_process_state != E32_IDLE)
ee32_process();
if (eepromWriteState != EEPROM_IDLE)
eepromWriteProcess();
else if (TIME_TO_WRITE())
eeCheck(false);
#else

View file

@ -131,18 +131,18 @@
#define NUM_XPOTS 3
#endif
#define TELEM_VALUES_MAX 32
#elif defined(CPUARM)
#elif defined(PCBSKY9X)
#define MAX_MODELS 60
#define NUM_CHNOUT 32 // number of real output channels CH1-CH32
#define MAX_FLIGHT_MODES 9
#define MAX_MIXERS 60
#define MAX_EXPOS 32
#define MAX_MIXERS 64
#define MAX_EXPOS 64
#define NUM_LOGICAL_SWITCH 32 // number of custom switches
#define NUM_CFN 60 // number of functions assigned to switches
#define NUM_CFN 64 // number of functions assigned to switches
#define NUM_TRAINER 16
#define NUM_POTS 3
#define NUM_XPOTS 0
#define TELEM_VALUES_MAX 16
#define TELEM_VALUES_MAX 32
#elif defined(CPUM2560) || defined(CPUM2561)
#define MAX_MODELS 30
#define NUM_CHNOUT 16 // number of real output channels CH1-CH16

View file

@ -68,6 +68,7 @@
#define SPORT_FIRMWARE_EXT ".frk"
extern FATFS g_FATFS_Obj;
extern FIL g_oLogFile;
extern uint8_t logDelay;
const pm_char *openLogs();

View file

@ -275,6 +275,7 @@ uint32_t pwrCheck();
// EEPROM driver
void eepromInit();
uint32_t eepromReadStatus();
// Rotary Encoder driver
void rotencInit();

View file

@ -36,7 +36,9 @@
#include "../../opentx.h"
extern volatile uint32_t Spi_complete; // TODO in the driver ?
volatile uint32_t Spi_complete;
uint8_t Spi_tx_buf[24] ;
uint8_t Spi_rx_buf[24] ;
uint32_t spi_PDC_action( register uint8_t *command, register uint8_t *tx, register uint8_t *rx, register uint32_t comlen, register uint32_t count )
{
@ -186,9 +188,13 @@ void eeprom_write_enable()
eeprom_write_one(6, 0);
}
uint32_t eeprom_read_status()
uint32_t eepromReadStatus()
{
#if defined(SIMU)
return 0;
#else
return eeprom_write_one(5, 1);
#endif
}
// SPI i/f to EEPROM (4Mb)

View file

@ -44,7 +44,7 @@ TEST(EEPROM, 100_random_writes)
uint8_t buf[1000];
uint8_t buf2[1000];
EeFsFormat();
eepromFormat();
for(int i=0; i<100; i++) {
int size = rand()%800;
@ -66,7 +66,7 @@ TEST(EEPROM, test2)
RlcFile f;
uint8_t buf[1000];
EeFsFormat();
eepromFormat();
for(int i=0; i<1000; i++) buf[i]='6'+i%4;
@ -89,7 +89,7 @@ TEST(EEPROM, eeCheckImmediately)
// RlcFile f;
uint8_t buf[1000];
EeFsFormat();
eepromFormat();
for(int i=0; i<1000; i++) buf[i]='6'+i%4;
@ -114,7 +114,7 @@ TEST(EEPROM, copy)
uint8_t buf[1000];
EeFsFormat();
eepromFormat();
for(int i=0; i<1000; i++) buf[i]='6'+i%4;
@ -139,7 +139,7 @@ TEST(EEPROM, rm)
uint8_t buf[1000];
EeFsFormat();
eepromFormat();
for(int i=0; i<1000; i++) buf[i]='6'+i%4;