Среда разработки STM32CubeIDE даёт пользователю интуитивно понятный интерфейс по настройке портов ввода/вывода с помощью графического компонента CubeMX. Однако, любой инструмент не идеален, и в некоторых случаях CubeIDE может вести себя неадекватно. Например, можно наткнуться на проблему с инициализацией шины I2C на МК STM32F103C6T6. А сегодня поговорим ещё об одном нетривиальном поведении.
Суть проблемы в следующем. Если настроить контакты PB3 и PB4 или PA15 для работы в любом из полезных режимов: GPIO ввод или вывод, таймер, АЦП или даже SPI, то программа соберётся без ошибок, но работать эти контакты не будут. Некоторые начинают думать, что имеет место «непропай» микросхемы, или что МК вообще сгорел (но они так не горят). Что с ними не так, чем эти контакты отличаются от других?
Дело в том, что данная группа выводов принадлежит интерфейсу отладки JTAG. Информация об этом есть в официальной инструкции к микроконтроллеру RM0008. Теоретически, при назначении этим выводам каких-то конкретных режимов, резервирование данных контактов для JTAG должно сбрасываться. Но этого не происходит. Благо, есть несколько способов, как принудить контроллер это сделать.
В этой статье использована отладочная плата типа bluepill с микроконтроллером STM32F103C8T6, а также самый простой клон программатора ST-Link V2.0. Всё это можно купить у нас в интернет-магазине:
Способ 1 — отключение JTAG через CubeMX
В наших уроках про STM32 я всегда рекомендую включать на вкладке SYS режим отладки Serial Wire. Это действие, во-первых, не даёт новичкам запутаться с перемычками на плате типа bluepill, а во-вторых — полностью отключает JTAG, освобождая от рабства контакты PB3, PB4, PA15.
Способ 2 — отключение JTAG с помощью CMSIS
Как и все прочие настройки, информация о резервировании выводов МК под различные нужды хранится в определённых регистрах. В нашем случае, виноват регистр MAPR. Вот выдержка из RM0008, которая показывает комбинации бит для разных режимов отладки.
Для этих комбинаций, в автоматически подготовленных заголовках проекта уже даже есть соответствующие константы. Нам подойдёт комбинация AFIO_MAPR_SWJ_CFG_1. Меняем содержимое регистра:
/* USER CODE BEGIN 2 */
AFIO -> MAPR |= AFIO_MAPR_SWJ_CFG_1;
/* USER CODE END 2 */
Собираем проект и загружаем программу на МК. Готово.
Не готово. Попробовал сделать так — не сработало.
А вот когда вставил еще вот это после инициализации тактирования порта
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
вот тогда сработало!