Поиск

Оптимальная эмуляция EEPROM во флеш-памяти STM32


Работая над более свежей версией хронометра для разнообразных соревнований (пока что все еще на STM32, с ESP32 я немного поковырялся, испугался и забил до поры до времени), опять столкнулся с необходимостью сохранения настроек. Сначала взял свой старый сниппет, немножко подкорректировал (сниппет разрабатывался для STM32F0x2), но потом мне стало как-то неуютно от того, что из более чем 110кБ свободной флеш-памяти я использую лишь 1-2кБ. После поиска решений на разных форумах пришел к такому результату.

Проще всего оказалось определить переменную, пользуясь gcc’шным параметром __attribute__:

__attribute__((section(".myvars"))) static const flash_storage Flash_Storage = { .all_stored = USERCONF_INITIALIZER
};


А для того, чтобы эта секция находилась точно после всех остальных данных во флеш-памяти, нужно запихнуть после секции .data в линкер-скрипте вот это:

.myvars :
{ . = ALIGN(1024); KEEP(*(.myvars))
} > rom

Кроме этого улучшения я добавил еще бинарный поиск (потому как искать линейно во флеш-памяти среди десятка тысяч записей — процесс очень долгий, а бинарный поиск позволяет за десяток итераций найти последнюю запись):

static int binarySearch(int l, int r){ while(r >= l){ int mid = l + (r - l) / 2; uint16_t sz = Flash_Data[mid].userconf_sz; if(sz == sizeof(user_conf)){ if(Flash_Data[mid+1].userconf_sz == 0xffff){ return mid; }else{ // element is to the right l = mid + 1; } }else{ // element is to the left r = mid - 1; } } return -1; // not found
} static int get_gooddata(){ static uint8_t firstrun = 1; if(firstrun){ firstrun = 0; if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ uint32_t flsz = FLASH_SIZE * 1024; // size in bytes flsz -= (uint32_t)Flash_Data - FLASH_BASE; uint32_t usz = (sizeof(user_conf) + 1) / 2; maxnum = flsz / 2 / usz; } } return binarySearch(0, maxnum-2); // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full
}


eddy_em.livejournal.com

Добавить комментарий