Перейти к содержанию
    

Проверка корректности данных во флеш STM32F103

Коллеги, есть проблемка. Сохраняю настройки во флеш. Есть функция, которая читает настройки при старте и в случае их некорректности (порча ячейки) устанавливает дефолтное значение.

Эта функция за время жизни устройства запускается как минимум один раз - при первой прошивке настройки пусты, программа понимает, что в ячейке бред, устанавливает дефолтное значение и пишет его во флеш.

 

В одной из ячеек хранится float. Его корректность проверяется следующим образом:

 
flash_data=flash_read(page_address+8);  // Читаем
OPTIONS_VAR.VoltageMAX=UintToFloat(flash_data); //Преобразуем во float
   if ((OPTIONS_VAR.VoltageMAX<12) || (OPTIONS_VAR.VoltageMAX>20))  // проверяем диапазон и если там некорректные данные то...
    { 
     OPTIONS_VAR.VoltageMAX=14;  // ставим дефолт
     OPTIONS_FLASH_ERROR=1; // ставим флаг ошибки, ориентируясь на который программа в дальшейшем пытается записать во флеш правильное значение
   }

 

Но вот беда, при пустом флеше в ячейке располагается нечто, что будучи преобразованным при помощи UintToFloat отображается в отладчике как " -1.#QNAN ". Это полбеды, настоящая беда в том, что вышеприведенная функция считает что данные корректны и не считает нужным их исправлять.

То есть " -1.#QNAN " удовлетворяет условиям if ((OPTIONS_VAR.VoltageMAX<12) || (OPTIONS_VAR.VoltageMAX>20))

 

 

Что делать?

 

Добавлено спустя 1 минуту

 

Кто-нибудь объяснит феномен, по которому над проблемой бьешся час, не находишь решения, потом задаешь вопрос на форуме, после чего решение, не дожидаясь ответов, приходит в голову немедленно?

Изменено пользователем murmur

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

по стилю написания:

 

1. никогда не используйте в тексте "магические числа", определяйте все такие величины заранее . В Вашем случае- неплохо иметь файл "defaults.h" и в нем дефайны вроде

#define CONFIG_V_MIN 12   ; минимально допустимая величина напряжения в конфиге

 

2. Подавляющее большинство программописателей четко разграничивает использование прописных(заглавных) и строчных букв в именах.

Например, имена констант состоят из заглавных букв, имена глобальных переменных начинаются с заглавной буквы, имена локальных переменных начинаются с строчной буквы.

Такие простые правила очень повышают читабельность кода.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проверять корректность блока данных по значению какой-то отдельной переменной, на мой взгляд, не есть гуд

Не проще добавить дополнительное поле с CRC? Достоверность в разы повысится

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Эта функция за время жизни устройства запускается как минимум один раз - при первой прошивке настройки пусты, программа понимает, что в ячейке бред, устанавливает дефолтное значение и пишет его во флеш.

Что делать?

Стирайте флэш перед записью программы. Тогда будете из ячейки читать 0xFF

А можно еще в программе описать константы в заданный регион флэша и они попадут в прошивку.

 

Кто-нибудь объяснит феномен, по которому над проблемой бьешся час, не находишь решения, потом задаешь вопрос на форуме, после чего решение, не дожидаясь ответов, приходит в голову немедленно?

 

Не помню как называется, но при описании проблемы ручками на бумаге или какому-нибудь собеседнику, мысли выстраиваются в логическую цепочку и формулируют законченный вопрос, в котором как известно, уже есть 50% ответа.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проверять корректность блока данных по значению какой-то отдельной переменной, на мой взгляд, не есть гуд

Не проще добавить дополнительное поле с CRC? Достоверность в разы повысится

 

Была такая мысль.

Но из-за одного испорченного байта сбрасывать в дефолт все настройки? Не есть гуд.

Можно конечно поставить цель меганадежного хранения данных, тогда нужно писать три копии переменных и сверять их содержимое, то есть будет возможность восстановления данных. Но это не самоцель.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void load_settings()
{
    int i;
    uint32_t v_data;
    uint32_t * v_settings_src = addr_flash_sector_11;
    uint32_t * v_settings_dst = &m_settings;

    CRC->CR |= CRC_CR_RESET;
    for (i = 0; i < sizeof(m_settings) / sizeof(uint32_t); i++)
    {
        v_data = *v_settings_src++;
        *v_settings_dst++ = v_data;
        CRC->DR = v_data;
    }
    m_is_settings_valid = *v_settings_src++ == CRC->DR;
    if (!m_is_settings_valid)
        load_default_settings();
}

 

 

феномен

эгрегор

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но из-за одного испорченного байта сбрасывать в дефолт все настройки? Не есть гуд.

Конечно, ибо у вас не будет гарантии, что настройка корректные.

Например, в вашем примере переменная может изменятся от 12 до 20 с дефолтом 17.

Для корректной работы, например, нужно не менее 15.

В результате ЧЕГО-ТО настройка стала некорректной, но попадающей в диапазон от 12 до 20, например, 13.

Для вас это нормально?!

Скажем так: вероятность потерять настройки ооочень низкая. Вряд ли вы когда получите события несовпадения CRC

и сброса всех настроек к дефолту. При этом CRC позволяет легко и надежно контролировать корректность настроек.

Можно хранить несколько упорядоченных копий, и если в последней CRC битая, то брать предыдущий набор,

у которого CRC будет валидной.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но из-за одного испорченного байта сбрасывать в дефолт все настройки? Не есть гуд.

ооочень спорно

если что-то похерилось в настройках, значит прибор будет работать не так, как нужно? или я что-то не понимаю?

определите тогда некую критическую секцию и считайте CRC для нее, а все остальное будет болтаться, как Бог на душу положит

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

если что-то похерилось в настройках, значит прибор будет работать не так, как нужно? или я что-то не понимаю?

В целом может быть вы и правы. В моем случае, если настройки сбросятся, ничего страшного не произойдет. Их просто нужно будет поставить на место.

И таким образом имеем два варианта

1. Ваш - прикручиваем CRC, загружаемся, ловим ошибку CRC - дальше что делаем? Наверное то же что делаю я - ставим безопасные настройки. Причем все, вы ведь по CRC всю структуру будете браковать?

2. Мой вариант - проверяем корректность настроек поштучно. Ставим по дефолту только тот параметр, который невменяем.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Однозначно надо CRC дела.

А по поводу NaN https://ru.wikipedia.org/wiki/NaN

http://stackoverflow.com/questions/4617796/1-qnan-error-c

 

Очень странным кажется то, что это число проходит проверку... Такого быть не должно, где-то тут ошибка с выводами. Возможно не чисто поставлен эксперимент...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Очень странным кажется то, что это число проходит проверку...

Это не число проходит проверку, это ошибка логики.

Условие сформировано так что идет проверка не лежит ли число в пределах, отличных от рассматриваемого? То есть не находится ли оно в пределах от 0 до 12 и от 20 до 65535. Естественно оно в этих пределах не находится, поскольку не является числом. Отсюда программа делает ошибочный вывод, что расссматриваемое число лежит в пределах от 12 до 20 ти.

 

Правильно нужно было сделать так

if ((!(OPTIONS_VAR.VoltageMAX>=12)) && (!(OPTIONS_VAR.VoltageMAX<=20)))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

неправильно

логика в том, что если у вас накрылся хотя бы один байт, то нет никаких гарантий, что не накрылись остальные

пусть даже они всё ещё находятся в допустимом диапазоне

так что

1. проверяйте контрольный код всего блока настроек

2. если не совпадает, грузите настройки с зеркальной копии и отправляйте предупреждение

3. если зеркала нет, грузите настройки с последней валидной резервной копии и переходите в режим конфигурации пользователем

4. если резервной копии нет, грузите дефолтовые настройки и переходите в режим конфигурации пользователем

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А, понял. Не присмотрелся к услови. Т.е. для вас результат сравнения == false является позитивным ответом и считается, ошибки нет и все ок.

 

if ((!(OPTIONS_VAR.VoltageMAX>=12)) && (!(OPTIONS_VAR.VoltageMAX<=20)))
ну в целом идея хорошая, только не ясно зачем отрицание ! ?

 

Потому что если это не опечатка и в программе именно так, то это отрицание всё испортит. Если оба сравнения вернут false(а с NAN так и будет), то оператору && достанутся два true(благодаря отрицанию) и опять получится ерунда.

 

Но все это не важно, надеюсь будет CRC.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Была такая мысль.

Но из-за одного испорченного байта сбрасывать в дефолт все настройки? Не есть гуд.

Можно конечно поставить цель меганадежного хранения данных, тогда нужно писать три копии переменных и сверять их содержимое, то есть будет возможность восстановления данных. Но это не самоцель.

Достаточно двух в разных сегментах. Очень сложно будет угробить их одновременно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...