- •Оглавление
- •Предисловие
- •Почему я написал книгу?
- •Для кого эта книга?
- •Как использовать эту книгу?
- •Как организована книга?
- •Об авторе
- •Ошибки и предложения
- •Поддержка книги
- •Как помочь автору
- •Отказ от авторского права
- •Благодарность за участие
- •Перевод
- •Благодарности
- •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
Таймеры |
324 |
Когда таймер отсчитывает в режиме TIM_COUNTERMODE_DOWN, он запускается со значения Period и ведет обратный отсчет до нуля: когда счетчик достигает конца, срабатывает IRQ таймера и устанавливается флаг UIF (то есть генерируется событие обновления и
HAL_TIM_PeriodElapsedCallback() вызывается HAL).
Напротив, когда таймер отсчитывает в режиме TIM_COUNTERMODE_CENTERALIGNED, он начинает отсчет с нуля до значения Period: это приводит к тому, что срабатывает IRQ таймера и устанавливается флаг UIF (то есть генерируется событие обновления и HAL_TIM_PeriodElapsedCallback() вызывается HAL). Затем таймер начинает обратный отсчет до нуля, и генерируется другое событие обновления (а также соответствующий IRQ).
11.3.5. Режим захвата входного сигнала
Таймеры общего назначения не предназначены для использования в качестве генераторов временного отсчета. Несмотря на то, что их вполне можно использовать для данной работы, эту задачу следует выполнять другими таймерами, такими как базовые таймеры и таймер SysTick. Таймеры общего назначения предлагают гораздо более продвинутые возможности, которые можно использовать для управления другими важными действиями, связанными со временем.
На рисунке 16 показана структурная схема входных каналов в таймере общего назначения25. Как видите, каждый вход подключен к детектору фронта (edge detector), который также оснащен фильтром (input filter), используемым для «борьбы с дребезгом» входного сигнала. Выход детектора фронта поступает в мультиплексор источников (IC1, IC2 и т. д.). Он позволяет «переназначить» входные каналы, если выбранный I/O привязан к другому периферийному устройству. Наконец, выделенный предделитель позволяет «замедлить» частоту входного сигнала, чтобы соответствовать рабочей частоте таймера, если ее нельзя снизить, как мы увидим через некоторое время.
Рисунок 16: Структурная схема входного канала в таймере общего назначения
25 Некоторые таймеры общего назначения (например, TIM14) имеют меньше входных каналов и, следовательно, упрощенную структурную схему входного каскада. Обратитесь к справочному руководству по вашему микроконтроллеру, чтобы узнать точную структурную схему таймера, который вы собираетесь использовать.
Таймеры |
325 |
Режим захвата входного сигнала (Input capture mode), предоставляемый таймерами общего назначения и расширенного управления, позволяет вычислять частоту внешних сигналов, подаваемых на каждый из 4 каналов, которые предоставляют данные таймеры. При этом захват выполняется независимо для каждого канала.
Рисунок 17: Процесс захвата внешнего сигнала, поданного на один из каналов таймера
На рисунке 17 показано, как работает процесс захвата. TIMx – это таймер, сконфигурированный на работу с заданной тактовой частотой TIMx_CLK26. Это означает, что он увеличивает регистр TIMx_CNT до значения Period каждые секунды. Предпо-
ложим, что мы подаем сигнал прямоугольной формы к одному из каналов таймера, и предположим, что мы сконфигурировали таймер с запуском на каждом переднем (нарастающем) фронте входного сигнала, тогда получим, что регистр TIMx_CCRx27 будет обновляться содержимым регистра TIMx_CNT на каждом обнаруженном перепаде. Когда это происходит, таймер генерирует соответствующее прерывание или запрос к DMA, позволяя отслеживать значение счетчика.
Чтобы получить период внешнего сигнала, необходимо выполнить два захвата подряд. Период рассчитывается путем вычитания этих двух значений CNT0 (значение 4 на рисунке 17) и CNT1 (значение 20 на рисунке 17) с использованием следующей формулы:
|
TIMx _ CLK |
|
−1 |
|
|||
Период = Захват |
|
|
|
|
(Prescaler +1)(Предделитель канала)(Индекс полярности) |
|
|
|
|
|
|
[4]
где:
Захват = CNT − CNT |
, если CNT |
CNT |
|
1 |
0 |
0 |
1 |
Захват = (TIMx _ Period −CNT )+ CNT |
, если CNT |
CNT |
|
0 |
1 |
0 |
1 |
Предделитель канала – это дополнительный предделитель, который можно применить к входному каналу, а Индекс полярности равен 1, если канал сконфигурирован на запуск
26Тактовая частота таймера не зависит от того, как работает таймер (в данном случае режим захвата входного сигнала). Как видно из предыдущих параграфов, тактовый сигнал таймера зависит от частоты шины или внешнего источника тактового сигнала и от соответствующих параметров предделителя.
27CCR – это сокращение от Capture Compare Register (регистр захвата/сравнения), а x – номер канала.
Таймеры |
326 |
по переднему (нарастающему) или заднему (спадающему) фронту входного сигнала, или равен 2, если отбираются оба фронта.
Другим важным условием является то, что частота возникновения UEV должна быть ниже частоты отбираемого сигнала. Причина, по которой это имеет значение, очевидна: если таймер работает быстрее, чем отбираемый сигнал, то он переполнится (то есть счетчик истечет до Period), прежде чем сможет произвести выборку фронтов сигнала (см. рисунок 18). По этой причине обычно удобно установить значение Period на максимальное и увеличить Prescaler, чтобы снизить частоту дискретизации.
Рисунок 18: Если таймер работает быстрее, чем происходит выборка сигнала, он переполняется до того, как обнаружатся два передних (нарастающих) фронта
Для конфигурации входных каналов используется функция
и экземпляр структуры Си TIM_IC_InitTypeDef, которая определена следующим образом:
typedef struct { |
|
|
uint32_t ICPolarity; |
/* Задает активный фронт входного сигнала. |
*/ |
uint32_t ICSelection; |
/* Задает вход. |
*/ |
uint32_t ICPrescaler; |
/* Задает предделитель захвата входного сигнала. |
*/ |
uint32_t ICFilter; |
/* Задает фильтр захвата входного сигнала. |
*/ |
} TIM_IC_InitTypeDef; |
|
|
•ICPolarity: задает полярность входного сигнала и может принимать значение из
таблицы 16.
•ICSelection: задает используемый вход таймера. Может принимать значение из
таблицы 17. Можно выборочно переназначить входные каналы на разные входные источники, то есть (IC1, IC2) отобразить на (TI2, TI1) и (IC3, IC4) отобразить на (TI4, TI3). Обычно это используется для различения захвата переднего фронта от захвата заднего фронта для сигналов, где TВКЛ отличается от TВЫКЛ . Также воз-
можно захватывать из такого же внутреннего канала, называемого TRC, подключенного к источникам ITR0..ITR3.
•ICPrescaler: конфигурирует каскад предделителя заданного входа. Может прини-
мать значение из таблицы 18.
•ICFilter: это 4-битное поле задает частоту, используемую для отбора внешнего
тактового сигнала, подключенного к выводу TIMx_CHx, и размер применяемого к нему цифрового фильтра. Полезен для борьбы с дребезгом входного сигнала. Обратитесь к техническому описанию вашего микроконтроллера для получения дополнительной информации.
Таймеры |
327 |
Таблица 16: Доступная полярность захвата входного сигнала |
|
Режим полярности |
захвата |
входного сигнала |
Описание |
TIM_ICPOLARITY_RISING |
Захватывается передний фронт внешнего сигнала |
TIM_ICPOLARITY_FALLING |
Захватывается задний фронт внешнего сигнала |
TIM_ICPOLARITY_BOTHEDGE |
Передний и задний фронты внешнего сигнала опреде- |
|
ляют период захвата (это увеличивает частоту дискрети- |
|
зации сигнала) |
Таблица 17: Доступный выбор режимов захвата входного сигнала
Выбор режима захвата входного |
|
сигнала |
Описание |
TIM_ICSELECTION_DIRECTTI |
Вход 1, 2, 3 или 4 таймера выбран для подключения к |
|
IC1, IC2, IC3 или IC4 соответственно. |
TIM_ICSELECTION_INDIRECTTI
Вход 1, 2, 3 или 4 таймера выбран для подключения к IC2, IC1, IC4 или IC3 соответственно.
TIM_ICSELECTION_TRC
Вход 1, 2, 3 или 4 таймера выбран для подключения к TRC (линия запуска на рисунке 3 – вход TRC выделен красным на рисунке 16)
Таблица 18: Доступные режимы предделителя захвата входного сигнала
Режим предделителя захвата |
|
входного сигнала |
Описание |
|
|
TIM_ICPSC_DIV1 |
Предделитель не используется |
TIM_ICPSC_DIV2 |
Захват выполняется один раз каждые 2 события |
TIM_ICPSC_DIV4 |
Захват выполняется один раз каждые 4 события |
TIM_ICPSC_DIV8 |
Захват выполняется один раз каждые 8 события |
Теперь самое время увидеть практический пример. Мы будем перестраивать Пример 2 данной главы так, чтобы производить выборку частоты переключения вывода PA5 (тот, что подключен к светодиоду LD2) через канал 1 таймера TIM3 (в микроконтроллере STM32F030 этот вывод совпадает с выводом PA6). Таким образом, мы сконфигурируем канал 1 как вывод захвата входного сигнала и сконфигурируем его в режиме DMA, чтобы он инициировал запрос TIM3_CH1 для автоматического заполнения временного буфера, в котором будет храниться значение регистра TIM3_CNT при обнаружении переднего (нарастающего) фронта входного сигнала.
Прежде чем проанализировать функцию main(), лучше всего взглянуть на процедуры инициализации TIM3.
Имя файла: src/main-ex6.c
59/* Функция инициализации TIM3 */
60void MX_TIM3_Init(void) {
61TIM_IC_InitTypeDef sConfigIC;
63htim3.Instance = TIM3;
64htim3.Init.Prescaler = 0;
65htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
66htim3.Init.Period = 65535;
67htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
Таймеры |
328 |
68 |
HAL_TIM_IC_Init(&htim3); |
|
69 |
|
|
70sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
71sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
72sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
73sConfigIC.ICFilter = 0;
74HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1);
75}
76
77void HAL_TIM_IC_MspInit(TIM_HandleTypeDef* htim_ic) {
78GPIO_InitTypeDef GPIO_InitStruct;
79if (htim_ic->Instance == TIM3) {
80/* Разрешение тактирования переферии */
81__HAL_RCC_TIM3_CLK_ENABLE();
82
83/**Конфигурация GPIO таймера TIM3
84PA6 ------> TIM3_CH1
85*/
86GPIO_InitStruct.Pin = GPIO_PIN_6;
87GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
88GPIO_InitStruct.Pull = GPIO_NOPULL;
89GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
90GPIO_InitStruct.Alternate = GPIO_AF1_TIM3;
91HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
92
93/* Инициализация DMA периферии */
94hdma_tim3_ch1_trig.Instance = DMA1_Channel4;
95hdma_tim3_ch1_trig.Init.Direction = DMA_PERIPH_TO_MEMORY;
96hdma_tim3_ch1_trig.Init.PeriphInc = DMA_PINC_DISABLE;
97hdma_tim3_ch1_trig.Init.MemInc = DMA_MINC_ENABLE;
98hdma_tim3_ch1_trig.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
99hdma_tim3_ch1_trig.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
100hdma_tim3_ch1_trig.Init.Mode = DMA_NORMAL;
101hdma_tim3_ch1_trig.Init.Priority = DMA_PRIORITY_LOW;
102HAL_DMA_Init(&hdma_tim3_ch1_trig);
103
104/* Несколько указателей дескриптора DMA периферии указывают на один
105и тот же дескриптор DMA.
106Имейте в виду, что существует только один канал для выполнения всех запросов к DMA. */
107__HAL_LINKDMA(htim_ic, hdma[TIM_DMA_ID_CC1], hdma_tim3_ch1_trig);
108}
109}
MX_TIM3_Init() конфигурирует таймер TIM3 так, чтобы он работал на частоте, равной ~732 Гц. Первый канал затем конфигурируется для запуска события захвата (TIM3_CH1) на каждом переднем фронте входного сигнала. Затем HAL_TIM_IC_MspInit() конфигурирует аппаратную часть (вывод PA6, подключенный к каналу 1 таймера TIM3) и дескриптор DMA, используемый для конфигурации запроса TIM3_CH1.
Таймеры |
329 |
Здесь мы должны отметить два момента. Прежде всего, DMA сконфигурирован так, что выравнивание данных периферии и памяти установлено для выполнения 16-битной передачи, поскольку регистр счетчика таймера размером 16 бит. В тех микроконтроллерах, где таймеры TIM2 и TIM5 имеют регистр счетчика размером 32 бита, необходимо сконфигурировать DMA для выполнения передачи с выравниванием по словам. Далее, поскольку мы используем HAL_TIM_IC_Init() в строке 68, HAL предназначен для вызова функции HAL_TIM_IC_MspInit() для выполнения низкоуровневых инициализаций вместо
HAL_TIM_Base_MspInit().
Имя файла: src/main-ex6.c
20uint8_t odrVals[] = { 0x0, 0xFF };
21uint16_t captures[2];
22volatile uint8_t captureDone = 0;
24int main(void) {
25uint16_t diffCapture = 0;
26char msg[30];
28 |
HAL_Init(); |
29 |
|
30Nucleo_BSP_Init();
31MX_DMA_Init();
32
33MX_TIM3_Init();
34MX_TIM6_Init();
36HAL_DMA_Start(&hdma_tim6_up, (uint32_t) odrVals, (uint32_t) &GPIOA->ODR, 2);
37__HAL_TIM_ENABLE_DMA(&htim6, TIM_DMA_UPDATE);
38 HAL_TIM_Base_Start(&htim6); 39
40 HAL_TIM_IC_Start_DMA(&htim3, TIM_CHANNEL_1, (uint32_t*) captures, 2); 41
42while (1) {
43if (captureDone != 0) {
44if (captures[1] >= captures[0])
45diffCapture = captures[1] - captures[0];
46else
47diffCapture = (htim3.Instance->ARR - captures[0]) + captures[1];
49frequency = HAL_RCC_GetPCLK1Freq() / (htim3.Instance->PSC + 1);
50frequency = (float) frequency / diffCapture;
52sprintf(msg, "Input frequency: %.3f\r\n", frequency);
53HAL_UART_Transmit(&huart2, (uint8_t*) msg, strlen(msg), HAL_MAX_DELAY);
54while (1);
55}
56}
57 }