[Программирование, C++, Промышленное программирование, Программирование микроконтроллеров] Маленькие хитрости для STM32
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
В процессе работы у каждого программиста иногда встречаются неожиданные проблемы, которые возникли как будто на ровном месте. Практически по Черномырдину «никогда такого не было, и вот опять!». После этого начинаешь искать решение в интернете или закапываешься в чтение мануалов и документации, чтобы разобраться в пустячном, на первый взгляд вопросе.
Через какое-то время решение находится (или ошибка исправляется), и ты даешь себе зарок запомнить этот случай, а еще лучше записать, чтобы не забыть выясненный нюанс в будущем. Но проходит время и свое обещание счастливо забывается. И в этом нет ничего удивительного, если трудоемкость решения оказалась очень низкой, такой, что при желании его может повторить практически любой желающий буквально за несколько часов, правда если он будет знать, в какую строну следует копать.
Продолжая серию статей про маленькие хитрости разработки под STM32, хочу поделиться двумя очень простыми, но полезными функциями. Они никак не тянут на полноценный проект на github.com, но способны облегчить жизнь (или наоборот, выпить не мало крови), при определенном стечении обстоятельств.
- Буферизированный вывод отладочной информации в последовательный порт
- Автоматическое включение защиты от чтения и модификации прошивки
Буферизированный вывод в последовательный порт
При разработке устройств на микроконтроллерах для отладки их работы обычно делается вывод отладочной информации через свободный последовательный порт. В этом нет ничего сложного или заслуживающего внимания.
Но иногда бывает, что просто сам факт вывода отладочной информации может привносить в стройную работу алгоритма некую неопределенность. Обычно так случается, когда требуется отладить реакцию устройств на внешнее воздействие или реализовать взаимодействие двух устройств между собой, а вывод отладочный информации реализован в блокирующем режиме.
В этом случае, блокирующий вывод отладочной информации через низкоскоростной последовательный порт может влиять на отлаживаемый алгоритм. К счастью, из подобной ситуации есть как минимум два выхода — реализовать реакцию на внешнее воздействие в виде обработчика прерывания или сделать отладочный вывод неблокирующим.
Ниже приведена простая реализация вывода отладочной информации через последовательный порт для STM32 с реализацией на функциях HAL. Чтобы не тормозить работу потока отладочным выводом, данные сперва накапливаются в буфер и передача по DMA начинается только после получения флага flush или при заполнении буфера целиком.
Код функции
SPL
#ifdef UART_TRACE
static volatile bool dma_send = false;
static char dma_buffer[150]; // Статический буфер для вывода через DMA
static volatile size_t dma_size = 0;
// Завершение передачи по DMA
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
if (huart == &UART_TRACE) {
dma_send = false;
dma_size = 0;
}
}
// Вывод отладочной информации в UART
// str - Текстовая строка для отладочного вывода с завершающим нулевым символом
// flush - вывод накопленного буфера
void stm32_debug_trace(const char *str, bool flush) {
size_t time_start = HAL_GetTick();
// Ждать завершения предыдущей передачи в порт (если она есть)
while (dma_send) {
if ((HAL_GetTick() - time_start) > 100) { // Костыль
dma_send = false;
dma_size = 0;
HAL_UART_AbortTransmit_IT(&UART_TRACE);
break;
}
}
size_t len = strlen(str);
if (len + dma_size <= sizeof(dma_buffer)) {
// Строка влезает, просто добавим её в конец буфера
memcpy(&dma_buffer[dma_size], str, len);
dma_size += len;
len = 0;
} else {
if (dma_size > 0) {
// Остатка буфера не хватает, передаем что там уже есть в блокирующем режиме
HAL_UART_Transmit(&UART_TRACE, (uint8_t*) dma_buffer, dma_size, 0xFFFF);
dma_size = 0;
}
if (len > sizeof(dma_buffer)) {
// Если не влезает в буфер
size_t over = len - sizeof(dma_buffer);
// Передаем начало, оставляя размер буфера
HAL_UART_Transmit(&UART_TRACE, (uint8_t*) str, over, 0xFFFF);
memcpy(dma_buffer, &str[over], sizeof(dma_buffer));
dma_size = sizeof(dma_buffer);
} else {
// все влезает
memcpy(dma_buffer, str, len);
dma_size = len;
}
}
if (flush || dma_size == sizeof(dma_buffer)) {
dma_send = true;
// Передача в фоне через
HAL_UART_Transmit_DMA(&UART_TRACE, (uint8_t*) dma_buffer, dma_size);
}
}
#endif // UART_TRACE
Автоматическое включение защиты от чтения и модификации прошивки
Вторая небольшая, но крайне полезная функция. Её задача, проверить установлена ли защита прошивки от чтения, и если нет, то включить её. Всего два десятка строчек из руководства, но для их корректной работы с другим функционалом пришлось серьезно повозиться.
Мне нравятся простые и универсальные решения, а в этом случае пришлось ломать голову из-за особенностей работы разных серий микроконтроллеров.
Если у старшей версии микроконтроллеров защиту от записи и модификации прошивки ставится на каждый сектор индивидуально, то у серии STM32F1xx, один бит защиты от записи/модификации отвечает сразу за два сектора.
Второй момент, который пришлось учитывать, защита от записи во флеш память программ нужно включать не на все сектора, а только на исполняемый код и как минимум один сектор необходимо было оставить с возможностью записи.
В результате различных тестов и экспериментов пришел к конфигурации, когда защита от модификации прошивки ставится на всю память, кроме второго и третьего сектора. Они используются для хранения настроек устройства и записи посмертного core dump`a при сбое прошивки.
Код функции
SPL
void stm32_read_protection_force() {
FLASH_OBProgramInitTypeDef OBconfig;
HAL_FLASHEx_OBGetConfig(&OBconfig);
if (((OBconfig.OptionType & OPTIONBYTE_RDP) != OPTIONBYTE_RDP) || OBconfig.RDPLevel != OB_RDP_LEVEL_1) {
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
OBconfig.OptionType = OPTIONBYTE_RDP | OPTIONBYTE_WRP;
// Защита от чтения прошивки
OBconfig.RDPLevel = OB_RDP_LEVEL_1;
// Защита от случайного изменения прошивки
#ifdef FLASH_END // Для STM32F2xx и STM32F4xx
OBconfig.WRPState = OB_WRPSTATE_ENABLE;
OBconfig.WRPSector = OB_WRP_SECTOR_All;
OBconfig.WRPSector &= ~OB_WRP_SECTOR_2;
OBconfig.WRPSector &= ~OB_WRP_SECTOR_3;
#else // Для STM32F1xx
OBconfig.WRPState = OB_WRPSTATE_ENABLE;
OBconfig.WRPPage = ~OB_WRP_PAGES2TO3;
#endif
HAL_FLASHEx_OBProgram(&OBconfig);
HAL_FLASH_OB_Lock();
HAL_FLASH_Lock();
HAL_FLASH_OB_Launch(); // Перезагрузка
}
}
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, Java, Разработка мобильных приложений, Разработка под Android] Как написать простое Android ToDo-приложение на Java
- [JavaScript, Программирование, VueJS] Сделаем худший Vue.js в мире (перевод)
- [Информационная безопасность, Программирование, Разработка под Android] Уязвимости Android 2020
- [JavaScript, Программирование] Основы JavaScript: почему вы должны знать, как работает JS-движок (перевод)
- [JavaScript, Программирование] 7 вопросов про замыкания в JavaScript (перевод)
- [Программирование, C++, Алгоритмы] Ленивые операции над множествами в C++
- [Open source, Программирование, Геоинформационные сервисы, Визуализация данных, Научно-популярное] Геология XXI века: от реальности к виртуальности
- [Программирование, C++, Алгоритмы] Ленивые итераторы и диапазоны в C++
- [PHP, Программирование] Работа с заказом через админку OpenCart, взгляд изнутри
- [Программирование, GTK+, Разработка под Linux] Пишем онлайн-радио на языке Vala
Теги для поиска: #_programmirovanie (Программирование), #_c++, #_promyshlennoe_programmirovanie (Промышленное программирование), #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_stm32, #_otladka (отладка), #_mikrokontrollery (микроконтроллеры), #_otladochnyj_vyvod (отладочный вывод), #_zaschita_proshivki (защита прошивки), #_blog_kompanii_timeweb (
Блог компании Timeweb
), #_programmirovanie (
Программирование
), #_c++, #_promyshlennoe_programmirovanie (
Промышленное программирование
), #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:43
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
В процессе работы у каждого программиста иногда встречаются неожиданные проблемы, которые возникли как будто на ровном месте. Практически по Черномырдину «никогда такого не было, и вот опять!». После этого начинаешь искать решение в интернете или закапываешься в чтение мануалов и документации, чтобы разобраться в пустячном, на первый взгляд вопросе. Через какое-то время решение находится (или ошибка исправляется), и ты даешь себе зарок запомнить этот случай, а еще лучше записать, чтобы не забыть выясненный нюанс в будущем. Но проходит время и свое обещание счастливо забывается. И в этом нет ничего удивительного, если трудоемкость решения оказалась очень низкой, такой, что при желании его может повторить практически любой желающий буквально за несколько часов, правда если он будет знать, в какую строну следует копать. Продолжая серию статей про маленькие хитрости разработки под STM32, хочу поделиться двумя очень простыми, но полезными функциями. Они никак не тянут на полноценный проект на github.com, но способны облегчить жизнь (или наоборот, выпить не мало крови), при определенном стечении обстоятельств.
Буферизированный вывод в последовательный порт При разработке устройств на микроконтроллерах для отладки их работы обычно делается вывод отладочной информации через свободный последовательный порт. В этом нет ничего сложного или заслуживающего внимания. Но иногда бывает, что просто сам факт вывода отладочной информации может привносить в стройную работу алгоритма некую неопределенность. Обычно так случается, когда требуется отладить реакцию устройств на внешнее воздействие или реализовать взаимодействие двух устройств между собой, а вывод отладочный информации реализован в блокирующем режиме. В этом случае, блокирующий вывод отладочной информации через низкоскоростной последовательный порт может влиять на отлаживаемый алгоритм. К счастью, из подобной ситуации есть как минимум два выхода — реализовать реакцию на внешнее воздействие в виде обработчика прерывания или сделать отладочный вывод неблокирующим. Ниже приведена простая реализация вывода отладочной информации через последовательный порт для STM32 с реализацией на функциях HAL. Чтобы не тормозить работу потока отладочным выводом, данные сперва накапливаются в буфер и передача по DMA начинается только после получения флага flush или при заполнении буфера целиком. Код функцииSPL#ifdef UART_TRACE
static volatile bool dma_send = false; static char dma_buffer[150]; // Статический буфер для вывода через DMA static volatile size_t dma_size = 0; // Завершение передачи по DMA void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if (huart == &UART_TRACE) { dma_send = false; dma_size = 0; } } // Вывод отладочной информации в UART // str - Текстовая строка для отладочного вывода с завершающим нулевым символом // flush - вывод накопленного буфера void stm32_debug_trace(const char *str, bool flush) { size_t time_start = HAL_GetTick(); // Ждать завершения предыдущей передачи в порт (если она есть) while (dma_send) { if ((HAL_GetTick() - time_start) > 100) { // Костыль dma_send = false; dma_size = 0; HAL_UART_AbortTransmit_IT(&UART_TRACE); break; } } size_t len = strlen(str); if (len + dma_size <= sizeof(dma_buffer)) { // Строка влезает, просто добавим её в конец буфера memcpy(&dma_buffer[dma_size], str, len); dma_size += len; len = 0; } else { if (dma_size > 0) { // Остатка буфера не хватает, передаем что там уже есть в блокирующем режиме HAL_UART_Transmit(&UART_TRACE, (uint8_t*) dma_buffer, dma_size, 0xFFFF); dma_size = 0; } if (len > sizeof(dma_buffer)) { // Если не влезает в буфер size_t over = len - sizeof(dma_buffer); // Передаем начало, оставляя размер буфера HAL_UART_Transmit(&UART_TRACE, (uint8_t*) str, over, 0xFFFF); memcpy(dma_buffer, &str[over], sizeof(dma_buffer)); dma_size = sizeof(dma_buffer); } else { // все влезает memcpy(dma_buffer, str, len); dma_size = len; } } if (flush || dma_size == sizeof(dma_buffer)) { dma_send = true; // Передача в фоне через HAL_UART_Transmit_DMA(&UART_TRACE, (uint8_t*) dma_buffer, dma_size); } } #endif // UART_TRACE Автоматическое включение защиты от чтения и модификации прошивки Вторая небольшая, но крайне полезная функция. Её задача, проверить установлена ли защита прошивки от чтения, и если нет, то включить её. Всего два десятка строчек из руководства, но для их корректной работы с другим функционалом пришлось серьезно повозиться. Мне нравятся простые и универсальные решения, а в этом случае пришлось ломать голову из-за особенностей работы разных серий микроконтроллеров. Если у старшей версии микроконтроллеров защиту от записи и модификации прошивки ставится на каждый сектор индивидуально, то у серии STM32F1xx, один бит защиты от записи/модификации отвечает сразу за два сектора. Второй момент, который пришлось учитывать, защита от записи во флеш память программ нужно включать не на все сектора, а только на исполняемый код и как минимум один сектор необходимо было оставить с возможностью записи. В результате различных тестов и экспериментов пришел к конфигурации, когда защита от модификации прошивки ставится на всю память, кроме второго и третьего сектора. Они используются для хранения настроек устройства и записи посмертного core dump`a при сбое прошивки. Код функцииSPLvoid stm32_read_protection_force() {
FLASH_OBProgramInitTypeDef OBconfig; HAL_FLASHEx_OBGetConfig(&OBconfig); if (((OBconfig.OptionType & OPTIONBYTE_RDP) != OPTIONBYTE_RDP) || OBconfig.RDPLevel != OB_RDP_LEVEL_1) { HAL_FLASH_Unlock(); HAL_FLASH_OB_Unlock(); OBconfig.OptionType = OPTIONBYTE_RDP | OPTIONBYTE_WRP; // Защита от чтения прошивки OBconfig.RDPLevel = OB_RDP_LEVEL_1; // Защита от случайного изменения прошивки #ifdef FLASH_END // Для STM32F2xx и STM32F4xx OBconfig.WRPState = OB_WRPSTATE_ENABLE; OBconfig.WRPSector = OB_WRP_SECTOR_All; OBconfig.WRPSector &= ~OB_WRP_SECTOR_2; OBconfig.WRPSector &= ~OB_WRP_SECTOR_3; #else // Для STM32F1xx OBconfig.WRPState = OB_WRPSTATE_ENABLE; OBconfig.WRPPage = ~OB_WRP_PAGES2TO3; #endif HAL_FLASHEx_OBProgram(&OBconfig); HAL_FLASH_OB_Lock(); HAL_FLASH_Lock(); HAL_FLASH_OB_Launch(); // Перезагрузка } } =========== Источник: habr.com =========== Похожие новости:
Блог компании Timeweb ), #_programmirovanie ( Программирование ), #_c++, #_promyshlennoe_programmirovanie ( Промышленное программирование ), #_programmirovanie_mikrokontrollerov ( Программирование микроконтроллеров ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:43
Часовой пояс: UTC + 5