Любое уважающее себя устройство должно следить за целостностью своей прошивки и сигнализировать если что-то не так.
Для проверки целостности данных удобно пользоваться циклическим избыточным кодом или CRC. Эта штука позволяет рассчитать число уникальное для набора данных. Таким образом имея данные и это число можно проверить верны ли данные или что-то пошло не так и у нас вместо нужных чисел полная билиберда.
В современных микроконтроллерах (вроде stm32) есть даже целый модуль для расчета CRC. Stm32f407 считает CRC32.
Существует огромное количество разновидностей расчета CRC в зависимости от разрядности результата и порождающего полинома. Но сейчас не об этом. Об алгоритмах еще напишу.
Подсчет контрольной суммы позволяют делать и современные среды разработки. Например в IAR есть приблуда, которая позволяет вычислить и впихнуть в нужное место памяти CRC прошивки.
Этим и займемся.
Создадим проект, который средствами IAR будет считать контрольную сумму прошивки, а при помощи периферии stm32 проверим верна ли прошивка.
Для настройки плюшки расчета CRC в IAR необходимо перейти в опции проекта и в меню Linker перейти во вкладку Checksum. В ней необходимо настроить пределы участка памяти для расчета и задать алгоритм CRC.

Теперь нужно изменить скрипт компановщика. Для этого переходим в Linker — Config и ставим галочку Override default и сохраняем в папку с проектом. Теперь нужно подредактировать этот файл. Добавляем в конец файла такую строку:
place at address mem:__ICFEDIT_region_ROM_end__-3 { readonly section .checksum };
Т.к. мы используем 4 байтный CRC32 нам нужно его расположить в памяти в конце прошивки. Мы создаем секцию checksum за 3 байта до последнего байта прошивки (т.е. за 4 до конца).

Теперь программа. Я буду пользоваться периферийной библиотекой ST.
Для того, чтобы вычитать посчитанную IAR контрольную сумму в переменную:
// для импорта контрольной суммы extern uint32_t __checksum;
Также нам будут нужны данные о секциях:
// для использования информации о секциях #pragma section=".intvec" #pragma section=".checksum"
и переменная для хранения CRC посчитанного контролером:
// для хранения подсчитанной контрольной суммы uint32_t calculated_crc;
При старте программы вычитаваем CRC из созданной нами секции памяти и получаем данные о начале и конце прошивки:
// читаем CRC в локальную переменную
uint32_t read_crc = __checksum;
// информация о границах памяти
uint32_t* begin = (uint32_t*)__section_begin(".intvec"); // получаем начало прошивки
uint32_t* end = (uint32_t*)__section_begin(".checksum"); // получаем начало CRC (конец прошивки)
uint32_t* ptr = begin;
Для работы с модулем расчета CRC в stm32 его необходимо затактировать:
// включаем модуль CRC
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
Дальше у нас два пути.
В принципе регистры работы с CRC очень простые и можно использовать обычные структуры:
// сбрасываем регистр данных CRC
CRC->CR |= CRC_CR_RESET;
// считаем CRC
while (ptr != end)
{
CRC->DR = *ptr++;
}
// записываем результат в переменную
calculated_crc = CRC->DR;
Но рас уж у нас есть библиотеки ST можно сделать и так:
// тот же подсчет CRC через библиотеку ST
CRC_ResetDR();
calculated_crc = CRC_CalcBlockCRC(begin, end - begin);
Вот и все. Остается только сравнить полученные данные. Если все ок включим светодиод, ну а если нет — выключим.
// настраиваем светодиод
STM_EVAL_LEDInit(LED3);
while(1)
{
if (calculated_crc == read_crc)
{
// если CRC совпало - зажигаем
STM_EVAL_LEDOn(LED3);
} else {
// если нет - гасим
STM_EVAL_LEDOff(LED3);
}
}
Прикладываю проект для stm32f4 discovery https://www.dropbox.com/s/clvgdyafg2gqixe/iar_crc_calculate.rar







Если не использовать переменную __checksum, и будет включена оптимизация, компилятор выдаст ошибку ielftool error: The string '__checksum' was not found in the string table. Простая строка volatile uint32_t *pCrc = &__checksum; или иное использование в коде __checksum решает проблему.
Отличная статья.
В Project->Options…->Linker->Extra Options поставить галку и добавить —keep __checksum.
Даже не используя рекомендации Олега от 12/02/2016 ошибки линкера не будет.
ps EWARM 7.50