- •Оглавление
- •Предисловие
- •Почему я написал книгу?
- •Для кого эта книга?
- •Как использовать эту книгу?
- •Как организована книга?
- •Об авторе
- •Ошибки и предложения
- •Поддержка книги
- •Как помочь автору
- •Отказ от авторского права
- •Благодарность за участие
- •Перевод
- •Благодарности
- •I Введение
- •1. Введение в ассортимент микроконтроллеров STM32
- •1.1. Введение в процессоры на базе ARM
- •1.1.1. Cortex и процессоры на базе Cortex-M
- •1.1.1.10. Внедренные функции Cortex-M в ассортименте STM32
- •1.2. Введение в микроконтроллеры STM32
- •1.2.1. Преимущества ассортимента STM32….
- •1.2.2. ….И его недостатки
- •1.3. Краткий обзор подсемейств STM32
- •1.3.1. Серия F0
- •1.3.2. Серия F1
- •1.3.3. Серия F2
- •1.3.4. Серия F3
- •1.3.5. Серия F4
- •1.3.6. Серия F7
- •1.3.7. Серия H7
- •1.3.8. Серия L0
- •1.3.9. Серия L1
- •1.3.10. Серия L4
- •1.3.11. Серия L4+
- •1.3.12. Серия STM32WB
- •1.3.13. Как правильно выбрать для себя микроконтроллер?
- •1.4. Отладочная плата Nucleo
- •2. Установка инструментария
- •2.1. Почему выбирают Eclipse/GCC в качестве инструментария для STM32
- •2.1.1. Два слова о Eclipse…
- •2.2. Windows – Установка инструментария
- •2.2.1. Windows – Установка Eclipse
- •2.2.2. Windows – Установка плагинов Eclipse
- •2.2.3. Windows – Установка GCC ARM Embedded
- •2.2.4. Windows – Установка инструментов сборки
- •2.2.5. Windows – Установка OpenOCD
- •2.2.6. Windows – Установка инструментов ST и драйверов
- •2.3. Linux – Установка инструментария
- •2.3.2. Linux – Установка Java
- •2.3.3. Linux – Установка Eclipse
- •2.3.4. Linux – Установка плагинов Eclipse
- •2.3.5. Linux – Установка GCC ARM Embedded
- •2.3.6. Linux – Установка драйверов Nucleo
- •2.3.7. Linux – Установка OpenOCD
- •2.3.8. Linux – Установка инструментов ST
- •2.4. Mac – Установка инструментария
- •2.4.1. Mac – Установка Eclipse
- •2.4.2. Mac – Установка плагинов Eclipse
- •2.4.3. Mac – Установка GCC ARM Embedded
- •2.4.4. Mac – Установка драйверов Nucleo
- •2.4.5. Mac – Установка OpenOCD
- •2.4.6. Mac – Установка инструментов ST
- •3. Hello, Nucleo!
- •3.1. Прикоснитесь к Eclipse IDE
- •3.2. Создание проекта
- •3.3. Подключение Nucleo к ПК
- •3.5. Изучение сгенерированного кода
- •4. Инструмент STM32CubeMX
- •4.1. Введение в инструмент CubeMX
- •4.1.1. Представление Pinout
- •4.1.2. Представление Clock Configuration
- •4.1.3. Представление Configuration
- •4.1.4. Представление Power Consumption Calculator
- •4.2. Генерация проекта
- •4.2.1. Генерация проекта Си при помощи CubeMX
- •4.2.2. Создание проекта Eclipse
- •4.2.3. Ручное импортирование сгенерированных файлов в проект Eclipse
- •4.3. Изучение сгенерированного кода приложения
- •4.3.1. Добавим что-нибудь полезное в микропрограмму
- •4.4. Загрузка исходного кода примеров книги
- •5. Введение в отладку
- •5.1. Начало работы с OpenOCD
- •5.1.1. Запуск OpenOCD
- •5.1.2. Подключение к OpenOCD Telnet Console
- •5.1.3. Настройка Eclipse
- •5.1.4. Отладка в Eclipse
- •5.2. Полухостинг ARM
- •5.2.1. Включение полухостинга в новом проекте
- •5.2.2. Включение полуохостинга в существующем проекте
- •5.2.3. Недостатки полухостинга
- •5.2.4. Как работает полухостинг
- •II Погружение в HAL
- •6. Управление GPIO
- •6.2. Конфигурация GPIO
- •6.2.1. Режимы работы GPIO
- •6.2.2. Режим альтернативной функции GPIO
- •6.2.3. Понятие скорости GPIO
- •6.3. Управление GPIO
- •6.4. Деинициализация GPIO
- •7. Обработка прерываний
- •7.1. Контроллер NVIC
- •7.1.1. Таблица векторов в STM32
- •7.2. Разрешение прерываний
- •7.2.1. Линии запроса внешних прерываний и контроллер NVIC
- •7.2.2. Разрешение прерываний в CubeMX
- •7.3. Жизненный цикл прерываний
- •7.4. Уровни приоритета прерываний
- •7.4.1. Cortex-M0/0+
- •7.4.2. Cortex-M3/4/7
- •7.4.3. Установка уровня прерываний в CubeMX
- •7.5. Реентерабельность прерываний
- •8. Универсальные асинхронные последовательные средства связи
- •8.1. Введение в UART и USART
- •8.2. Инициализация UART
- •8.3. UART-связь в режиме опроса
- •8.3.1. Установка консоли последовательного порта в Windows
- •8.3.2. Установка консоли последовательного порта в Linux и MacOS X
- •8.4. UART-связь в режиме прерываний
- •8.5. Обработка ошибок
- •8.6. Перенаправление ввода-вывода
- •9. Управление DMA
- •9.1. Введение в DMA
- •9.1.1. Необходимость DMA и роль внутренних шин
- •9.1.2. Контроллер DMA
- •9.2. Модуль HAL_DMA
- •9.2.1. DMA_HandleTypeDef в HAL для F0/F1/F3/L0/L1/L4
- •9.2.2. DMA_HandleTypeDef в HAL для F2/F4/F7
- •9.2.3. DMA_HandleTypeDef в HAL для L0/L4
- •9.2.4. Как выполнять передачи в режиме опроса
- •9.2.5. Как выполнять передачи в режиме прерываний
- •9.2.8. Разнообразные функции модулей HAL_DMA и HAL_DMA_Ex
- •9.3. Использование CubeMX для конфигурации запросов к DMA
- •10. Схема тактирования
- •10.1. Распределение тактового сигнала
- •10.1.1. Обзор схемы тактирования STM32
- •10.1.1.1. Многочастотный внутренний RC-генератор в семействах STM32L
- •10.1.3.1. Подача тактового сигнала от высокочастотного генератора
- •10.1.3.2. Подача тактового сигнала от 32кГц генератора
- •10.2. Обзор модуля HAL_RCC
- •10.2.1. Вычисление тактовой частоты во время выполнения
- •10.2.2. Разрешение Выхода синхронизации
- •10.2.3. Разрешение Системы защиты тактирования
- •10.3. Калибровка HSI-генератора
- •11. Таймеры
- •11.1. Введение в таймеры
- •11.1.1. Категории таймеров в микроконтроллере STM32
- •11.1.2. Доступность таймеров в ассортименте STM32
- •11.2. Базовые таймеры
- •11.2.1. Использование таймеров в режиме прерываний
- •11.2.2. Использование таймеров в режиме опроса
- •11.2.3. Использование таймеров в режиме DMA
- •11.2.4. Остановка таймера
- •11.3. Таймеры общего назначения
- •11.3.1.1. Режим внешнего тактирования 2
- •11.3.1.2. Режим внешнего тактирования 1
- •11.3.2. Режимы синхронизации ведущего/ведомого таймеров
- •11.3.2.1. Разрешение прерываний, относящихся к триггерной цепи
- •11.3.2.2. Использование CubeMX для конфигурации синхронизации ведущего/ведомого устройств
- •11.3.3. Программная генерация связанных с таймером событий
- •11.3.4. Режимы отсчета
- •11.3.5. Режим захвата входного сигнала
- •11.3.5.1. Использование CubeMX для конфигурации режима захвата входного сигнала
- •11.3.6. Режим сравнения выходного сигнала
- •11.3.6.1. Использование CubeMX для конфигурации режима сравнения выходного сигнала
- •11.3.7. Генерация широтно-импульсного сигнала
- •11.3.7.1. Генерация синусоидального сигнала при помощи ШИМ
- •11.3.7.2. Использование CubeMX для конфигурации режима ШИМ
- •11.3.8. Одноимпульсный режим
- •11.3.8.1. Использование CubeMX для конфигурации одноимпульсного режима
- •11.3.9. Режим энкодера
- •11.3.9.1. Использование CubeMX для конфигурации режима энкодера
- •11.3.10.1. Режим датчика Холла
- •11.3.10.2. Комбинированный режим трехфазной ШИМ и другие функции управления двигателем
- •11.3.10.3. Вход сброса таймера и блокировка регистров таймера
- •11.3.10.4. Предварительная загрузка регистра автоперезагрузки
- •11.3.11. Отладка и таймеры
- •11.4. Системный таймер SysTick
- •12. Аналого-цифровое преобразование
- •12.1. Введение в АЦП последовательного приближения
- •12.2. Модуль HAL_ADC
- •12.2.1. Режимы преобразования
- •12.2.1.1. Режим однократного преобразования одного канала
- •12.2.1.2. Режим сканирования с однократным преобразованием
- •12.2.1.3. Режим непрерывного преобразования одного канала
- •12.2.1.4. Режим сканирования с непрерывным преобразованием
- •12.2.1.5. Режим преобразования инжектированных каналов
- •12.2.1.6. Парный режим
- •12.2.2. Выбор канала
- •12.2.3. Разрядность АЦП и скорость преобразования
- •12.2.4. Аналого-цифровые преобразования в режиме опроса
- •12.2.6. Аналого-цифровые преобразования в режиме DMA
- •12.2.6.1. Многократное преобразование одного канала в режиме DMA
- •12.2.6.3. Непрерывные преобразования в режиме DMA
- •12.2.7. Обработка ошибок
- •12.2.8. Преобразования, управляемые таймером
- •12.2.9. Преобразования, управляемые внешними событиями
- •12.2.10. Калибровка АЦП
- •12.3. Использование CubeMX для конфигурации АЦП
- •13.1. Введение в периферийное устройство ЦАП
- •13.2. Модуль HAL_DAC
- •13.2.1. Управление ЦАП вручную
- •13.2.2. Управление ЦАП в режиме DMA с использованием таймера
- •13.2.3. Генерация треугольного сигнала
- •13.2.4. Генерация шумового сигнала
- •14.1. Введение в спецификацию I²C
- •14.1.1. Протокол I²C
- •14.1.1.1. START- и STOP-условия
- •14.1.1.2. Формат байта
- •14.1.1.3. Кадр адреса
- •14.1.1.4. Биты «Подтверждено» (ACK) и «Не подтверждено» (NACK)
- •14.1.1.5. Кадры данных
- •14.1.1.6. Комбинированные транзакции
- •14.1.1.7. Удержание синхросигнала
- •14.1.2. Наличие периферийных устройств I²C в микроконтроллерах STM32
- •14.2. Модуль HAL_I2C
- •14.2.1.1. Операции I/O MEM
- •14.2.1.2. Комбинированные транзакции
- •14.3. Использование CubeMX для конфигурации периферийного устройства I²C
- •15.1. Введение в спецификацию SPI
- •15.1.1. Полярность и фаза тактового сигнала
- •15.1.2. Управление сигналом Slave Select
- •15.1.3. Режим TI периферийного устройства SPI
- •15.1.4. Наличие периферийных устройств SPI в микроконтроллерах STM32
- •15.2. Модуль HAL_SPI
- •15.2.1. Обмен сообщениями с использованием периферийного устройства SPI
- •15.2.2. Максимальная частота передачи, достижимая при использовании CubeHAL
- •15.3. Использование CubeMX для конфигурации периферийного устройства SPI
- •16. Циклический контроль избыточности
- •16.1. Введение в расчет CRC
- •16.1.1. Расчет CRC в микроконтроллерах STM32F1/F2/F4/L1
- •16.2. Модуль HAL_CRC
- •17. Независимый и оконный сторожевые таймеры
- •17.1. Независимый сторожевой таймер
- •17.1.1. Использование CubeHAL для программирования таймера IWDG
- •17.2. Системный оконный сторожевой таймер
- •17.2.1. Использование CubeHAL для программирования таймера WWDG
- •17.3. Отслеживание системного сброса, вызванного сторожевым таймером
- •17.4. Заморозка сторожевых таймеров во время сеанса отладки
- •17.5. Выбор сторожевого таймера, подходящего для вашего приложения
- •18. Часы реального времени
- •18.1. Введение в периферийное устройство RTC
- •18.2. Модуль HAL_RTC
- •18.2.1. Установка и получение текущей даты/времени
- •18.2.1.1. Правильный способ чтения значений даты/времени
- •18.2.2. Конфигурирование будильников
- •18.2.3. Блок периодического пробуждения
- •18.2.5. Калибровка RTC
- •18.2.5.1. Грубая калибровка RTC
- •18.2.5.2. Тонкая калибровка RTC
- •18.2.5.3. Обнаружение опорного тактового сигнала
- •18.3. Использование резервной SRAM
- •III Дополнительные темы
- •19. Управление питанием
- •19.1. Управление питанием в микроконтроллерах на базе Cortex-M
- •19.2. Как микроконтроллеры Cortex-M управляют рабочим и спящим режимами
- •19.2.1. Переход в/выход из спящих режимов
- •19.2.1.1. «Спящий режим по выходу»
- •19.3. Управление питанием в микроконтроллерах STM32F
- •19.3.1. Источники питания
- •19.3.2. Режимы питания
- •19.3.2.1. Рабочий режим
- •19.3.2.2. Спящий режим
- •19.3.2.3. Режим останова
- •19.3.2.4. Режим ожидания
- •19.3.2.5. Пример работы в режимах пониженного энергопотребления
- •19.4. Управление питанием в микроконтроллерах STM32L
- •19.4.1. Источники питания
- •19.4.2. Режимы питания
- •19.4.2.1. Рабочие режимы
- •19.4.2.2. Спящие режимы
- •19.4.2.2.1. Режим пакетного сбора данных
- •19.4.2.3. Режимы останова
- •19.4.2.4. Режимы ожидания
- •19.4.2.5. Режим выключенного состояния
- •19.4.3. Переходы между режимами питания
- •19.4.4. Периферийные устройства с пониженным энергопотреблением
- •19.4.4.1. LPUART
- •19.4.4.2. LPTIM
- •19.5. Инспекторы источников питания
- •19.6. Отладка в режимах пониженного энергопотребления
- •19.7. Использование калькулятора энергопотребления CubeMX
- •20. Организация памяти
- •20.1. Модель организации памяти в STM32
- •20.1.1. Основы процессов компиляции и компоновки
- •20.2.1. Исследование бинарного ELF-файла
- •20.2.2. Инициализация секций .data и .bss
- •20.2.2.1. Пара слов о секции COMMON
- •20.2.3. Секция .rodata
- •20.2.4. Области Стека и Кучи
- •20.2.5. Проверка размера Кучи и Стека на этапе компиляции
- •20.2.6. Различия с файлами скриптов инструментария
- •20.3. Как использовать CCM-память
- •20.3.1. Перемещение таблицы векторов в CCM-память
- •20.4.1. Программирование MPU с использованием CubeHAL
- •21. Управление Flash-памятью
- •21.1. Введение во Flash-память STM32
- •21.2. Модуль HAL_FLASH
- •21.2.1. Разблокировка Flash-памяти
- •21.2.2. Стирание Flash-памяти
- •21.2.3. Программирование Flash-памяти
- •21.3. Байты конфигурации
- •21.3.1. Защита от чтения Flash-памяти
- •21.4. Дополнительные памяти OTP и EEPROM
- •21.5. Задержка чтения Flash-памяти и ускоритель ART™ Accelerator
- •21.5.1. Роль TCM-памятей в микроконтроллерах STM32F7
- •22. Процесс начальной загрузки
- •22.1.1. Программное физическое перераспределение памяти
- •22.1.2. Перемещение таблицы векторов
- •22.1.3. Запуск микропрограммы из SRAM с помощью инструментария GNU MCU Eclipse
- •22.2. Встроенный загрузчик
- •22.2.1. Запуск загрузчика из встроенного программного обеспечения
- •22.2.2. Последовательность начальной загрузки в инструментарии GNU MCU Eclipse
- •22.3. Разработка пользовательского загрузчика
- •22.3.2. Как использовать инструмент flasher.py
- •23. Запуск FreeRTOS
- •23.1. Введение в концепции, лежащие в основе ОСРВ
- •23.2.1. Структура файлов с исходным кодом FreeRTOS
- •23.2.1.2. Как импортировать FreeRTOS с использованием CubeMX и CubeMXImporter
- •23.3. Управление потоками
- •23.3.1. Состояния потоков
- •23.3.2. Приоритеты потоков и алгоритмы планирования
- •23.3.3. Добровольное освобождение от управления
- •23.3.4. Холостой поток idle
- •23.4. Выделение памяти и управление ею
- •23.4.1. Модель динамического выделения памяти
- •23.4.1.1. heap_1.c
- •23.4.1.2. heap_2.c
- •23.4.1.3. heap_3.c
- •23.4.1.4. heap_4.c
- •23.4.1.5. heap_5.c
- •23.4.2. Модель статического выделения памяти
- •23.4.3. Пулы памяти
- •23.4.4. Обнаружение переполнения стека
- •23.5. Примитивы синхронизации
- •23.5.1. Очереди сообщений
- •23.5.2. Cемафоры
- •23.5.3. Сигналы потоков
- •23.6. Управление ресурсами и взаимное исключение
- •23.6.1. Мьютексы
- •23.6.2. Критические секции
- •23.6.3. Обработка прерываний совместно с ОСРВ
- •23.7. Программные таймеры
- •23.7.1. Как FreeRTOS управляет таймерами
- •23.8. Пример из практики: Управление энергосбережением с ОСРВ
- •23.8.1. Перехват холостого потока idle
- •23.8.2. Бестиковый режим во FreeRTOS
- •23.9. Возможности отладки
- •23.9.1. Макрос configASSERT()
- •23.9.2. Статистика среды выполнения и информация о состоянии потоков
- •23.10. Альтернативы FreeRTOS
- •23.10.1. ChibiOS
- •23.10.2. ОС Contiki
- •23.10.3. OpenRTOS
- •24. Продвинутые методы отладки
- •24.1. Введение в исключения отказов Cortex-M
- •24.1.1.1. Как инструментарий GNU MCU Eclipse обрабатывает исключения отказов
- •24.1.1.2. Как интерпретировать содержимое регистра LR при переходе в исключение
- •24.1.2. Исключения отказов и их анализ
- •24.2.1. Представление Expressions
- •24.2.1.1. Мониторы памяти
- •24.2.2. Точки наблюдения
- •24.2.3. Режим Instruction Stepping Mode
- •24.2.4. Keil Packs и представление Peripheral Registers
- •24.2.5. Представление Core Registers
- •24.3. Средства отладки от CubeHAL
- •24.4. Внешние отладчики
- •24.4.1. Использование SEGGER J-Link для отладчика ST-LINK
- •24.4.2. Использование интерфейса ITM и трассировка SWV
- •24.5. STM Studio
- •24.6. Одновременная отладка двух плат Nucleo
- •25. Файловая система FAT
- •25.1. Введение в библиотеку FatFs
- •25.1.1. Использование CubeMX для включения в ваши проекты библиотеки FatFs
- •25.1.2. Наиболее важные структуры и функции FatFs
- •25.1.2.1. Монтирование файловой системы
- •25.1.2.2. Открытие файлов
- •25.1.2.3. Чтение и запись файла
- •25.1.2.4. Создание и открытие каталога
- •25.1.3. Как сконфигурировать библиотеку FatFs
- •26. Разработка IoT-приложений
- •26.2. Ethernet контроллер W5500
- •26.2.1. Как использовать шилд W5500 и модуль ioLibrary_Driver
- •26.2.1.1. Конфигурирование интерфейса SPI
- •26.2.1.2. Настройка буферов сокетов и сетевого интерфейса
- •26.2.2. API-интерфейсы сокетов
- •26.2.2.1. Управление сокетами в режиме TCP
- •26.2.2.2. Управление сокетами в режиме UDP
- •26.2.3. Перенаправление ввода-вывода на сокет TCP/IP
- •26.2.4. Настройка HTTP-сервера
- •26.2.4.1. Веб-осциллограф
- •27. Начало работы над новым проектом
- •27.1. Проектирование оборудования
- •27.1.1. Послойная разводка печатной платы
- •27.1.2. Корпус микроконтроллера
- •27.1.3. Развязка выводов питания
- •27.1.4. Тактирование
- •27.1.5. Фильтрация вывода сброса RESET
- •27.1.6. Отладочный порт
- •27.1.7. Режим начальной загрузки
- •27.1.8. Обратите внимание на совместимость с выводами…
- •27.1.9. …и на выбор подходящей периферии
- •27.1.10. Роль CubeMX на этапе проектирования платы
- •27.1.11. Стратегии разводки платы
- •27.2. Разработка программного обеспечения
- •27.2.1. Генерация бинарного образа для производства
- •Приложение
- •Принудительный сброс микроконтроллера из микропрограммы
- •B. Руководство по поиску и устранению неисправностей
- •Проблемы с установкой GNU MCU Eclipse
- •Проблемы, связанные с Eclipse
- •Eclipse не может найти компилятор
- •Eclipse постоянно прерывается при выполнении каждой инструкции во время сеанса отладки
- •Пошаговая отладка очень медленная
- •Микропрограмма работает только в режиме отладки
- •Проблемы, связанные с STM32
- •Микроконтроллер не загружается корректно
- •Невозможно загрузить микропрограмму или отладить микроконтроллер
- •C. Схема выводов Nucleo
- •Nucleo-F446RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F411RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F410RB
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F401RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F334R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F303RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F302R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F103RB
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F091RC
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F072RB
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F070RB
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-F030R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-L476RG
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-L152RE
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-L073R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •Nucleo-L053R8
- •Разъемы, совместимые с Arduino
- •Morpho-разъемы
- •D. Корпусы STM32
- •LFBGA
- •LQFP
- •TFBGA
- •TSSOP
- •UFQFPN
- •UFBGA
- •VFQFP
- •WLCSP
- •E. Изменения книги
- •Выпуск 0.1 – Октябрь 2015
- •Выпуск 0.2 – 28 октября 2015
- •Выпуск 0.2.1 – 31 октября 2015
- •Выпуск 0.2.2 – 1 ноября 2015
- •Выпуск 0.3 – 12 ноября 2015
- •Выпуск 0.4 – 4 декабря 2015
- •Выпуск 0.5 – 19 декабря 2015
- •Выпуск 0.6 – 18 января 2016
- •Выпуск 0.6.1 – 20 января 2016
- •Выпуск 0.6.2 – 30 января 2016
- •Выпуск 0.7 – 8 февраля 2016
- •Выпуск 0.8 – 18 февраля 2016
- •Выпуск 0.8.1 – 23 февраля 2016
- •Выпуск 0.9 – 27 марта 2016
- •Выпуск 0.9.1 – 28 марта 2016
- •Выпуск 0.10 – 26 апреля 2016
- •Выпуск 0.11 – 27 мая 2016
- •Выпуск 0.11.1 – 3 июня 2016
- •Выпуск 0.11.2 – 24 июня 2016
- •Выпуск 0.12 – 4 июля 2016
- •Выпуск 0.13 – 18 июля 2016
- •Выпуск 0.14 – 12 августа 2016
- •Выпуск 0.15 – 13 сентября 2016
- •Выпуск 0.16 – 3 октября 2016
- •Выпуск 0.17 – 24 октября 2016
- •Выпуск 0.18 – 15 ноября 2016
- •Выпуск 0.19 – 29 ноября 2016
- •Выпуск 0.20 – 28 декабря 2016
- •Выпуск 0.21 – 29 января 2017
- •Выпуск 0.22 – 2 мая 2017
- •Выпуск 0.23 – 20 июля 2017
- •Выпуск 0.24 – 11 декабря 2017
- •Выпуск 0.25 – 3 января 2018
- •Выпуск 0.26 – 7 мая 2018
Управление питанием |
491 |
заключается в увеличении частоты ядра с помощью своего рода «разгона». Рекомендуется переходить в режим высокоинтенсивной работы, когда приложение не выполняет критические задачи и когда источником системного тактового сигнала является HSIили HSE-генератор. Эти функции полезны, когда мы хотим временно увеличить/уменьшить тактовую частоту микроконтроллера без перенастройки схемы тактирования, что обычно приводит к незначительным накладным расходам. HAL предоставляет две удоб-
ные функции, HAL_PWREx_EnableOverDrive() и HAL_PWREx_DisableOverDrive() для выполне-
ния этой операции.
Режим малоинтенсивной работы противоположен режиму высокоинтенсивной работы и
заключается в понижении частоты ЦПУ и отключении некоторых периферийных устройств. В этом режиме можно перевести внутренний регулятор напряжения в режим пониженного энергопотребления. В некоторых микроконтроллерах STM32F4/F7 режим
малоинтенсивной работы доступен даже в режиме останова.
19.3.2.2. Спящий режим
Перейти в спящий режим (sleep mode) можно с помощью выполнения инструкции WFI или WFE. В спящем режиме все выводы I/O сохраняют то же состояние, что и в рабочем режиме. Однако нам не следует заботиться об ассемблерных инструкциях, поскольку CubeHAL предоставляет функцию:
void HAL_PWR_EnterSLEEPMode(uint32_t Regulator, uint8_t SLEEPEntry);
Первый параметр, Regulator, не имеет смысла в спящем режиме для всей серии STM32F и оставлен для совместимости с серией STM32L. Второй параметр, SLEEPEntry, может принимать значения PWR_SLEEPENTRY_WFI или PWR_SLEEPENTRY_WFE: как следует из названий, первый выполняет инструкцию WFI, а второй – WFE.
Если вы посмотрите на функцию HAL_PWR_EnterSLEEPMode(), то обнаружите, что, если мы передадим параметр PWR_SLEEPENTRY_WFE, он последовательно выполнит две инструкции WFE. Это приводит к тому, что HAL_PWR_EnterSLEEPMode() переходит в спящий режим таким же образом, как она вызывается с параметром PWR_SLEEPENTRY_WFI (двойной вызов WFE приводит к тому, что если установлен регистр событий, то он сбрасывается первой инструкцией WFE, а второй переводит микроконтроллер в спящий режим). Я не знаю, почему ST приняла этот подход. Если вы хотите получить полный контроль над тем, как микроконтроллер переводится в режимы пониженного энергопотребления, вам придется изменить содержимое этой функции по своему усмотрению. Ясно, что микроконтроллер выйдет из спящего режима после выполнения условия выхода инструкции WFE.
Если для перехода в спящий режим используется инструкция WFI, то любое прерывание от периферийного устройства, подтвержденное контроллером вложенных векторных прерываний (NVIC), может пробудить устройство из спящего режима.
Если для перехода в спящий режим используется инструкция WFE, то микроконтроллер выходит из спящего режима, как только происходит событие. Событие пробуждения может быть сгенерировано в следующих случаях:
Управление питанием |
492 |
•разрешение прерывания в регистре управления периферийным устройством, но не в NVIC, и установка бита SEVONPEND в регистре управления системой – Когда микроконтроллер возобновляет работу из WFE, бит отложенного состояния (pending bit) периферийного прерывания и бит отложенного состояния периферийного канала IRQ контроллера NVIC (в регистре NVIC сброса прерываний) должны быть сброшены;
•или конфигурирование внешней или внутренней линии EXTI в режиме события (event mode) – Когда ЦПУ возобновляет работу из WFE, нет необходимости сбрасывать бит отложенного состояния периферийного прерывания или бит отложенного состояния канала IRQ контроллера NVIC, так как бит отложенного состояния, соответствующий линии события не установлен.
Данный режим предлагает самое низкое время пробуждения, поскольку не тратится время на вход/выход из прерывания.
19.3.2.3. Режим останова
Режим останова (stop mode) основан на режиме глубокого сна Cortex-M в сочетании с запретом тактирования периферии. В режиме останова все тактирование в домене питания 1,8 В остановлено, а блок PLL и HSI- и HSE-генераторы отключены. SRAM и содержимое регистров сохраняются. В режиме останова все выводы I/O сохраняют то же состояние, что и в рабочем режиме. Регулятор напряжения может быть сконфигурирован как в нормальном режиме работы, так и в режиме пониженного энергопотребления. Для перевода микроконтроллера в режим останова HAL предоставляет функцию:
HAL_PWR_EnterSTOPMode(uint32_t Regulator, uint8_t STOPEntry);
где параметр Regulator принимает значение PWR_MAINREGULATOR_ON для того, чтобы оставить внутренний регулятор напряжения включенным, или значение PWR_LOWPOWERREGULATOR_ON для того, чтобы перевести его в режим пониженного энергопотребления. Пара-
метр STOPEntry может принимать значения PWR_STOPENTRY_WFI или PWR_STOPENTRY_WFE.
Для перехода в режим останова, все биты отложенного состояния линий EXTI, все биты отложенного состояния прерываний периферийных устройств и флаг будильника RTC Alarm должны быть сброшены. В противном случае процедура перехода в режим останова игнорируется, и выполнение программы продолжается. Если приложению необходимо отключить внешний высокочастотный генератор (HSE) перед переходом в режим останова, сначала должен быть переключен источник системного тактового сигнала на HSI-генератор, а затем сброшен бит HSEON. В противном случае, если перед переходом в режим останова бит HSEON остается равным 1, необходимо включить функцию системы защиты тактирования (CSS) для обнаружения любого отказа внешнего генератора (внешнего тактового сигнала) и избежать сбоя при переходе в режим останова.
Любая линия EXTI, сконфигурированная в режиме прерываний или событий, вынуждает ЦПУ выйти из режима останова, если оно перешло в режим пониженного энергопотребления при помощи инструкции WFI или WFE. Поскольку и HSE-генератор, и блок PLL отключаются перед переходом в режим останова, при выходе из этого режима источником тактового сигнала микроконтроллера устанавливается HSI-генератор. Это означает, что наш код должен переконфигурировать схему тактирования в соответствии с желаемым тактовым сигналом SYSCLK.
Управление питанием |
493 |
19.3.2.4. Режим ожидания
Режим ожидания (standby mode) позволяет достичь минимального энергопотребления. Он основан на режиме глубокого сна Cortex-M с отключенным регулятором напряжения. Следовательно, отключается домен питания 1,8-1,2 В. Также отключаются мультиплексор блока PLL, HSI- и HSE-генераторы. Содержимое SRAM и регистров теряется, за исключением регистров цепи автономной работы (standby circuitry). Для перевода микроконтроллера в режим ожидания HAL предоставляет функцию:
void HAL_PWR_EnterSTANDBYMode(void);
Микроконтроллер выходит из режима ожидания при возникновении внешнего сброса (вывод NRST), сброса от IWDG, нарастающего фронта на одном из разрешенных выводов WKUPx или от события RTC. Все регистры сбрасываются после выхода из режима
ожидания, за исключением регистра управления/состояния питания (PWR->CSR). После вы-
хода из режима ожидания выполнение программы возобновляется так же, как и после сброса (выборка вывода начальной загрузки, загрузка байтов конфигурации, выбор вектора сброса и т. д.). Используя макрос:
__HAL_PWR_GET_FLAG(PWR_FLAG_SB);
мы можем проверить, сбрасывается ли микроконтроллер при выходе из режима ожидания. Поскольку и HSE-генератор, и блок PLL отключаются перед переходом в режим ожидания, при выходе из этого режима источником тактового сигнала микроконтроллера установлен HSI-генератор. Это означает, что наш код должен переконфигурировать схему тактирования в соответствии с желаемым тактовым сигналом SYSCLK.
Прочитайте внимательно
Некоторые микроконтроллеры STM32 имеют аппаратную ошибку, которая не позволяет перейти или выйти из режима ожидания. Должны быть выполнены особые условия, прежде чем мы перейдем в этот режим. Обратитесь к перечню аппаратных ошибок (errata sheet) вашего микроконтроллера для получения дополнительной информации об этом.
19.3.2.5. Пример работы в режимах пониженного энергопотребления
В следующем примере, предназначенном для работы на Nucleo-F030R815, показано, как работают режимы пониженного энергопотребления.
Имя файла: src/main-ex1.c
14int main(void) {
15char msg[20];
17HAL_Init();
18Nucleo_BSP_Init();
20/* Прежде чем мы сможем получить доступ к каждому регистру PWR, мы должны включить его */
15 Для других плат Nucleo обратитесь к примерам книги.
Управление питанием |
494 |
21 __HAL_RCC_PWR_CLK_ENABLE(); 22
23while (1) {
24if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB)) {
25/* Если установлен флаг режима ожидания в PWR->CSR, то генерируется сброс
26* при выходе из режима ожидания (STANDBY) */
27sprintf(msg, "RESET after STANDBY mode\r\n");
28HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
29/* Мы должны явно сбросить флаг */
30__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU|PWR_FLAG_SB);
31}
32
33sprintf(msg, "MCU in run mode\r\n");
34HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
35while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET) {
36HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
37HAL_Delay(100);
38}
39
40 HAL_Delay(200);
41
42sprintf(msg, "Entering in SLEEP mode\r\n");
43HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
44
45 SleepMode();
46
47sprintf(msg, "Exiting from SLEEP mode\r\n");
48HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
49
50while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET);
51HAL_Delay(200);
52
53sprintf(msg, "Entering in STOP mode\r\n");
54HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
55
56 StopMode();
57
58sprintf(msg, "Exiting from STOP mode\r\n");
59HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
60
61while(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET);
62HAL_Delay(200);
63
64sprintf(msg, "Entering in STANDBY mode\r\n");
65HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
66
67 StandbyMode();
68
69while(1); // Сюда никогда не придем, так как МК сбрасывается при выходе из STANDBY
70}
Управление питанием |
495 |
71 }
72
73
74void SleepMode(void)
75{
76GPIO_InitTypeDef GPIO_InitStruct;
78/* Отключение всех GPIO для уменьшения энергопотребления */
79 MX_GPIO_Deinit();
80
81/* Конфигурация пользовательской кнопки в качестве генератора внешнего прерывания */
82__HAL_RCC_GPIOC_CLK_ENABLE();
83GPIO_InitStruct.Pin = B1_Pin;
84GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
85GPIO_InitStruct.Pull = GPIO_NOPULL;
86HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);
87
88 HAL_UART_DeInit(&huart2);
89
90/* Приостановить отсчет тиков для предотвращения пробуждения по прерыванию от Systick.
91В противном случае прерывание от Systick пробудит устройство через 1 мс. */
92HAL_SuspendTick();
93
94__HAL_RCC_PWR_CLK_ENABLE();
95/* Запрос на переход в спящий режим (SLEEP) */
96HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFI);
98/* Возобновление отсчета тиков, если он был приостановлен до перехода в спящий режим */
99 HAL_ResumeTick();
100
101/* Переинициализация выводов GPIO */
102MX_GPIO_Init();
103
104/* Переинициализация UART2 */
105MX_USART2_UART_Init();
106}
Макрос __HAL_RCC_PWR_CLK_ENABLE() в строке 21 включает периферийное устройство PWR: прежде чем мы сможем выполнить какую-либо операцию, связанную с управлением питанием, нам необходимо включить периферийное устройство PWR, даже если мы просто проверяем, установлен ли флаг режима ожидания в регистре PWR->CSR. Это источник причинения уймы головной боли у начинающих пользователей, борющихся с управлением питанием.
Строки [24:31] проверяют, установлен ли флаг режима ожидания: если это так, то это означает, что микроконтроллер был сброшен после выхода из режима ожидания. Строки [33:38] представляют собой рабочий режим: светодиод LD2 мигает, пока мы не нажмем пользовательскую кнопку платы Nucleo, подключенную к выводу PC13. Оставшиеся строки кода в main() просто переключаются между тремя режимами пониженного энергопотребления при каждом нажатии пользовательской кнопки.
Управление питанием |
496 |
Строки [74:106] определяют функцию SleepMode(), используемую для перевода микроконтроллера в спящий режим. Все GPIO сконфигурированы как аналоговые, чтобы уменьшить потребление тока на неиспользуемых I/O (особенно те выводы, которые могут быть источником утечек). Соответствующие им периферийные тактовые сигналы отключены, за исключением периферийного устройства GPIOC: вывод PC13 используется для выхода из режимов пониженного энергопотребления. То же самое относится к интерфейсу UART2 и таймеру SysTick, который останавливается для предотвращения выхода микроконтроллера из режима пониженного энергопотребления через 1 мс. Вызов функции HAL_PWR_EnterSLEEPMode() в строке 96 переводит микроконтроллер в спящий режим, пока он не пробудится при нажатии пользовательской кнопки USER (микроконтроллер пробуждается, потому что мы конфигурируем соответствующий IRQ, который вызывает условие выхода инструкции WFI из режима пониженного энергопотребления). Функция StopMode(), не показанная здесь, практически идентична функции SleepMode(), за исключением того факта, что она вызывает функцию HAL_PWR_EnterSTOPMode() для перевода микроконтроллера в режим останова.
Имя файла: src/main-ex1.c
140void StandbyMode(void) {
141MX_GPIO_Deinit();
142
143/* Эта процедура взята из перечня аппаратных ошибок (Errata sheet) STM32F030 */
144__HAL_RCC_PWR_CLK_ENABLE();
145
146 HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1); 147
148/* Сброс Флага пробуждения периферийного устройства PWR */
149__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
150
151/* Включение вывода WKUP */
152HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
154/* Переход в режим ожидания (STANDBY) */
155HAL_PWR_EnterSTANDBYMode();
156}
Наконец, строки [140:156] определяют функцию StandbyMode(). Здесь мы следуем процедуре, описанной в перечне аппаратных ошибок STM32F30, поскольку на этот микроконтроллер оказывает влияние аппаратная ошибка, которая не позволяет ЦПУ перейти в режим ожидания: сначала мы должны отключить вывод PWR_WAKEUP_PIN1, а затем сбросить флаг пробуждения в регистре PWR->CSR и повторно включить вывод пробуждения, который в микроконтроллере STM32F030 соответствует выводу PA0.
Микроконтроллеры STM32 обычно имеют два вывода пробуждения, которые называются PWR_WAKEUP_PIN1 и PWR_WAKEUP_PIN2. Для многих микроконтроллеров STM32 с корпусом LQFP64 второй вывод пробуждения соответствует PC13, который подключен к пользовательской кнопке USER на всех платах Nucleo (кроме Nucleo-F302, где он подключен к выводу PB13). Тем не менее, мы не можем использовать PWR_WAKEUP_PIN2 в нашем примере, потому что этот вывод подтянут к питанию резистором на печатной плате. Когда мы конфигурируем выводы пробуждения в сочетании с режимом ожидания, мы не используем
Управление питанием |
497 |
соответствующий порт GPIO, который позволил бы нам сконфигурировать режим входного вывода, ведь он отключается перед переходом в режим ожидания: выводы пробуждения напрямую обрабатываются контроллером питания PWR, который сбрасывает микроконтроллер, если один из двух выводов переходит на высокий логический уровень. Поэтому в примере мы используем вывод PWR_WAKEUP_PIN1, соответствующий выводу PA0 в микроконтроллере
STM32F030.
Рисунок 5: Как измерить энергопотребление микроконтроллера на плате Nucleo
Платы Nucleo позволяют измерять потребление тока микроконтроллером при помощи штыревого разъема IDD. Перед началом измерений необходимо установить соединение с платой, как показано на рисунке 5, сняв перемычку IDD и подключив щупы амперметра. Убедитесь, что амперметр настроен на шкалу мА. Таким образом, вы можете увидеть потребление энергии в каждом режиме питания.
19.3.3.Важное предупреждение о микроконтроллерах
STM32F1
Во время разработки примеров бестикового режима работы во FreeRTOS в соответствующей главе я столкнулся с неприятным поведением микроконтроллера STM32F103 при переходе в режим останова с помощью процедуры HAL_PWR_EnterSTOPMode() от HAL CubeF1. В частности, возникшая проблема связана с выходом из этого режима пониженного энергопотребления, когда микроконтроллер переходит в него при помощи инструкции WFI. В этом специфичном сценарии микроконтроллер правильно переходит в режим останова, но, когда он просыпается от прерывания, он немедленно генерирует исключение тяжелого отказа Hard Fault. Я пришел к выводу, что разработчики ST не следуют советам ARM при переходе в режимы пониженного энергопотребления в процессорах Cortex-M3, как сообщается здесь16.
16 http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHICBGB.html
Управление питанием |
498 |
Изменение процедуры HAL следующим образом решило проблему: |
|
1 void HAL_PWR_EnterSTOPMode(uint32_t Regulator, uint8_t STOPEntry) {
2/* Проверка параметров */
3assert_param(IS_PWR_REGULATOR(Regulator));
4assert_param(IS_PWR_STOP_ENTRY(STOPEntry));
6/* Сброс бита PDDS в регистре PWR, чтобы указать о наступающем переходе в режим останова \
7(STOP) при переходе ЦПУ в режим глубокого сна (Deepsleep) */
8CLEAR_BIT(PWR->CR, PWR_CR_PDDS);
10/* Выбор режима регулятора напряжения установкой бита LPDS в регистре PWR в соответствии \
11со значением параметра Regulator */
12MODIFY_REG(PWR->CR, PWR_CR_LPDS, Regulator);
13
14/* Установка бита SLEEPDEEP регистра управления системой Cortex */
15SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
16
17/* Выбор перехода в режим останова -----------------------------------------*/
18if(STOPEntry == PWR_STOPENTRY_WFI)
19{
20/* Запрос Wait For Interrupt */
21__DSB(); // Добавлено мной
22__WFI();
23__ISB(); // Добавлено мной
24}
25else
26{
27/* Запрос Wait For Event */
28__SEV();
29PWR_OverloadWfe(); /* локальное переопределение WFE */
30PWR_OverloadWfe(); /* локальное переопределение WFE */
31}
32/* Сброс бита SLEEPDEEP регистра управления системой Cortex */
33CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
34}
Изменение состоит просто в добавлении двух инструкций барьера памяти до и после инструкции WFI, как показано в строках 21 и 23.
Я задал вопрос по этой проблеме на официальном форуме ST17, но до сих пор так и не получил ответа на момент написания данной главы, и подозреваю, что ничего не получу.
17 https://community.st.com/s/question/0D50X00009XkfT2SAJ/question-regarding-implementation-of- halpwrenterstopmode-and-other-lowpower-routines-in-f1-hal