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

16. STM32. Программирование STM32F103. Flash
(на русском языке)

Робота із 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

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

 
Translate
Архіви

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