ARV, когда оперативки гигабайт - так и делаю. А на МК тащить библиотеку поддержки UTF-16 - себе дороже. Только локали способны весь флеш занять. Аккуратно, ручками, только то, что надо или вообще самостоятельно. Не так уж часто приходится на МК по NTFS на флешке лазить или через ESP8266 SOAP/REST на UTF-16 парсить.
С UTF-8, как я уже писал выше, проще.
Братцы помогите разобраться с EEPROM и EEMEM-ами.
Железо - Мега 128, дисплей с тачем и остальная периферия. В EEPROM надо хранить разного рода настройки, кольцевой список данных, ну и сам указатель на текущую "ячейку" этих данных. Общение с EEPROM будет из разных си файлов проекта. Поэтому хотелось бы как-то оптимизировать, каталогизировать это дело. Начал с настроек тач панели.
Схимичил файлы "eeprom.h"
странно работает. Тач панель не отрабатывает нажатия. И стирание EEPROM, при прошивке, не дает никакого эффекта. Как будто калибровка корректная. Прежний вариант кода(закомментированный) с "абсолютной" адресацией работает отменно. Тач отрабатывает, как надо и стирание памяти запускает автоматическую калибровку. Не пойму, где ошибка?
ARV, Проблема в том, что настройки потребуются "кусками" в непредсказуемые периоды времени. И обновляться тоже кусочно будут. Да еще и данные как-то надо писать/читать. Сначала массив данных будет расти до определенного предела, а потом старые данные будут затираться свежими по кругу. Получается, всю эту кучу надо будет перезаписывать, при малейшем изменении? Коли так, то буду признателен, если поделитесь примером кода применительным к ситуации. И "eeprom_update_block" обновит только изменившиеся данные или отрефрешит весь объем, занятый структурой?
eeprom_update_* сначало побайтово читают eeprom и если новые данные такие же - то не пишет, пропуская этот байт.
А у вас размер данных всегда динамический? Т.е. расти может до неопределенных размеров. Что будете делать, когда он помещаться перестанет? Лучше всё-таки имхо сразу установить максимальный размер и писать в EEPROM блоками по кольцу, вместе с настройками. Для уменьшения износа EEPROM настройки т.е. тоже лучше "двигать".
MOHCTEP писал(а):настройки потребуются "кусками" в непредсказуемые периоды времени
после того, как все настройки считаны в ОЗУ в структуру config, вы в любой момент можете обращаться к её куску config.someone - в чем проблема?
MOHCTEP писал(а):обновляться тоже кусочно будут
на здоровье: в той же структуре обновляйте config.someone когда угодно и сколько угодно раз!
MOHCTEP писал(а):всю эту кучу надо будет перезаписывать, при малейшем изменении?
зачем?! только в критические моменты: при (перед) выключении питания или в моменты простоя (раз в 1...100 секунд, например). для чего после каждого чиха обновлять настройки?!
MOHCTEP писал(а):И "eeprom_update_block" обновит только изменившиеся данные
да, сверит все и обновит только те байты, которые изменились. потому она и update
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
EEMEM не очень подходит для кольцевых буферов. Если уж делаете кольцевой, то делайте "абсолютную" адресацию, как и делали. Только действительно объедините все ваши значения в структуру и всё. Даже разного размера можно делать, только текущий размер тоже записывать в EEPROM надо будет. У меня с фиксированным размером по кольцевому буферу как-то так обычно настройки сохраняются/загружаются:
Спойлер
#define EEPROM_SIZE 512
#define EEPROM_ENTRY_SIZE (sizeof(settings_t) + sizeof(state_t))
#define EEPROM_ENTRIES (EEPROM_SIZE / EEPROM_ENTRY_SIZE)
typedef struct {
uint32_t seq;
// state_t goes here in actual EEPROM
uint16_t crc;
} settings_t;
void load_settings() {
uint8_t *ptr = 0; // byte pointer in EEPROM
uint32_t cur_seq = 0;
state_t state_buf;
cli();
while (queue_num < EEPROM_ENTRIES) {
settings.seq = eeprom_read_dword((void *) ptr);
if (settings.seq <= cur_seq || settings.seq == 0xFFFFFFFF) {
settings.seq = cur_seq;
break;
}
cur_seq = settings.seq;
ptr += sizeof (settings.seq);
eeprom_read_block(&state_buf, (void *) ptr, sizeof (state_buf));
ptr += sizeof (state_buf);
settings.crc = eeprom_read_word((void *) ptr);
ptr += sizeof (settings.crc);
if (settings.crc != crc16((void *) &state_buf, sizeof (state_buf))) {
LOG("CRC incorrect\r\n");
break;
}
// Since we are here, settings are valid, CRC are good
state = state_buf;
queue_num++;
}
sei();
}
void save_settings(eSaveMode savemode) {
cli();
settings.crc = crc16((void *) &state, sizeof (state)); // Calculate crc16 of state struct
// Save data to EEPROM
settings.seq++;
if (queue_num >= EEPROM_ENTRIES) // Reset queue_num once we reach end of EEPROM
queue_num = 0;
uint8_t *ptr = (void *)(queue_num * EEPROM_ENTRY_SIZE); // Get location of next segment in EEPROM
eeprom_write_dword((void *) ptr, settings.seq);
ptr += sizeof (settings.seq);
eeprom_update_block((void *)&state, (void *) ptr, sizeof (state));
ptr += sizeof (state);
eeprom_write_word((void *) ptr, settings.crc);
sei();
}
Ну у меня тут небольшой костыль, две структуры. Т.к. настоящие "настройки" в структуре state, а структура settings - там лишь порядковый номер и CRC. Я тут обрезал, у меня еще кое что там было, не важно в данном случае. Смысл в том, что EEPROM по блокам по размеру обоих структур разбита и по кольцу пишется-читается с порядковым номером и CRC.
имхо, проблема "кольцевых буферов" в EEPROM для сохранения настроек надумана: настройки - это не та информация, которая обновляется часто. скажем, показания одометра обновляются часто, а настройки?! без малейших ухищрений ресурса в 100000 перезаписей должно хватить на 27 часов ежесекундных перезаписей! какие такие настройки можно так часто перезаписывать? а если настройки ведутся 1 раз в минуту, то ресурс исчерпается не раньше, чем через 70 суток. но я не могу себе представить и этой ситуации.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
ARV, ну в принципе да, если именно настройки, которые не часто сохраняются, то можно и без колец обойтись. ТС просто сам про кольц. буфер написал. А у меня там не совсем настройки, а состояния различные сохраняются, не раз в минуту, но может раз 10 за час меняться. Поэтому буфер сделал, чтобы хватило на годы.
ARV, NStorm, спасибо!
Видимо я не совсем точно описал проблему.
Настройки - их одинаковая кучка, а значит и размер в памяти всегда одинаков, меняться будут только непосредственно значения, по необходимости.
Данные. Сначала, при самом первом включении, их просто еще нет. Со временем, они появляются тоже кучкой и пишутся в EEPROM, каждая следующая порция - за предыдущей. Это необходимо, для анализа их изменения и оперативного изменения тех самых настроек. Когда допустимый объем данных заполнен, следующая порция должна запомниться на месте устаревших данных. Вот тут-то, в области данных и нужен кольцевой буфер.
Ступор у меня в том, что разнообразие настроек довольно велико и они тоже разные: от 32 битных, до бит-полей, есть и структуры и массивы, возможны и строки. Вот как весь этот винегрет увязать в структуру и подружить ее с EEPROM?
Ступор у меня в том, что разнообразие настроек довольно велико и они тоже разные: от 32 битных, до бит-полей, есть и структуры и массивы, возможны и строки. Вот как весь этот винегрет увязать в структуру и подружить ее с EEPROM?
Так в чем проблема? Делаете из них структуру и сохраняете, как выше писали. Структуры тоже вполне можно включать в структуры. Строки, если фиксированной максимальной длины - вообще без проблем.
MOHCTEP писал(а):для анализа их изменения и оперативного изменения тех самых настроек
micro-SD и FatFS от нашего японского коллеги по имени Чен решают любые проблемы, как с количеством записей, так и с анализом, так и со строками и всем прочим. файловый ввод-вывод - наше всё. для 128-й меги вообще не вопрос.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Появились еще вопросы, уважаемые коты. Прошу помочь.
1 Доселе обходился как-то без чисел с плавающей точкой, а тут пришлось их попробовать и нарвался на проблему. Почему-то не хотят они у меня плавать, а норовят в целочисленные превратиться. Пробовал готовить по всякому... Что я не так делаю?
Этими структурами постепенно заполняется ЕЕПРОМ (около 200 штучек). Теперь, мне со всех записей нужно прочесть в массив, допустим значения data_t.b[2] или все data_t.a. Вот как это правильно сделать и чтоб оперативка не сильно тратилась? В идеале бы только на массив нужных, в данное время, данных.
Огромная разница. Во 2ом случае сначала year приводится к float, и потом делится на 19 уже как float.
Добавлено after 6 minutes 28 seconds:
[uquote="MOHCTEP",url="/forum/viewtopic.php?p=3885141#p3885141"]Этими структурами постепенно заполняется ЕЕПРОМ (около 200 штучек). Теперь, мне со всех записей нужно прочесть в массив, допустим значения data_t.b[2] или все data_t.a. Вот как это правильно сделать и чтоб оперативка не сильно тратилась? В идеале бы только на массив нужных, в данное время, данных.[/uquote]
uint32_t buf;
eeprom_read_block(&buf, sizeof(data_t) * NR_BLOCK + sizeof(data_t.time), sizeof(buf)); // Прочитать с блока NR_BLOCK (порядковый номер) значение .a
Ну т.е. банально вычисляем начало блока, плюс добавляем пропуск того, что идет до нужных данных, т.е. скипаем их. И читаем нужное кол-во байт. Если все блоки надо прочитать - ну проходимся по очереди NR_BLOCK от 1 до N.
NStorm, Спасибо! С плавающим "флотом" вроде понял суть. А со структурами, вот как мне точно попасть на нужную переменную? Судя по вашему примеру, структура сохраняется в порядке объявления переменных?
И для чтения, к примеру, data_t.с[2] надо вот этакую конструкцию писать?
MOHCTEP, компилятор не меняет порядок в структуре. В каком порядке задали - в таком порядке оно будет в памяти. Т.е. да, "сохраняется в порядке объявления переменных". Единственный момент - как вы структуру в EEPROM писать будете. Если целиком структуру через eeprom_write_block(), то всё будет в таком порядке. Но если вручную как-то - то порядок уже от вас зависеть может.
В вашем примере - да, почти так. Только sizeof(data_t.b) надо еще на 4 умножить, т.к. там у вас массив в примере выше.
Ну и ес-но для удобства, чтобы не писать эту длинную фигню каждый раз, можно определить макрос. Вроде:
Или написать небольшую функцию, которая будет считать нужны адрес каждый раз. Смотря как много разных элементов структуры вам так отдельно выцеплять надо. Функция будет такты отнимать на расчет адреса, макросы с фиксированными смещениями считаются на этапе компиляции, но будут занимать место во флэше.