STM32 — правильно используем встроенный flash

Предисловие

Давно ни для кого не секрет, что STMicroelectronics производит замечательные 32-битные ARM микроконтроллеры STM32. В последнее время они набирают всё большую популярность, и на то есть веские причины, которые в рамках этой статьи я повторять не намерен. Кому интересно — раз, два и три.

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

Именно о таком моменте я и хочу рассказать. А именно — как правильно использовать возможность записи во встроенный flash нашего МК. Добро пожаловать под кат.


Курим маны, читаем статьи

Подавляющее большинство статей (а если точнее — вообще все, которые я видел) предлагают реализацию алгоритма, рекомендуемого в официальном мануале по программированию флеша. Вот такого:



Кодим, компилим, проверяем — всё работает. Хорошо работает. Ровно до тех пор, пока вы не включите оптимизацию. Я использую gcc и проверял с ключами -O1 и -O2. Без оптимизации — работает. С оптимизацией — не работает. Нервно курим, пьём кофе, и тратим день-два на поиск проблемы и размышления о бренности бытия.

Как правильно

Уж не знаю, почему производитель советует использовать неправильно работающий алгоритм. Возможно где-то это объяснено, но за два дня у меня так и не получилось ничего найти. Решение-же оказалось довольно простым — в регистре FLASH->SR для контроля окончания операции надо использовать не бит BSY (искренне не понимаю, почему даже ST рекомендует использовать его), а бит EOP, выставляющийся при окончании текущей операции стирания/записи.

Причина проста — по тем или иным причинам на момент проверки бит BSY может быть ещё не выставлен. Однако бит EOP выставляется тогда, и только тогда, когда операция завершена. Сбрасывается этот бит вручную, записью в него единицы. Кодим, проверяем, радуемся жизни.

Сырцы

Для полноты картины необходимо найти и почитать другие статьи на эту тему (ссылка на одну из них приведена выше). Здесь-же прилагаю исходники с кратеньким описанием.

Разблокировка работы с flash — эти две строчки необходимо вставить в функцию инициализации МК:
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;


Стирание страницы flash — перед записью необходимо стереть данные по нужным адресам, это особенность флеша:
//pageAddress - любой адрес, принадлежащий стираемой странице
void Internal_Flash_Erase(unsigned int pageAddress) {
	while (FLASH->SR & FLASH_SR_BSY);
	if (FLASH->SR & FLASH_SR_EOP) {
		FLASH->SR = FLASH_SR_EOP;
	}

	FLASH->CR |= FLASH_CR_PER;
	FLASH->AR = pageAddress;
	FLASH->CR |= FLASH_CR_STRT;
	while (!(FLASH->SR & FLASH_SR_EOP));
	FLASH->SR = FLASH_SR_EOP;
	FLASH->CR &= ~FLASH_CR_PER;
}


Запись:
//data - указатель на записываемые данные
//address - адрес во flash
//count - количество записываемых байт, должно быть кратно 2
void Internal_Flash_Write(unsigned char* data, unsigned int address, unsigned int count) {
	unsigned int i;

	while (FLASH->SR & FLASH_SR_BSY);
	if (FLASH->SR & FLASH_SR_EOP) {
		FLASH->SR = FLASH_SR_EOP;
	}

	FLASH->CR |= FLASH_CR_PG;

	for (i = 0; i < count; i += 2) {
		*(volatile unsigned short*)(address + i) = (((unsigned short)data[i + 1]) << 8) + data[i];
		while (!(FLASH->SR & FLASH_SR_EOP));
		FLASH->SR = FLASH_SR_EOP;
	}

	FLASH->CR &= ~(FLASH_CR_PG);
}


Вот такие пироги. Приятного всем кодинга и поменьше багов.
Поделиться публикацией
Комментарии 36
    +3
    Впору создавать сайт с реестром и кратким описание мелких ошибок в документации и либе драйверов от STM.
      0
      а разве официальных errata у них нет?
        0
        Есть. Но они часто отстают от реальности, ибо реальные проблемы и способствуют их пополнению =)
      +1
      Мне интересно было бы понять и разобраться с тем как поднимать связку stm32+freeRTOS+lwip на gcc, а то наш контроллерный программист использует iar, который в качестве IDE ну уж очень слабенький.
      По мне так проще было бы прикрутить тулчейн на основе gcc к QtCreator и получить кроссплатформенную среду. Но в сети как-то маловато руководств, есть некие шаблоны, но лично мне слабо понятно как общий шаблон для stm32f4xx натянуть на конкретную плату.
        0
        Ну так IaR тулчейн вас не заставляет использовать IaR IDE. Я лично так и делаю, собираю одним тулчейном, программирую же всегда в другой IDE.

        Другой вопрос — дебагинг.
          0
          А где можно взять iar под macosx или linux?

          И ещё хочется код прошивки и клиента одним компилятором собирать.
            0
            Сам тулчейн можно под wine попробовать погонять.

            Про клиента вы ранее не говорили. Он у вас тоже на ARM Cortex-M4?
              0
              Обычное приложение, общающееся с контроллером по ethernet. Поэтому есть соблазн код сетевого протокола сделать общим. Да и клиент вполне себе компилируется и работает под arm.
                0
                Ну в таком случае GCC чуть ли не единственный полноценный вариант. Есть у него только вопросы по оптимизации и т.п., но если не критично, то отличное решение.
                  0
                  Я так понимаю, что IAR делает просто более компактный код или он реально для Cortex M4 генерирует более быстрый код? Наверняка все можно подкрутить флагами компиляции до одного уровня?
                  P.S.
                  А интересно, как поживает clang-arm-none-eabi?
                    0
                    Есть много статей по поводу сравнения, я лично вынес для себя, что IaR по футпринту делает код меньше. У меня на практике было так, что еле влезали в Flash контроллера, поэтому подобная оптимизация была очень нужна.

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

                    clang'ом не пользовался, но вот armcc очень даже не плохо, на мой взгляд :)
          0
          Насчёт кроссплатформенности мало что подсказать могу, но вот под Windows есть очень хорошая IDE от CooCox. Настраивается в два клика, удобный редактор, под рукой удобная подробная справка по регистрам целевого МК. Бесплатная. Единственный минус — нет поддержки STM8.

          Насчёт связки stm32+FreeRTOS+lwip — lwip не использовал, но FreeRTOS прикручивается довольно просто. На эту тему уже есть довольно много статей, но если кто-нибудь хочет — могу написать ещё один топик.

          Пока искал другие ссылки, нашел вот эту. Возможно поможет с Вашей проблемой.
            +1
            Перенос из одной IDE в другую — довольно муторное занятие. Может пройти всё гладко,
            а может и нет. У разных тулзов здорово различается «нижний» уровень.
            — синтаксис ассемблера (секции, атрибуты символов)
            — «среда исполнения» и стд. либы
            — синтаксис скрипта линкера для сборки
            — ну и работа с заливщиком-отладчиком

            Поэтому в CMSIS например просто сдалали разные подкаталоги под EWARM/GCC/KEIL/и.т.д.
            Уровень "*.с" практически одинаковый, не считая готовых либ. Да, у IAR действительно
            слабенький IDE. И по сравнению с ним IDE-шка в CooCox (Eclipse) — просто праздник какой-то.
            НО! У IAR:
            — могучая либа (готовых strxxx/printf/и.т.д.) в нескольких вариантах
            — встроенный CMSIS
            — отличный отладчик на кучу донглов
              0
              к QtCreator прикрутить нормально не получилось — сложности с отладкой по JTAG. Но удалось прикрутить к Eclipse со всеми возможными плюшками — по шагам ходит, периферию показывает и т.п.
                0
                Там же по идее gdbserver все делает, а QtCreator с ним умеет работать.
              0
              Полезный пост, добавил себе в закладки.

              У меня также интересный случай был с FLASH latency. Надо бы тоже описать.
                +4
                Есть сообществу интересно, то могу написать подробную статью по работе с MicroSD памятью через SPI. Материала на эту тему довольно много, но качество меня не радует.
                0
                А нет ли где подробного описания процесса снятия ReadOut Protection с STM32F1* и STM32F0*? А то сейчас это похоже умеет делать только ST'шная утилита, а под линуксом st-link не позволяет. Вот бы допилить туда эту фичу =)
                  0
                  Проблема STM32Fxxx в том, что при записи во флэш контроллер останавливается полностью. А максимальное время записи там большое. Особенно если нужно стирание выполнить сначала. В результате на практике использоваться флэш для записи каких-то данных невозможно (ну, либо система должна быть некритична к большим паузам в работе, что редкость)
                    0
                    Часто используют для обновления прошивки, а данные куда-нибудь на внешнюю eeprom.
                      0
                      Да, разве что так. И даже в этом случае приходится извращаться. С тем же USB всё очень странно работает, когда контроллер неожиданно останавливается на сотню миллисекунд.
                      0
                      Не такая уж и большая редкость. В двух последних моих проектах как раз использовал встроенный Flash.
                        0
                        Вы готовые к 100 мС паузе в работе прошивки?
                          0
                          Учитывая, что чип почти постоянно в спячке потому, что ему нечего делать — вполне. =)
                            0
                            Это хорошо если в спячке. А таймеры, Ethernet, USB — вот это. А если он чем-то управляет? Приём там 100мС на страницу.
                              0
                              Не существует ничего идеального. У всего есть своё место и назначение. Конкретно в моём случае — Ethernet и USB не было.
                              P.S.: Да, и если не ошибаюсь — останавливается выполнение кода ядром, а не вообще вся периферия. Вы ничего не перепутали?
                      0
                      И ещё — на сколько я помню чудеса с оптимизация и битами вызваны тем, что вы что-то не так делаете :)
                      Если буквально следовать документации то всё работает. Помню, что там были какие-то примечания в совершенно неочевидных местах.
                        0
                        А в errata ничего по этому поводу нет? У них бывает, что флаг выставляется не сразу и надо подождать несколько циклов прежде, чем его начинать мониторить.
                          0
                          Почти наверняка где-то оно есть, но проблема в том, что угробив два дня я так ничего и не нашел. Зато теперь (я надеюсь) — у других разработчиков такой проблемы не возникнет, т.к. эта статья гуглится первой строчкой по всем запросам, которые я вбивал когда искал сам.
                            0
                            Это не errata. Это кривость документации — всё раскидано по массе разделов с кучей примечаний.
                            0
                            Да, именно поэтому я не успокаиваюсь (да и не только я, я думаю), пока прошивка не будет нормально работать с -O2. Решение, предложеное в мануале с -O2 работать отказалось, именно потому я и написал этот пост. По моему мнению использовать флаг занятости (BSY) для контроля окончания операции в принципе не правильно. Например часто такое вижу в статьях, где используется SPI. Для контроля окончания операции фактически всегда есть специальные флаги, именно для этого и предназначенные.
                              0
                              В случае SPI BSY используется если необходимо выключить SPI совсем. Между отправляемыми байтами ждем установки TXE, после последнего отправляемого — ждем снятия BSY и только потом гасим SPI (сбрасываем SPE).
                                0
                                Я не имел ввиду, что этот флаг бесполезен, если Вы так меня поняли. Просто хотел сказать, что у всего есть своё назначение.
                                  0
                                  Это было дополнение, когда он реально полезен. А то, как его используют во всяких примерах, конечно, не лучший вариант.

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

                          Самое читаемое