Подсчет CRC прошивки средствами IAR и проверка на stm32f4 discovery

Любое уважающее себя устройство должно следить за целостностью своей прошивки и сигнализировать если что-то не так.
Для проверки целостности данных удобно пользоваться циклическим избыточным кодом или 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

Просмотров:   8590

Комментарии

пт, 12/02/2016 - 17:18
Олег

Если не использовать переменную __checksum, и будет включена оптимизация, компилятор выдаст ошибку ielftool error: The string '__checksum' was not found in the string table. Простая строка volatile uint32_t *pCrc = &__checksum; или иное использование в коде __checksum решает проблему.

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

Plain text

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.
CAPTCHA
Введи эти символы. Ато роботы одолели!