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

Flash-память и загрузчик STM32: запись, защита, прошивка

Как устроена Flash-память STM32F103 и STM32F407, как выбрать область загрузки выводами BOOT0 и BOOT1, через какие интерфейсы прошивает встроенный загрузчик и как выглядит его протокол по UART, как стирать и писать Flash из своей программы, что хранят байты конфигурации и чем грозит защита от чтения уровня 2.

Обновлено Редакция GAW

Flash-память STM32 хранит программу и константы и одновременно служит местом для настроек, калибровок и журналов, если их записывать из программы. Рядом с ней лежат системная память со встроенным загрузчиком ST и байты конфигурации, которые задают защиту и режимы сторожевого таймера. Здесь — как всем этим пользоваться на STM32F103 и STM32F407, по программному руководству PM0075 (Flash STM32F1 описана не в RM0008, а в нём), справочному руководству RM0090 и заметке AN3155 о протоколе загрузчика.

Коротко

  • STM32F103: страницы по 1 КБ (до 128 КБ памяти) или 2 КБ (high-density, connectivity line), запись полусловами, стирание страницы 20–40 мс.
  • STM32F407: 12 секторов — 4 по 16 КБ, один 64 КБ и 7 по 128 КБ; запись байтами, полусловами, словами или двойными словами, стирание сектора 128 КБ — 1–2 с.
  • Ресурс: от 10 тысяч циклов стирания; хранение данных — от 10 до 30 лет в зависимости от температуры и числа циклов.
  • Загрузка: BOOT0 = 0 — из Flash; BOOT0 = 1, BOOT1 = 0 — встроенный загрузчик; BOOT0 = 1, BOOT1 = 1 — из SRAM.
  • Загрузчик работает через USART1 (PA9, PA10) у обоих семейств; синхронизация байтом 0x7F, ответ 0x79.
  • Защита: у STM32F103 снимается со стиранием Flash; у STM32F4 уровень 2 необратим.

Организация Flash-памяти

STM32F103x8/BSTM32F405/407
Основная память64 или 128 страниц по 1 КБ с адреса 0x0800 0000секторы 0–3 по 16 КБ, 4 — 64 КБ, 5–11 по 128 КБ
Системная память (загрузчик ST)2 КБ, 0x1FFF F00030 КБ, 0x1FFF 0000
Однократно программируемая (OTP)нет512 байт и 16 байт блокировки, 0x1FFF 7800
Байты конфигурации16 байт, 0x1FFF F80016 байт, 0x1FFF C000
Единица записиполуслово (16 бит)байт, полуслово, слово, двойное слово — по PSIZE
Время записи40–52,5–70 мкс на полуслово16–100 мкс на слово
Время стираниястраница — 20–40 мс, вся память — 20–40 мс16 КБ — 250–500 мс, 64 КБ — 0,55–1,1 с, 128 КБ — 1–2 с, вся память — 8–16 с при PSIZE = x32
Ресурс10 тысяч циклов10 тысяч циклов

Таблица составлена по PM0075 (таблица 3), RM0090 (раздел 3.3, таблица 5) и таблицам 28 DS5319 и 40 DS8626. У STM32F103 high-density (256–512 КБ) и connectivity line страницы по 2 КБ, а у connectivity line системная память — 18 КБ с адреса 0x1FFF B000 (PM0075, таблицы 4 и 5). У STM32F42x/43x память до 2 МБ разделена на два банка по 12 секторов, и чтение из одного банка не останавливается во время записи в другой (RM0090, раздел 3.4).

Пока идёт запись или стирание, чтение Flash останавливает шину: ядро не может выбрать команду из Flash, пока операция не закончится (PM0075, раздел 1.2; RM0090, раздел 3.6). У STM32F407 стирание сектора 128 КБ длится секунды — программа, которая в это время должна обслуживать прерывания, выполняет критичный код и обработчики из SRAM. Для частых записей настроек на STM32F4 удобнее маленькие секторы 1–3 по 16 КБ, чем секторы по 128 КБ. Время доступа к Flash на высокой частоте задают такты ожидания — их считает калькулятор LATENCY.

Ресурс Flash — не меньше 10 тысяч циклов на всём диапазоне температур, а данные хранятся не меньше 30 лет при 85 °C после тысячи циклов, 10 лет при 105 °C после тысячи циклов и 20 лет при 55 °C после 10 тысяч циклов (DS5319, таблица 29; DS8626, таблица 42).

Режимы загрузки: BOOT0 и BOOT1

BOOT1BOOT0Откуда загрузка
любой0основная Flash-память
01системная память — встроенный загрузчик
11встроенная SRAM

Режимы одинаковы у STM32F1 и STM32F4 (RM0008, таблица 9; RM0090, таблица 2). Выбранная область отображается на адрес 0x0000 0000, откуда ядро берёт начальный указатель стека и вектор сброса. Значения выводов защёлкиваются на четвёртом такте SYSCLK после сброса и снова считываются при выходе из режима Standby. BOOT0 — отдельный вывод, а BOOT1 совмещён с PB2 (DS5319, таблица 5; DS8626, таблица 7): после защёлкивания PB2 свободен для обычной работы. При загрузке из SRAM программа должна сама перенести таблицу векторов регистром VTOR.

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

Встроенный загрузчик

Системная память содержит загрузчик, записанный ST на производстве. Через какие интерфейсы он работает, зависит от линейки (RM0008, раздел 3.4; RM0090, раздел 2.4):

МикроконтроллерИнтерфейсы загрузчика
STM32F103 low-, medium- и high-densityUSART1
STM32F103 XL-densityUSART1, USART2 (на выводах ремапа)
STM32F105/107USART1, USART2 (ремап), CAN2 (ремап), USB OTG FS в режиме DFU
STM32F405/407USART1 (PA9, PA10), USART3 (PB10, PB11 или PC10, PC11), CAN2 (PB5, PB13), USB OTG FS в режиме DFU (PA11, PA12)

USART работают от внутреннего генератора HSI, а CAN и USB требуют кварца: у STM32F105/107 — 8, 14,7456 или 25 МГц, у STM32F407 — с частотой, кратной 1 МГц, от 4 до 26 МГц. У массового STM32F103 загрузчика по USB нет: прошить его по USB «из коробки» нельзя, нужен адаптер USB–UART, программатор SWD или собственный загрузчик.

Протокол загрузчика по UART

Протокол описан в AN3155. Кадр — 8 бит данных, бит чётности even и стоп-бит. Загрузчик ждёт байт 0x7F, по его длительности измеряет скорость передатчика и отвечает подтверждением ACK = 0x79 — после этого он готов к командам. Скорость хоста может быть от 1200 до 115 200 бит/с (это проверенные ST границы), а расхождение скоростей не должно превышать 2,5 % (AN3155, разделы 1 и 2).

Каждая команда — байт кода и его дополнение (их XOR равен 0xFF). Загрузчик отвечает ACK или NACK = 0x1F. Блоки данных завершаются контрольной суммой — XOR всех байтов блока. Основные команды (AN3155, таблица 2):

КодКомандаЧто делает
0x00Getверсия протокола и список команд
0x01Get Versionверсия протокола
0x02Get IDидентификатор микроконтроллера
0x11Read Memoryчитает до 256 байт с заданного адреса
0x21Goпереход к программе во Flash или SRAM
0x31Write Memoryпишет до 256 байт в SRAM или Flash
0x43 / 0x44Erase / Extended Eraseстирание страниц или всей памяти; у микроконтроллера есть только одна из двух команд
0x63 / 0x73Write Protect / Unprotectзащита от записи
0x82 / 0x92Readout Protect / Unprotectзащита от чтения

Утилиты прошивки — например, STM32CubeProgrammer от ST — реализуют этот протокол; сам загрузчик не меняется и не стирается, поэтому вернуться к нему можно всегда, если BOOT0 доступен.

Запись Flash из программы

После сброса регистр управления FLASH_CR заблокирован. Его открывают записью двух ключей в FLASH_KEYR: KEY1 = 0x4567 0123, затем KEY2 = 0xCDEF 89AB; неверная последовательность блокирует регистр до следующего сброса и вызывает ошибку шины (PM0075, раздел 2.3.2; RM0090, раздел 3.6.1). Ключи у STM32F1 и STM32F4 одинаковые.

STM32F1 (PM0075, разделы 2.3.3–2.3.4):

  • запись — только полусловами: установить PG в FLASH_CR, записать 16 бит по нужному адресу, дождаться сброса BSY и проверить результат. Запись не стёртой ячейки пропускается с флагом PGERR — исключение составляет запись 0x0000;
  • стирание страницы — бит PER, адрес любой ячейки страницы в FLASH_AR, бит STRT, ожидание BSY;
  • стирание всей памяти — MER и STRT; системная память и байты конфигурации при этом не затрагиваются;
  • на время записи и стирания должен быть включён генератор HSI (PM0075, раздел 1.2).

STM32F4 (RM0090, разделы 3.6.2–3.6.4): стирание — по секторам (бит SER и номер сектора SNB), банкам или всей памяти, а разрядность записи PSIZE ограничена напряжением питания (RM0090, таблица 13):

ПитаниеPSIZEЕдиница записи
2,7–3,6 В с внешним VPP 8–9 В1164 бита
2,7–3,6 В1032 бита
2,1–2,7 В0116 бит
1,8–2,1 В008 бит

Запись или стирание с PSIZE больше допустимого для текущего напряжения может оставить данные, которые читаются правильно, но не сохранятся (RM0090, раздел 3.6.2).

Пример записи массива полуслов в последнюю страницу STM32F103C8 (адрес 0x0801 FC00, 1 КБ):

#include "stm32f1xx.h"

#define PAGE_ADDR 0x0801FC00U          /* last 1 KB page of a 128 KB STM32F103 */

static void flash_wait(void)
{
    while (FLASH->SR & FLASH_SR_BSY) {}
}

int flash_write_page(const uint16_t *data, uint32_t count)   /* count <= 512 */
{
    FLASH->KEYR = FLASH_KEY1;            /* unlock FLASH_CR */
    FLASH->KEYR = FLASH_KEY2;

    flash_wait();
    FLASH->CR |= FLASH_CR_PER;           /* page erase */
    FLASH->AR = PAGE_ADDR;
    FLASH->CR |= FLASH_CR_STRT;
    flash_wait();
    FLASH->CR &= ~FLASH_CR_PER;

    FLASH->CR |= FLASH_CR_PG;            /* half-word programming */
    for (uint32_t i = 0; i < count; i++) {
        *(volatile uint16_t *)(PAGE_ADDR + 2U * i) = data[i];
        flash_wait();
        if (FLASH->SR & (FLASH_SR_PGERR | FLASH_SR_WRPRTERR))
            break;
    }
    FLASH->CR &= ~FLASH_CR_PG;
    FLASH->CR |= FLASH_CR_LOCK;          /* lock again */

    for (uint32_t i = 0; i < count; i++)
        if (*(volatile uint16_t *)(PAGE_ADDR + 2U * i) != data[i])
            return -1;
    return 0;
}

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

Байты конфигурации и защита

Байты конфигурации (option bytes) задают защиту и некоторые режимы микроконтроллера и загружаются из Flash при сбросе.

У STM32F1 их восемь, каждый хранится вместе с дополнением (PM0075, раздел 2.5): RDP — защита от чтения, USER — сторожевой таймер IWDG аппаратный или программный и сброс при входе в Stop и Standby, Data0 и Data1 — два байта для данных пользователя, WRP0–WRP3 — защита от записи групп страниц (по 4 страницы у low- и medium-density). Чтобы их изменить, после открытия FPEC нужно записать те же ключи KEY1 и KEY2 в FLASH_OPTKEYR, стереть область битом OPTER и записать полуслова с битом OPTPG.

Защита от чтения STM32F1 устроена просто: память не защищена, только если байт RDP равен 0xA5, а его дополнение — 0x5A; любое другое значение, в том числе стёртое 0xFF, означает защиту (PM0075, таблица 6). Под защитой код из Flash работает как обычно, но отладчик и программа, загруженная в SRAM (в том числе через DMA), не могут читать Flash, а страницы 0–3 (0–1 у high-density) защищены от записи (PM0075, раздел 2.4.1). При записи 0xA5 контроллер сначала стирает всю основную память — так прошивку нельзя вытащить, сняв защиту.

У STM32F4 уровней защиты три (RM0090, раздел 3.7.3):

УровеньБайт RDPЧто запрещеноКак снять
00xAAничего—
1любой, кроме 0xAA и 0xCC (по умолчанию после стирания байтов)чтение Flash и резервной SRAM отладчиком, из SRAM и через загрузчикзаписать 0xAA — Flash и резервная SRAM стираются
20xCCвсё, что на уровне 1, плюс отладка JTAG/SWD, загрузка из SRAM и загрузчиком, изменение байтов конфигурацииникак: уровень необратим

Для изменения байтов конфигурации STM32F4 служат свои ключи OPTKEY1 = 0x0819 2A3B и OPTKEY2 = 0x4C5D 6E7F в регистре FLASH_OPTKEYR. Если защита ставится при подключённом отладчике, новые байты загружаются только при сбросе по питанию — это оговаривают и PM0075, и RM0090. Уровень 2 ST советует ставить только на готовых изделиях: после него отладить или проанализировать микросхему невозможно, в том числе для самой ST.

Свой загрузчик и переход в приложение

Собственный загрузчик — небольшая программа в начале Flash, которая принимает новую прошивку по UART, CAN, USB или радио, пишет её в остальную память и передаёт управление. Приложение компонуется с начального адреса после загрузчика, а его таблица векторов переносится регистром VTOR. Таблица должна быть выровнена по числу векторов, но не меньше чем на 128 слов — 512 байт (PM0056, раздел 4.4.4). В шаблоне CMSIS для этого есть настройка: определение USER_VECT_TAB_ADDRESS и смещение VECT_TAB_OFFSET в system_stm32f1xx.c, и SystemInit приложения сам запишет VTOR.

Переход из загрузчика в приложение:

#include "stm32f1xx.h"

#define APP_ADDR 0x08004000U            /* the application starts after a 16 KB bootloader */

void jump_to_app(void)
{
    uint32_t sp = *(volatile uint32_t *)APP_ADDR;          /* initial stack pointer */
    uint32_t pc = *(volatile uint32_t *)(APP_ADDR + 4U);   /* reset handler */

    __disable_irq();
    SysTick->CTRL = 0;                                      /* stop SysTick */
    for (uint32_t i = 0; i < 8; i++) {                      /* disable and clear all IRQs */
        NVIC->ICER[i] = 0xFFFFFFFFU;
        NVIC->ICPR[i] = 0xFFFFFFFFU;
    }
    SCB->VTOR = APP_ADDR;
    __set_MSP(sp);
    __enable_irq();
    ((void (*)(void))pc)();
}

Перед переходом загрузчик выключает всё, что включал сам: периферию, DMA, прерывания, — иначе приложение получит прерывание раньше, чем настроит его обработчик. Проверить, что по адресу действительно лежит приложение, можно по первому слову: начальный указатель стека должен указывать в SRAM.

Частые ошибки

  • Стирание страницы, в которой выполняется программа, — программа перестаёт существовать на середине функции.
  • Запись в не стёртую ячейку STM32F1 — пропускается с флагом PGERR, данные не меняются.
  • Неверный PSIZE на STM32F4 — данные выглядят записанными, но не сохраняются.
  • Байты конфигурации без сброса по питанию при подключённом отладчике — новая защита не вступает в силу.
  • RDP уровня 2 на отладочной плате — микросхему больше нельзя отладить.
  • Приложение без переноса VTOR — прерывания уходят в обработчики загрузчика.
  • BOOT0 в воздухе — микроконтроллер то запускает программу, то загрузчик.

Частые вопросы

Как прошить STM32 без программатора?

Встроенным загрузчиком из системной памяти. Подайте 1 на BOOT0 и 0 на BOOT1 (PB2), сбросьте микроконтроллер и подключите адаптер USB–UART к USART1: PA9 — TX, PA10 — RX. Загрузчик ждёт байт 0x7F, по нему определяет скорость и отвечает 0x79. Так работают все STM32F103 и STM32F407; у STM32F407, кроме того, есть USART3, CAN2 и USB DFU, у STM32F103 USB DFU в загрузчике нет — он есть только у STM32F105/107.

Сколько раз можно перезаписать Flash STM32?

Не меньше 10 тысяч циклов стирания и записи на всём диапазоне температур. После 10 тысяч циклов данные хранятся не меньше 20 лет при 55 °C, после тысячи — 30 лет при 85 °C и 10 лет при 105 °C (DS5319, таблица 29; DS8626, таблица 42). Для часто меняющихся данных Flash расходуют по кругу: пишут записи друг за другом и стирают страницу, только когда она заполнена.

Как снять защиту от чтения STM32F103?

Записать в байт RDP значение 0xA5: это можно сделать через встроенный загрузчик (команда Readout Unprotect) или отладчиком из SRAM. Перед снятием защиты контроллер Flash сам стирает всю основную память, поэтому прочитать прошивку так нельзя. Затем нужен сброс, а если отладчик был подключён — сброс по питанию (PM0075, раздел 2.4.1).

Что будет, если включить RDP уровня 2 на STM32F4?

Уровень 2 (байт RDP = 0xCC) необратим: отладочный порт JTAG/SWD отключается навсегда, загрузка из SRAM и системного загрузчика запрещена, байты конфигурации больше нельзя менять. Работать будет только программа из Flash, и обновлять её придётся своим загрузчиком (RM0090, раздел 3.7.3).

Источники

  1. STMicroelectronics. PM0075 Rev 2. STM32F10xxx Flash memory microcontrollers, programming manual — 1.2 — страницы, системная память и байты конфигурации (таблицы 2–5), остановка шины при записи, HSI при записи и стирании; 2.3 — ключи, запись полусловами, стирание страницы и всей памяти, запись байтов конфигурации; 2.4 — защита от чтения (таблица 6) и от записи; 2.5 — байты конфигурации (таблицы 7–9)
  2. STMicroelectronics. RM0008 Rev 21. Reference manual: STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx — 3.4 — режимы загрузки (таблица 9), защёлкивание BOOT на 4-м такте, встроенный загрузчик: USART1, у XL-density ещё USART2, у connectivity line — CAN2 и USB DFU
  3. STMicroelectronics. RM0090 Rev 22. Reference manual: STM32F405/415, STM32F407/417, STM32F427/437 and STM32F429/439 — 2.4 — режимы загрузки (таблица 2), встроенный загрузчик: USART1, USART3, CAN2, USB OTG FS; 3.3–3.4 — секторы, системная память, OTP, двухбанковая память F42x/43x (таблицы 5–8); 3.6.1 — ключи; 3.6.2 — разрядность записи PSIZE от напряжения (таблица 13); 3.7.3 — уровни защиты RDP; 3.9 — ключи OPTKEYR
  4. STMicroelectronics. AN3155 Rev 22. USART protocol used in the STM32 bootloader — 1 — синхронизация байтом 0x7F, чётность even, ответ 0x79; 2 — скорость 1200–115 200 бит/с, расхождение не больше 2,5 %; 3 — команды (таблица 2), ACK 0x79 и NACK 0x1F, дополнение команды и контрольная сумма XOR
  5. STMicroelectronics. DS5319 Rev 20 и DS8626 Rev 12 — даташиты STM32F103x8/B и STM32F405/407 — DS5319: таблица 28 — время записи и стирания, таблица 29 — ресурс и хранение данных, таблица 5 — PB2/BOOT1; DS8626: таблица 40 — время записи и стирания секторов, таблица 42 — ресурс и хранение, таблица 7 — PB2/BOOT1
  6. STMicroelectronics. PM0056 Rev 7. STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual — 4.4.4 — регистр VTOR: выравнивание таблицы векторов не меньше 128 слов
  7. STMicroelectronics. CMSIS Device F1: system_stm32f1xx.c, stm32f103xb.h — USER_VECT_TAB_ADDRESS и VECT_TAB_OFFSET — перенос таблицы векторов в SystemInit; имена битов FLASH для примера

Нашли ошибку?