Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кармин Новиелло - Освоение STM32.pdf
Скачиваний:
2754
Добавлен:
23.09.2021
Размер:
47.68 Mб
Скачать

Управление Flash-памятью

554

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

21.2. Модуль HAL_FLASH

Как и все другие периферийные устройства STM32, даже Flash-память предоставляет несколько регистров, используемых для манипулирования ее параметрами, как было сказано выше. Модуль HAL_FLASH с соответствующим модулем HAL_FLASHEx позволяют легко стирать и перепрограммировать память NVM, не слишком вдаваясь в детали их реализации. В следующих параграфах представлены наиболее важные функции из этих модулей.

21.2.1. Разблокировка Flash-памяти

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

HAL_StatusTypeDef HAL_FLASH_Unlock(void);

которая позволяет нам полностью игнорировать конкретную архитектуру Flash-памяти. Как только защита от записи/стирания во Flash-памяти отключена, мы можем выполнить операцию стирания или записи. Обратная разблокировке процедура выполняется с помощью функции:

HAL_StatusTypeDef HAL_FLASH_Lock(void);

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

21.2.2. Стирание Flash-памяти

Прежде чем мы сможем изменить содержимое ячейки Flash-памяти, нам нужно сбросить ее биты до значения по умолчанию («0» или «1» в зависимости от типа памяти NOR-Flash). Это выполняется с помощью операции стирания над разбиением из секторов/страниц (sector/page granularity). В качестве альтернативы можно выполнить массовое стирание всего банка: это означает, что на тех микроконтроллерах STM32, которые предоставляют два банка, мы можем массово стирать каждый банк за раз.

В большинстве микроконтроллеров STM32 отдельные ячейки блока Flash-памяти (сектора или страницы) устанавливаются в «1» после операции стирания, но среди них есть два заметных исключения: микроконтроллеры STM32L0 и STM32L1, в которых значение по умолчанию, напротив, «0».

FLASH_BANK_BOTH

Управление Flash-памятью

555

CubeHAL предоставляет два способа выполнения операции стирания Flash-памяти: сти-

рание в режимах опроса и прерываний.

Функция:

HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit,

uint32_t *SectorError);

позволяет выполнять стирание Flash-памяти в режиме опроса. Она принимает указатель на экземпляр структуры FLASH_EraseInitTypeDef, которую мы рассмотрим через некоторое время, и указатель на переменную SectorError, которая возвращает идентификатор неисправных секторов/страниц в случае ошибки во время процедуры стирания (например, если процедура стирания на 4-й странице не удалась, параметр SectorError будет содержать значение 3).

Структура FLASH_EraseInitTypeDef сильно отличается в каждом семействе STM32. По этой причине загляните в файл stm32XXxx_hal_flash_ex.h CubeHAL для вашего микроконтроллера. Здесь мы рассмотрим реализацию в CubeHAL для наиболее производительных микроконтроллеров STM32, таких как F2/F4/F7.

typedef struct {

 

 

 

uint32_t TypeErase;

/*

Массовое или посекторное стирание

*/

uint32_t Banks;

/*

Выбор стираемого банка при массовом стирании

*/

uint32_t Sector;

/*

Стираемый начальный сектор при посекторном стирании

*/

uint32_t NbSectors;

/*

Количество стираемых секторов

*/

uint32_t VoltageRange; /*

Диапазон напряжения устройства, который определяет

 

 

 

параллелизм стирания

*/

} FLASH_EraseInitTypeDef;

 

 

TypeErase: указывает, выполняем ли мы массовое стирание всего банка или сти-

рание сектора/страницы. Может принимать значения FLASH_TYPEERASE_SECTORS

или FLASH_TYPEERASE_MASSERASE.

Banks: доступный только в тех сериях STM32, которые обеспечивают многобанко-

вую внутреннюю Flash-память, данный параметр задает банк, участвующий в массовом стирании. Он может принимать значения FLASH_BANK_1, FLASH_BANK_2 или для стирания обоих банков.

Sector (Page): это поле ссылается на идентификатор сектора, участвующий в по-

секторном стирании. Может принимать значения FLASH_SECTOR_0, FLASH_SECTOR_1 и т. д. (максимальное количество секторов зависит от конкретного микроконтроллера). В тех микроконтроллерах STM32, которые предоставляют Flash-память с дополнительным разбиением на страницы (page granularity), эти поля заменяются первым адресом страницы, участвующей в процедуре стирания. Обратитесь к исходному коду CubeHAL за дополнительной информацией об этом.

NbSectors (NbPages): количество секторов (страниц), которые будут стерты, начиная с заданного в поле Sector сектора.

VoltageRange: несмотря на то что мы стираем целый сектор (или страницу), фак-

тически процедура стирания циклически перебирает его подмножества (обычно по два байта). Более производительные микроконтроллеры STM32 позволяют стирать несколько байт одновременно. Эта функция называется параллелизмом

Управление Flash-памятью

556

Flash-памяти (flash parallelism), и она зависит от рабочего напряжения микроконтроллера: чем выше VDD, тем больше байт стирается за раз5. Это поле может принимать значение из таблицы 3. Однако всегда обращайтесь к справочному руководству по вашему микроконтроллеру для получения дополнительной информации.

Таблица 3: Параллелизм программирования/стирания в зависимости от диапазона напряжения

VoltageRange

Диапазон напряжения

Параллелизм

 

 

 

 

 

FLASH_VOLTAGE_RANGE_1

1,7

– 2,1

В

8 бит за раз

FLASH_VOLTAGE_RANGE_2

2,1

– 2,4

В

16 бит за раз

FLASH_VOLTAGE_RANGE_3

2,4

– 3,6

В

32 бит за раз

FLASH_VOLTAGE_RANGE_4

2,7

– 3,6

В с внешним VPP

64 бит за раз

HAL_FLASHEx_Erase() является блокирующей функцией: она будет ожидать завершения процедуры стирания. Это может быть довольно «длительной» процедурой, в зависимости от семейства STM32, частоты HCLK, количества секторов/страниц, участвующих в стирании, и напряжения VDD в тех микроконтроллерах STM32, которые предоставляют параллелизм программирования/стирания. Чтобы избежать блокирования действий микропрограммы на время этой процедуры, HAL предоставляет функцию:

HAL_StatusTypeDef HAL_FLASHEx_Erase_IT(FLASH_EraseInitTypeDef *pEraseInit,

uint32_t *SectorError);

которая выполняет процедуру стирания в режиме прерываний. Мы можем получить уведомление о завершении процедуры стирания, разрешив прерывание FLASH_IRQn и реализовав соответствующую ISR.

Прочитайте внимательно

Следует проявлять особую осторожность в случае, если мы стираем область Flash-памяти, содержащую программный код, особенно если мы стираем первый сектор/страницу, содержащий таблицу векторов (это всегда верно, если мы выполняем массовое стирание). Если это так, то нам нужно переместить программный код и всю таблицу векторов в SRAM, как показано в Главе 20, в противном случае произойдет сбой после срабатывания прерывания.

21.2.3. Программирование Flash-памяти

После стирания сектора/страницы мы можем приступить к программированию его содержимого. Теоретически, вполне возможно получить доступ напрямую к ячейке Flashпамяти, чтобы изменить ее содержимое6, написав код на Си, например:

5Серия STM32L4 предоставляет аналогичную функцию, называемую режимом быстрого программирования/стирания (fast program/erase). Она зависит как от VDD, так и от тактовой частоты. Эта функция позволяет стереть/запрограммировать Flash-память с разбиением на двойные слова (double word granularity). Обратитесь к справочному руководству по вашему микроконтроллеру для получения дополнительной информации об этом.

6Очевидно, что Flash-память должна быть разблокирована, прежде чем мы сможем ее изменить.

Управление Flash-памятью

557

...

*(volatile uint16_t*)0x0800AA00 = Data;

...

Однако это в принципе не удобно по двум основным причинам. Прежде всего, в некоторых микроконтроллерах STM32 могут потребоваться предварительные операции (например, установка специальных регистров), прежде чем мы сможем запрограммировать ячейку Flash-памяти. Во-вторых, в зависимости от конкретной серии STM32 и диапазона напряжения VDD, количество байт, которые могут быть одновременно переданы во Flash-память, может значительно отличаться. По этим причинам HAL определяет функцию:

HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram,

uint32_t Address, uint64_t Data);

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

TypeProgram: указывает, сколько байт передано во время операции записи, и мо-

жет принимать значения FLASH_TYPEPROGRAM_HALFWORD, FLASH_TYPEPROGRAM_WORD и

FLASH_TYPEPROGRAM_DOUBLEWORD. Обратите внимание, что этот параметр указывает

только объем данных, передаваемых с помощью функции HAL_FLASH_Program(). Фактическое число байт, переданных в одной транзакции, зависит от семейства STM32 и степени параллелизма, если он доступен.

Address: это начальный адрес памяти, с которого начинается размещение кон-

тента.

Data: это данные, которые должны храниться в ячейке Flash-памяти (представлен-

ные в виде переменной double word).

Как и в случае описанной выше процедуры стирания, можно выполнить процедуру программирования Flash-памяти в режиме прерываний, используя функцию:

HAL_StatusTypeDef HAL_FLASH_Program_IT(uint32_t TypeProgram,

uint32_t Address, uint64_t Data);

21.2.4.Доступ к чтению Flash-памяти во время программирования и стирания

Доступ к чтению Flash-памяти во время выполнения операции стирания или записи приведет к остановке (stall) шины, по крайней мере, в большинстве микроконтроллеров STM327. Это означает, что, если вам нужно выполнять параллельно другие операции, вам необходимо переместить код в SRAM, который будет выполняться во время операции программирования Flash-памяти. Типовой сценарий представлен пользовательским загрузчиком: мы можем запрограммировать наш код так, чтобы мы заменяли новую микропрограмму во Flash-памяти, используя UART в режиме прерываний или DMA.

7 В некоторых микроконтроллерах STM32, например, в серии STM32L0, может возникнуть отказ шины, если мы попытаемся получить доступ к Flash-памяти, пока выполняется полустраничное программирование (half-page program). Для получения дополнительной информации обратитесь к справочному руководству по рассматриваемому вами микроконтроллеру.