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

в 14:33, , рубрики: flash, stm32, микроконтроллеры, Программинг микроконтроллеров, метки: , ,
Предисловие

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

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

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

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

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

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);
}

Вот такие пироги. Приятного всем кодинга и поменьше багов.

Автор: EighthMayer

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js