- •Оглавление
- •Предисловие
- •Почему я написал книгу?
- •Для кого эта книга?
- •Как использовать эту книгу?
- •Как организована книга?
- •Об авторе
- •Ошибки и предложения
- •Поддержка книги
- •Как помочь автору
- •Отказ от авторского права
- •Благодарность за участие
- •Перевод
- •Благодарности
- •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
Управление питанием |
483 |
...
while(1) {
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); HAL_Delay(500);
}
Этот с виду безобидный код оказывает существенное влияние на энергопотребление нашего устройства. Несмотря на то что нам особо не нужно много чего делать в течение этих 500 мс, мы тратим много энергии на проверку значения глобального счетчика тиков таймера SysTick, чтобы посмотреть, прошло ли это время задержки. Вместо этого мы можем перестроить этот код, чтобы большую часть времени оставаться в спящем режиме, и мы можем сконфигурировать таймер, который будет пробуждать микроконтроллер каждые 100 мс.
Разрешение другим программным компонентам решать, когда переводить микроконтроллер в спящий режим, может представлять собой другой подход. Как мы увидим в Главе 23, операционная система реального времени может быть запрограммирована на автоматический перевод микроконтроллера в спящий режим, когда ему нечего делать5.
19.2.1. Переход в/выход из спящих режимов
Как было сказано в предыдущем параграфе, ЦПУ переходит в спящий режим исключительно на добровольной основе, используя специальные ассемблерные инструкции ARM. Это означает, что, как программисты, мы несем полную ответственность за энергопотребление разрабатываемых нами устройств6.
Микроконтроллеры на базе Cortex-M предлагают две инструкции для их перевода в спящий режим: WFI и WFE. Инструкция «Ожидание прерывания» (Wait For Interrupt, WFI) также называется безусловной инструкцией перехода в спящий режим. Когда ЦПУ выполняет данную инструкцию, оно немедленно останавливает выполнение ядра. Процессор возобновит работу только по запросу прерывания, в зависимости от приоритета прерывания и действующего уровня сна (подробнее об этом позже), или в случае событий отладки. Если прерывание оказалось отложено (pending), пока микроконтроллер выполнял инструкцию WFI, он переходит в спящий режим и сразу же выходит из него.
«Ожидание события» (Wait For Event, WFE) является другой инструкцией, позволяющей перевести микроконтроллер в спящий режим. Она отличается от WFI тем, что проверяет состояние специального регистра событий7, прежде чем остановить ядро: если этот регистр установлен, WFE сбрасывает его и не приостанавливает ЦПУ, продолжающее выполнение программы (это позволяет нам управлять отложенным событием, если это необходимо). В противном случае она приостанавливает микроконтроллер, пока данный регистр событий снова не будет установлен.
5В данной главе мы обнаружим, что одна из возможных стратегий состоит в переводе микроконтроллера в спящий режим, когда планировщик ставит на выполнение холостой поток. Холостой поток (idle thread)
– это поток, выполняемый ОСРВ, когда все остальные потоки «не выполняются». Он ясно дает понять, что микроконтроллеру ничего существенного делать не надо, и его можно безопасно перевести в спящий режим.
6Понятно, что речь идет об энергопотреблении ядра микроконтроллера и всех интегрированных в него периферийных устройств. Потребляемая энергия всей платы определяется другими «вещами», которые мы не будем здесь рассматривать.
7Этот регистр является внутренним для ядра и недоступен для пользователя.
Управление питанием |
484 |
Но в чем именно разница между событием и прерыванием? События являются источником путаницы в мире STM32 (а также в мире Cortex-M в целом). Они выглядят как нечто нематериальное по сравнению с прерываниями, которые мы научились обрабатывать в Главе 7. Прежде чем мы выясним, что такое события, нам нужно лучше объяснить роль контроллера EXTI в микроконтроллере STM32. Расширенный контроллер пре-
рываний и событий (Extended Interrupts and Events Controller, EXTI) – это аппаратный ком-
понент, встроенный в микроконтроллер, который управляет внешними и внутренними асинхронными прерываниями/событиями и генерирует запрос событий для ЦПУ/контроллера NVIC и запрос на пробуждение для контроллера питания (см. рисунок 2). Контроллер EXTI позволяет управлять несколькими линиями событий, которые могут пробудить микроконтроллер из некоторых спящих режимов (не все события могут пробудить микроконтроллер). Линии могут быть конфигурируемыми или прямыми и, следовательно, встроенными в микроконтроллер:
•Линии являются конфигурируемыми: активный фронт может быть выбран независимо, а флаг состояния указывает источник прерывания. Конфигурируемые линии используются внешними прерываниями от вводов/выводов и несколькими периферийными устройствами (подробнее об этом позже).
•Линии являются прямыми и аппаратными: они используются некоторыми пе-
риферийными устройствами для генерации пробуждения от события останова или прерывания. Флаг состояния предоставляется самим периферийным устройством. Например, RTC может использоваться для генерации события для пробуждения микроконтроллера.
Рисунок 2: Как события могут быть использованы для пробуждения ядра
Другим важным аспектом, который необходимо прояснить в отношении контроллеров EXTI и NVIC, является то, что каждая линия может маскироваться независимо для генерации прерываний или событий. Например, в Главе 6 мы видели, что GPIO можно сконфигурировать для работы в режиме GPIO_MODE_EVT_*, который отличается от режима GPIO_MODE_IT_*: в первом случае, когда срабатывает I/O, он не будет генерировать запрос IRQ, но установит флаг события. Это приведет к пробуждению микроконтроллера, если он перешел в режим пониженного энергопотребления при помощи инструкции WFE.
Управление питанием |
485 |
Таким образом, инструкция WFE проверяет, нет ли отложенных событий, и по этой причине она также называется инструкцией условного перехода в спящий режим. Этот регистр событий может быть установлен:
•в случае перехода в и выхода из исключения (exception entrance and exit);
•когда включена функция SEV-On-Pend, регистр событий может быть установлен при изменении отложенного состояния прерывания с 0 на 1 (подробнее об этом позже);
•если периферийное устройство устанавливает свою выделенную линию событий (это зависит от периферийного устройства);
•в случае выполнения инструкции SEV (Send Event – «Генерация события»);
•в случае события отладки (например, запрос на приостановку выполнения программы).
ВГлаве 7 мы видели, что в ядрах Cortex-M3/4/7 мы можем временно маскировать выполнение этих прерываний, имеющих приоритет ниже значения, установленного в регистре BASEPRI. Однако данные прерывания все еще разрешены и помечаются как отложенные при их срабатывании. Мы можем сконфигурировать микроконтроллер для установки регистра событий в случае отложенных прерываний, установив бит SCR->SEVONPEND. Как следует из названия, этот регистр приведет к «установке регистра
событий, если прерывания отложены». Это означает, что, если процессор был переведен в спящий режим по инструкции WFE, ЦПУ сразу же пробуждается, и мы можем в конечном итоге обрабатывать отложенные прерывания. Вместо этого WFI никогда не пробудит ядро. Cube HAL предоставляет две удобные функции, HAL_PWR_EnableSEVOnPend() и
HAL_PWR_DisableSEVOnPend(), для выполнения этой настройки.
Если вместо этого прерывания маскируются установкой регистра PRIMASK, отложенное прерывание может пробудить процессор, независимо от используемой инструкции перехода в спящий режим (WFI или WFE): эта характеристика позволяет некоторым частям микроконтроллера отключаться программно путем запрета их тактирования, и программное обеспечение может обратно разрешить его после пробуждения перед выполнением ISR.
Итак, подведем итог. WFI и WFE ведут себя одинаково:
•пробуждают по запросам прерываний/исключений, которые разрешены и имеют более высокий приоритет, чем текущий уровень8;
•микроконтроллер может быть пробужден событиями отладки;
•могут использоваться для перехода как в спящий режим, так и в режим глубокого сна (подробнее об этом позже).
Вместо этого WFI и WFE отличаются по следующим причинам:
•выполнение WFE не переводит микроконтроллер в спящий режим, если установлен внутренний регистр событий, в то время как выполнение WFI всегда приводит к спящему режиму;
•новое отложенное состояние запрещенного или маскированного прерывания может пробудить процессор от WFE, если установлен регистр SEVONPEND;
•выполнив WFE, микроконтроллер может быть пробужден внешним событием;
8 Запрет прерывания на приоритетной основе применим только к микроконтроллеру на базе CortexM3/4/7.
Управление питанием |
486 |
•выполнив WFI, микроконтроллер может быть пробужден разрешенным прерыванием, когда установлен регистр PRIMASK.
19.2.1.1. «Спящий режим по выходу»
Функция «Спящий режим по выходу» (Sleep-On-Exit) полезна для приложений, построенных на прерываниях, где все операции (кроме этапа инициализации) выполняются внутри обработчиков прерываний. Это программируемая функция, которую можно включить или отключить, установив бит регистра SCB->SCR. Когда она включена, ядро Cortex-M автоматически переходит в спящий режим (так же, как и при выполнении инструкции WFI) при выходе из обработчика исключения/прерывания. Функция Sleep-On- Exit должна быть включена в конце этапа инициализации. В противном случае, если событие прерывания произойдет на этапе инициализации, когда функция Sleep-On-Exit уже включена, процессор перейдет в спящий режим, несмотря на то что этап инициализации еще не завершен.
CubeHAL предоставляет две удобные процедуры для включения/отключения этого ре-
жима: HAL_PWR_EnableSleepOnExit() и HAL_PWR_DisableSleepOnExit().
19.2.2.Спящие режимы в микроконтроллерах на базе
Cortex-M
До сих пор мы много говорили о спящем режиме. Это в основном потому, что схема управления питанием, определенная ARM, дополнительно подстраивается производителями интегральных схем, как это делает ST со своими продуктами. Микроконтроллеры на базе Cortex-M архитектурно поддерживают два спящих режима: нормальный спящий режим и глубокий сон. Как мы узнаем позже в данной главе, микроконтроллеры STM32F называют их Спящим (sleep) режимом и режимом Останова (stop) и добавляют третий, еще более глубокий режим, называемый режимом Ожидания (standby). Серия STM32L дополнительно расширяет эти два «основных» режима работы на несколько подрежимов.
И спящий режим, и режим глубокого сна достигаются с помощью инструкций WFI и WFE, которые мы рассмотрели ранее. Единственное отличие состоит в том, что режим глубокого сна достигается установкой бита SLEEPDEEP в 1 в регистре PWR->SCR. Однако нам не нужно разбираться в этих подробностях, поскольку CubeHAL спроектирован для абстрагирования от них.
Обычно микроконтроллеры STM32 спроектированы таким образом, что в спящем режиме отключается только тактирование ЦПУ, в то время как на другие тактовые генераторы или источники аналогового тактового сигнала он не оказывает влияния (это означает, что все включенные периферийные устройства остаются активными). Вместо этого в режиме останова тактирование всех периферийных устройств домена питания 1,8 В (или 1,2 В для новейших микроконтроллеров STM32), отключается, а тактирование домена питания VDD остается включенным9, за исключением HSI-генератора и
9 Как мы увидим далее, микроконтроллер STM32 может питаться от регулируемого источника напряжения в диапазоне от 2,0 до 3,6 В (некоторые из них позволяют питаться даже до 1,7 В). Этот источник напряжения также называется доменом питания VDD, и все компоненты внутри микроконтроллера, питаемые от этого источника, считаются частью домена питания VDD. Тем не менее, внутреннее ядро микроконтроллера и некоторые другие периферийные устройства питаются от встроенного внутреннего регулятора напряжения 1,8 В (или даже 1,0 В в маломощных микроконтроллерах STM32L). Они определяются доменом