STM32 FLASH.

STM32 FLASH.

Думаю постоянные посетители сайта заметили, что предпочитаю все делать на регистрах, но иногда все таки использую SPL. Например, в статье про самописный бутлоадер, использовались библиотечные функции для работы с флэш памятью.

if(new_firmware)
 {
     // для работы с флешем используем StdPeriph, не забудь ее подключить
     //разблокируем флэш,
      FLASH_Unlock();
      //очищаем флаги
      FLASH->SR |= FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR;
	//стираем страницы
	for(erase_counter = 0; (erase_counter <= count_page) && (FLASHStatus == FLASH_COMPLETE); erase_counter++)
	{
		FLASHStatus = FLASH_ErasePage(APPLICATION_ADDRESS + (FLASH_PAGE_SIZE * erase_counter));
	}

      /*обновляемся*/

      //блокируем флэш
      FLASH_Lock();
 }


В очередной раз, подключая эту библиотеку, решил, что она занимает много места и решил самостоятельно реализовать необходимые функции.

Для работы с флэш памятью предназначены 7 регистров:
  • Key register (FLASH_KEYR)
  • Option byte key register (FLASH_OPTKEYR)
  • Flash control register (FLASH_CR)
  • Flash status register (FLASH_SR)
  • Flash address register (FLASH_AR)
  • Option byte register (FLASH_OBR)
  • Write protection register (FLASH_WRPR)



FLASH_KEYR
После сброса МК FPEC (Flash memory program/erase controller) защищен от случайной записи/стирания. И для того, чтобы его разблокировать необходимо в регистр FLASH_KEYR последовательно записать два ключа: KEY1 = 0×45670123 и KEY2 = 0xCDEF89AB.

#define FLASH_KEY1 ((uint32_t)0x45670123)
#define FLASH_KEY2 ((uint32_t)0xCDEF89AB)

void FLASH_Unlock(void)
{
	FLASH->KEYR = FLASH_KEY1;
	FLASH->KEYR = FLASH_KEY2;
}	
 

После этого бит LOCK в регистре FLASH_CR будет сброшен, а по окончании записи его надо программно установить.

void FLASH_Lock(void)
{
	FLASH->CR |= FLASH_CR_LOCK;
}



FLASH_OPTKEYR
Позволяет снять защиту с опционных байтов для их модификации, которые после сброса МК доступны только для чтения. По своему назначению схож с FLASH_KEYR, ключи и последовательность действий для его разблокировки такая же. Отличие состоит в том, что после последовательной записи двух ключей будет установлен бит OPTWRE в регистре FLASH_CR, который разрешает запись данных в область опционных байт флэш памяти.


FLASH_SR
STM32 FLASH.

BSY(Busy) — устанавливается во время операций записи/стирания и сбрасывается по окончании или возникновении ошибки.

PGERR(Programming error) — устанавливается при попытке программирования не стертой памяти, то есть значение которой отлично от 0xFFFF.

WRPRTERR(Write protection error) — устанавливается при попытке программирования, защищенной от записи области.

EOP(End of operation) — устанавливается аппаратно, при успешном завершении операции записи/стирания.


FLASH_CR
Выше мы уже задействовали регистр FLASH_CR, предлагаю рассмотреть битовые поля из которых он состоит.
STM32 FLASH.

PG(Programming) — запись единицы в этот бит разрешает программирование флэш памяти.

PER(Page erase) — запись единицы в этот бит позволяет стереть одну страницу флэш памяти.

MER(Mass erase) — запись единицы в этот бит разрешает полное стирание флэш памяти.

OPTPG(Option byte programming) — запись единицы в этот бит разрешает программирования опционных байтов.

OPTER(Option byte erase) — запись единицы в этот бит позволяет стирать опционные байты.

STRT(Start) — запись единицы в этот бит запускает процедуру стирания флэш памяти.

LOCK(LOCK) — запись единицы в этот бит блокирует запись/стираниt флэш памяти.

OPTWRE(Option bytes write enable) — запись единицы в этот бит разрешает программирование опционных байтов.

ERRIE(Error interrupt enable) — запись единицы в этот бит разрешает генерацию прерываний при возникновении ошибок, то есть при установке PGERR или WRPRTERR в регистре FLASH_SR.

EOPIE(End of operation interrupt enable) — запись единицы в этот бит разрешает генерацию прерываний по окончанию операции записи/стирания, то есть при установке EOP в регистре FLASH_SR.

OBL_LAUNCH(Force option byte loading) — запись единицы в этот бит...


FLASH_AR
Предназначен для задания адреса при программировании флэш памяти. Для стирания страницы, в этот регистр необходимо записать любой из адресов, входящих в эту страницу и не обязательно начальный.


FLASH_OBR и FLASH_WRPR
Эти регистры в операциях записи и стирания не участвуют, а предназначены для установки защиты МК. Об этом планируется отдельная статья.


В коде приведенном в начале статьи видно, что перед тем как писать во флэш её надо очистить, а стирать флэш у STM32 можно либо по одной странице, либо полностью. При обновлении прошивки бутлоадером, вариант полного стирания флэш памяти не подходит(затрется сам бутлоадер), по этому необходимо стирать по одной странице. Размер страницы необходимо уточнить в документации на МК.

_Bool flash_ready(void) 
{
	return !(FLASH->SR & FLASH_SR_BSY);
}

_Bool check_EOP(void)
{
	if(FLASH->SR & FLASH_SR_EOP)
	{	
		FLASH->SR |= FLASH_SR_EOP;
		return 1;
	}	
	return 0;
}	

_Bool FLASH_Erase_Page(uint32_t address) 
{
	while(!flash_ready()); //Ожидаем готовности флеша к записи
	
	FLASH->CR|= FLASH_CR_PER; //Устанавливаем бит стирания одной страницы
	FLASH->AR = address; // Задаем её адрес
	FLASH->CR|= FLASH_CR_STRT; // Запускаем стирание
	while(!flash_ready());  //Ждем пока страница сотрется
	FLASH->CR &= ~FLASH_CR_PER; //Сбрасываем бит стирания одной страницы
	
	return check_EOP();//операция завершена, очищаем флаг
}

Прочитать данные 32-битной переменной, очень просто достаточно знать ее адрес.
data= (*(__IO uint32_t*) address)


Для записи данных, также необходим адрес и понимание того, что данные пишутся блоками по 16 бит.
_Bool FLASH_Program_Word(uint32_t address,uint32_t data)
{
	while(!flash_ready()); //Ожидаем готовности флеша к записи
	
	FLASH->CR |= FLASH_CR_PG; //Разрешаем программирование флеша
	*(__IO uint16_t*)address = (uint16_t)data; //Пишем младшие 2 байта
	while(!flash_ready());//Ждем завершения операции
	if(!check_EOP())return 0;
	
	address+=2;//Прибавляем к адресу два байта
	data>>=16;//Сдвигаем данные
	*(__IO uint16_t*)address = (uint16_t)data; //Пишем старшие 2 байта
	while(!flash_ready());//Ждем завершения операции
	FLASH->CR &= ~(FLASH_CR_PG); //Запрещаем программирование флеша
	
	return check_EOP();
}

В случае если функция вернула ноль, необходимо проверить значение флагов в регистре FLASH_SR, чтобы понять причину возникновения ошибки.

Вот и всё, основные необходимые функции для работы с памятью реализованы и многие непонятные моменты прояснились. Все что для этого надо было — это прочитать пару страниц даташита)))
комментарии
0