Главная » Микроконтроллеры » Загрузчик для STM32 с поддержкой SD-карты

Загрузчик для STM32 с поддержкой SD-карты

В данной статье покажем вам, как заменить содержимое Flash памяти в микроконтроллерах STM32 с использованием носителя в виде SD-карты. Для этого необходим специальный загрузчик, приведенный далее.

Загрузчик, поддерживающий передачу данных с SD-карты во флэш-память, находится в начальных областях памяти программы. Каждый раз после сброса, микроконтроллер запускает его (когда строка BOOT0 = 0, состояние линии BOOT1 не имеет значения), независимо от того, сохранена ли правильная версия пользовательской программы или нет.

Это решение дает большую гибкость, поскольку загрузчик сохраняется в памяти микроконтроллера только один раз (для этого вам необходим JTAG-программатор или вы также можете сделать это через USART1, в соответствии с рекомендациями производителя).

Рис. 1. Схема, иллюстрирующая работу загрузчика

В начале своей работы загрузчик запускается во флэш-памяти и сразу копирует себя в память SRAM, а затем запускается из нее (рис. 1), что позволяет свободно манипулировать содержимым флэш-памяти. Затем выполняется инициализация периферийных устройств, необходимых для работы загрузчика. Благодаря этому решению нет необходимости обновлять программное обеспечение во флэш-памяти после каждого сброса микроконтроллера, но мы делаем это в особых случаях:

  • Когда флэш-память не запрограммирована, это сводится к чтению первых ячеек вектора пользовательского прерывания (указателя стека и вектора сброса) и проверке, были ли они удалены случайно. Этот простой код, конечно, не может определить, является ли приложение безошибочным, но этого достаточно, чтобы определить, находится ли приложение в памяти.
  • Когда пользователь принудительно запускает загрузчик, что проверяется состоянием одной из линий микроконтроллера GPIO (определяется WakeUp_PORT и WakeUp_PIN).
  • Когда загрузчик был вызван из пользовательского приложения. Этот метод позволяет вам разместить несколько строк кода в вашей программе, которые обеспечивают вызов загрузчика.

Внутренняя поддержка Flash

Производитель внедрил в микроконтроллеры STM32 специальный драйвер Flash Program / Erase Controller (FPEC), который можно использовать для изменения содержимого флэш-памяти. В микроконтроллерах STM32 флэш-память организована в виде страниц, размер которых составляет 1 КБ или 2 КБ, в зависимости от общего объема памяти.

Флэш-память находится в адресном пространстве процессора, начиная с адреса 0x08000000. Подробное описание того, как обрабатывать флэш-память в микроконтроллерах STM32, можно найти в документе PM0042 под названием «Программирование флэш-памяти STM32F10xxx», который доступен на веб-сайте STMicroelectronics.

После сброса микроконтроллера FPEC защищает содержимое флэш-памяти от сохранения, поэтому нет возможности случайного повреждения ее содержимого. Чтобы внести какие-либо изменения, вы должны сначала разблокировать память. Это делается путем ввода двух значений в реестр Flash_KEYR:

KEY1 = 0x45670123

а затем

KEY2 = 0xCDEF89AB

С этого момента  могут выполняться операции стирания и записи памяти, пока не произойдет ошибка, которая блокирует доступ к памяти до следующей разблокировки. Алгоритм записи во флэш-память через FPEC показан на рис. 2.

Рис. 2. Алгоритм программирования флэш-памяти в микроконтроллерах STM32

Запись в память производится 2 байтами. Сначала установите бит PG в реестре Flash_CR, информируя контроллер о том, что мы будем программировать. После этого действия вы можете изменить содержимое памяти, что требует ввода 2 байтов по адресу, где они должны быть размещены в памяти. Затем дождитесь окончания этой операции и убедитесь, что запись была произведена правильно, для чего необходимо прочитать записанные 2 байта и убедиться в их правильности — это можно сделать путем сравнения. Если ошибок не нет,  то вы можете записать следующие данные таким же образом. После сохранения всей страницы вы должны удалить бит PG.

Содержимое флэш-памяти в микроконтроллерах STM32 может быть удалено двумя способами: страница за страницей или все ее содержимое. В случае загрузчика память будет удаляться постранично. Постраничный алгоритм удаления показан на рис. 3.

Рис. 3. Алгоритм стирания флэш-памяти в микроконтроллерах STM32 (постраничный)

Мы начинаем стирать содержимое памяти, устанавливая бит PER, информирующий FPEC в регистре Flash_CR о том, что страница флэш-памяти будет удалена. Затем введите адрес удаляемой страницы в регистр Flash_AR и установите бит STRT в регистр Flash_CR. В этот момент начинается физическое удаление содержимого указанной страницы памяти. На следующем этапе мы ожидаем его завершения, после чего проверяем, была ли страница удалена правильно, читая и проверяя ее содержимое.

Поддержка SD-карты

Как упоминалось ранее, процессор обменивается данными с SD-картой через интерфейс SPI. На рис. 4 показан рекомендуемый способ подключения разъема SD-карты к микроконтроллеру.

Рис. 4. Электрическая схема подключения SD-карты к микроконтроллеру

Блок-схема приложения загрузчика показана на рисунке 5. Библиотека FAT, используемая в проекте, дает возможность читать файлы с SD-карты и поддерживает длинные имена.

Рис. 5. Блок-схема приложения, выполняющего роль загрузчика

Как показано в примере 1 функция FAT_ConnectEvent присоединена к библиотеке FAT и вызывается когда на SD-карте обнаруживается раздел FAT16/32. В нем открывается корневой каталог, затем проверяется, есть ли на карте каталог \stm32f10x и файл file_name.txt.

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

Пример 1. Функция FAT_ConnectEvent

void FAT_ConnectEvent (FAT_Desc * FAT32D) {
FILE file_desc;
uint32_t result;
uint32_t address_shift = 0;
if (! sfopen (&file_desc, (const char *) FAT32D- & gt; FAT_name_string_descriptor, "r")) {
return;
}
if (! sfopen (&file_desc, "stm32f10x / file_name.txt", "r")) {
return;
}
fread (boot_read_buffer, 1, boot_page_size, &file_desc);
fclose (&file_desc);
if (! sfopen (&file_desc, (const char *) boot_read_buffer, "r")) {
return;
}
FlashUnlock ();
do {
if (FlashErasePage (DEF_APP_ADDRESS + address_shift))
{
break;
}
result = fread (boot_read_buffer, 1, boot_page_size, &file_desc);
if (FlashWritePage (DEF_APP_ADDRESS + address_shift, boot_read_buffer, result))
{
break;
}
address_shift + = boot_page_size;
} while (result == boot_page_size);
FlashLock ();
fclose (&file_desc);
}

Заключительные замечания

Загрузчик должен быть сохранен в памяти микроконтроллера так же, как и любая другая программа (с использованием интерфейса JTAG или через USART). После сохранения во флэш-памяти загрузчик сразу готов к использованию.

Чтобы использовать его для правильного запуска пользовательского приложения, вам необходимо выполнить в нем несколько операций. Во-первых, это перемещение приложения пользователя во флэш-памяти с адреса от 0x8000000 до 0x8002000, то есть на 8 КБ вверх (например, путем изменения адреса ссылки начала памяти в сценарии компоновщика). Во-вторых — удалить настройку вектора прерывания пользовательского приложения, как это делает загрузчик.

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

В прикрепляемом файле вам нужно только подключить соответствующую библиотеку ST (CMSIS), определяющую показатели структуры регистров устройств (RCC, BKP, и т. д.)

Пример 2. Пример заголовочного файла для вызова загрузчика

#ifndef BOOTLOADER_H_ \
#define BOOTLOADER_H_
// адрес таблицы векторов прерываний загрузчика
#define BOOTLOADER_VECTOR_ADDR 0x8000000
// определения, вставленные из файлов библиотеки ST
/ * --------- PWR регистрирует битовый адрес в области псевдонима ---------- * /
#define PWR_OFFSET (PWR_BASE - PERIPH_BASE)
/ * --- CR Register --- * /
/ * Псевдоним слова адреса бита DBP * /
#define CR_OFFSET (PWR_OFFSET + 0x00)
#define DBP_BitNumber 0x08
#define CR_DBP_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (DBP_BitNumber * 4))
// структура, описывающая начало стандартного вектора прерывания
typedef struct {
uint32_t SP;
void (* RESET_ISR) (void);
void (* NMIExc) (void);
void (* HardFaultExc) (void);
void (* MemManageExc) (void);
void (* BusFaultExc) (void);
void (* UsageFaultExc) (void);
void (* RESRV1) (void);
void (* RESRV2) (void);
void (* RESRV3) (void);
void (* RESRV4) (void);
void (* SVC) (void);
BOOTLOADER_CM3_ISR_TABLE};
// определение указателя на таблицу прерываний загрузчика
#define BOOTLOADER_TAB ((BOOTLOADER_CM3_ISR_TABLE *) BOOTLOADER_VECTOR_ADDR)
// макрос для вызова загрузчика путем перехода к нему
#define BOOTLOADER_CALL_BY_JUMP () (BOOTLOADER_TAB- & SVC) ()
// макрос, служащие для вызова загрузчика через запись сигнатуры
// к первому резервному регистру данных и сбросу процессора
#define BOOTLOADER_CALL_BY_RESET () {\
RCC-> APB1ENR | = RCC_APB1Periph_BKP | RCC_APB1Periph_PWR; \
RCC-> APB1RSTR & amp; = ~ ((uint32_t) (RCC_APB1Periph_BKP | RCC_APB1Periph_PWR)); \\
* (vu32 *) CR_DBP_BB = (u32) 1; \
BKP-> DR1 = 0x159D; \
SCB-> AIRCR = (SCB-> AIRCR & 0xFFFF) | (0x5FA & lt; & lt; 16) | (1 & lt; & lt; 0); \
}
#endif / * BOOTLOADER_H _ * /

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

Необходимо обсудить, что находится внутри макроса BOOTLOADER_CALL_BY_RESET. Первые две строки отвечают за включение часов для контроллера резервного копирования и его выключение, третья строка отвечает за разблокировку записи в регистры резервного копирования (она поступает из библиотеки stm32f10x_pwr).

В четвертой строке необходимо ввести значение 0x159D в первый регистр данных резервного копирования, которое загрузчик будет искать в этом реестре после сброса. Пятая строка отвечает за программный сброс микроконтроллера. Это включает установку бита VECTRESET (самый младший бит) в регистре управления прерываниями и сбросом приложения. Это один из регистров контроллера NVIC, определенных в спецификации ядра Cortex-M3. После ввода в нулевой бит 1 с одновременным вводом в биты 16 … 31 сигнатуры 0x5FA, происходит сброс микроконтроллера.

Оставить комментарий

Ваш email нигде не будет показан. Обязательные для заполнения поля помечены *

*