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

Опубликовано lamazavr - вт, 09/30/2014 - 22:01
Body

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

Статья действительно хорошая.
Спасибо, Александр, что поделились способом избавления от ошибки линкера.

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

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