сайт для палких паяльників

Работа с Flash памятью

STM32 не имеет энергонезависимой EEPROM памяти. EEPROM есть только у STM32L. Так случилось, что в STMicroelectronics решили, что EEPROM нужна только для Ultra Low Power серии микроконтроллеров. А что же нам делать? Нам нужна энергонезависимая память. Где нам хранить наши данные, настройки и т.д.? Во Flash! Да, в той же памяти, где лежит программа микроконтроллера. STM32 может писать во Flash память.

Для того, чтобы безопасно что то записать во Flash память, надо сначала выяснить ее структуру. Нас интересует Main memory. Именно в ней хранится программа и в эту память мы будем писать. Конечно, в не занятый программой участок памяти. Flash память разбита на страницы. Количество и размер страниц в разных контроллерах разная. О структуре памяти Вашего микроконтроллера читайте в Programming manual.

stm32_flash

Эта таблица приведена для всех STM32F103 medium-density devices. У нашего контроллера STM32F103C8 64 Кб Flash памяти. То есть, адрес начала последней страницы 0x800FC00.

А теперь “приколы”, то есть ограничения при использовании Flash:

  • Писать можно только в предварительно вытертую память. В стертой памяти все биты установлены в “1”.
  • Вытирать можно только страницу целиком. То есть, мы не можем вытереть 1, 2, или 10 байт, только страницу целиком. В нашем случае – это блок в 1 КБ.
  • Писать во Flash надо словами по 32 бита.

Если нам надо хранить во Flash настройки, лучше всего это делать на последних страницах Flash памяти. Одного килобайта нам хватит, поэтому мы будем использовать последнюю страницу. Я раньше не зря упомянул адрес последней страницы. Еще нам надо следить за размером программы. Если размер прошивки будет залезать на последнюю страницу – это проблема. Мы не можем гарантировать целостность данных и самой прошивки.

Теперь перейдем к практической реализации.

Перед тем, к начинать работу с Flash надо выполнить пару функций – FLASH_PrefetchBufferCm, FLASH_SetLatency.

void FLASH_Init(void) {
	/* Next commands may be used in SysClock initialization function
	   In this case using of FLASH_Init is not obligatorily */
	/* Enable Prefetch Buffer */
	FLASH_PrefetchBufferCmd( FLASH_PrefetchBuffer_Enable);
	/* Flash 2 wait state */
	FLASH_SetLatency( FLASH_Latency_2);
}

Эти функции могут быть выполнены при настройке рабочей частоты. Смотри статью “4 STM32. Программирование STM32F103. Тактирования

FLASH Latency рекомендуется устанавливать:

FLASH_Latency_0 – 0 < SYSCLK≤ 24 MHz
FLASH_Latency_1 – 24 MHz < SYSCLK ≤ 48 MHz
FLASH_Latency_2 – 48 MHz < SYSCLK ≤ 72 MHz

Для записи во Flash память надо её разблокировать, стереть страницу, записать информацию, заблокировать Flash:

FLASH_Unlock();
FLASH_ErasePage(MY_FLASH_PAGE_ADDR);
FLASH_ProgramWord((uint32_t)address1, (uint32_t)data1);
FLASH_ProgramWord((uint32_t)address2, (uint32_t)data2);
...
FLASH_ProgramWord((uint32_t)addressn, (uint32_t)datan);
FLASH_Lock();

Читать с флэш:

(*(__IO uint32_t*)address);

Читать 32-битными словами не всегда удобно и, как правило, нам нужно хранить несколько настроек с различными типами данных. Для упрощения этого процесса сделаем структуру с параметрами, которые нам надо сохранять:

typedef	struct
  {
	char Parameter1;		// 1 byte
	uint8_t Parameter2;		// 1 byte
	uint16_t Parameter3;	// 2 byte
	uint32_t Parameter4;	// 4 byte
							// 8 byte = 2 * 32 bits words.  It's - OK
							// !!! Full size (bytes) must be a multiple of 4 !!!
  } tpSettings;

Одно требование к этой структуре: ее длина должна быть кратная 32 битам, то есть кратно 4 байт, поскольку мы можем писать в Flash память только 32 битными словами. Например, создадим такую структуру, с тремя параметрами:

typedef	struct
  {
	char Parameter1;		// 1 byte
	uint8_t Parameter2;		// 1 byte
	unsigned char Parameter3;	// 1 byte
							// 3 byte = 24 bits.  It's NOT OK!
							// !!! Full size (bytes) must be a multiple of 4 !!!
  } tpSettings;

Эти параметры занимают только 3 байта, то есть 24 бита. Надо “дотянуть” размер до целого 32-битного слова. Можно просто добавить дополнительный параметр, назовем его nothing:

typedef	struct
  {
	char Parameter1;		// 1 byte
	uint8_t Parameter2;		// 1 byte
	unsigned char Parameter3;	// 1 byte

	uint8_t nothing;		// 1 byte

							// 4 byte = 32 bits.  It's - OK
							// !!! Full size (bytes) must be a multiple of 4 !!!
  } tpSettings;

Теперь нам понадобится две функции для чтения и записи нашей структуры:

void FLASH_ReadSettings(void) {
	//Read settings
	uint32_t *source_addr = (uint32_t *)MY_FLASH_PAGE_ADDR;
	uint32_t *dest_addr = (void *)&settings;
	for (uint16_t i=0; i<SETTINGS_WORDS; i++) {
		*dest_addr = *(__IO uint32_t*)source_addr;
		source_addr++;
		dest_addr++;
	}
}

void FLASH_WriteSettings(void) {
	FLASH_Unlock();
	FLASH_ErasePage(MY_FLASH_PAGE_ADDR);

	// Write settings
	uint32_t *source_addr = (void *)&settings;
	uint32_t *dest_addr = (uint32_t *) MY_FLASH_PAGE_ADDR;
	for (uint16_t i=0; i<SETTINGS_WORDS; i++) {
		FLASH_ProgramWord((uint32_t)dest_addr, *source_addr);
		source_addr++;
		dest_addr++;
	}

	FLASH_Lock();
}

MY_FLASH_PAGE_ADDR – это адрес страницы, где мы будем хранить наши настройки.
SETTINGS_WORDS – количество 32-битных слов, которые занимает структура.

Полный код программы:

#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_flash.h"


// ====================================================
// FLASH Settings struct
// ====================================================
#define MY_FLASH_PAGE_ADDR 0x800FC00

typedef	struct
  {
	char Parameter1;		// 1 byte
	uint8_t Parameter2;		// 1 byte
	uint16_t Parameter3;	// 2 byte
	uint32_t Parameter4;	// 4 byte

							// 8 byte = 2  32-bits words.  It's - OK
							// !!! Full size (bytes) must be a multiple of 4 !!!
  } tpSettings;

tpSettings settings;

#define SETTINGS_WORDS sizeof(settings)/4

void FLASH_Init(void) {
	/* Next commands may be used in SysClock initialization function
	   In this case using of FLASH_Init is not obligatorily */
	/* Enable Prefetch Buffer */
	FLASH_PrefetchBufferCmd( FLASH_PrefetchBuffer_Enable);
	/* Flash 2 wait state */
	FLASH_SetLatency( FLASH_Latency_2);
}

void FLASH_ReadSettings(void) {
	//Read settings
	uint32_t *source_addr = (uint32_t *)MY_FLASH_PAGE_ADDR;
	uint32_t *dest_addr = (void *)&settings;
	for (uint16_t i=0; i<SETTINGS_WORDS; i++) {
		*dest_addr = *(__IO uint32_t*)source_addr;
		source_addr++;
		dest_addr++;
	}
}

void FLASH_WriteSettings(void) {
	FLASH_Unlock();
	FLASH_ErasePage(MY_FLASH_PAGE_ADDR);

	// Write settings
	uint32_t *source_addr = (void *)&settings;
	uint32_t *dest_addr = (uint32_t *) MY_FLASH_PAGE_ADDR;
	for (uint16_t i=0; i<SETTINGS_WORDS; i++) {
		FLASH_ProgramWord((uint32_t)dest_addr, *source_addr);
		source_addr++;
		dest_addr++;
	}

	FLASH_Lock();
}
// ====================================================


int main(void)
{
    FLASH_Init();
    FLASH_ReadSettings();

    settings.Parameter1++;
    settings.Parameter2++;
    settings.Parameter3++;
    settings.Parameter4++;

    FLASH_WriteSettings();

    while (1)
    {

    }
}

Памятка

Надо помнить, что Flash память имеет ограничения на количество циклов записи. Согласно документации – минимум 10000. Это не очень и много, если достаточно интенсивно использовать Flash память. Но для хранения настроек вполне достаточно.

Желаю успехов!

Смотри также:

1 коментар: 16. STM32. Программирование STM32F103. Flash

  • DarkDevil говорить:

    “Эта таблица приведена для всех STM32F103 medium-density devices. У нашего контроллера STM32F103C8 64 Кб Flash памяти. То есть, адрес начала последней страницы 0x800FC00.”

    0x801FC00 наверное так должно быть?)

Translate
Архіви

© 2011-2018 Андрій Корягін, Кременчук - Київ, Україна