- •Оглавление
- •Предисловие
- •Почему я написал книгу?
- •Для кого эта книга?
- •Как использовать эту книгу?
- •Как организована книга?
- •Об авторе
- •Ошибки и предложения
- •Поддержка книги
- •Как помочь автору
- •Отказ от авторского права
- •Благодарность за участие
- •Перевод
- •Благодарности
- •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
Аналого-цифровое преобразование |
376 |
12.2.2. Выбор канала
В зависимости от семейства STM32 и используемого корпуса, АЦП в микроконтроллерах STM32 могут преобразовывать сигналы от различного количества каналов. В семействах F0 и L0 расположение каналов фиксировано: первым всегда является IN0, вторым – IN1 и так далее. Пользователь может только решить, использовать тот или иной канал или нет. Это означает, что в режиме сканирования первым выбранным каналом всегда будет IN0, вторым – IN1 и так далее. Вместо этого в других микроконтроллерах STM32 предлагается понятие группы. Группа состоит из последовательности преобразований, которые могут быть выполнены любыми каналами и в любой очередности. Хотя входные каналы фиксированы и привязаны к определенным выводам микроконтроллера (то есть IN0 – первый канал, IN1 – второй и т. д.), они могут быть логически переупорядочены для формирования пользовательских последовательностей выборки. Изменение порядка каналов осуществляется путем присвоения им индекса в диапазоне от 1 до 16. Этот индекс называется рангом (rank) в CubeHAL.
Рисунок 10: Как можно переупорядочить входные каналы с помощью рангов
На рисунке 10 показана данная концепция. Хотя канал IN4 является фиксированным (например, он связан с выводом PA4 в микроконтроллере STM32F401RE), ему может быть логически назначен ранг 1, так что это будет первый канал, с которого будет браться выборка. Те микроконтроллеры, которые предоставляют такую возможность, также позволяют выбирать частоту дискретизации каждого канала индивидуально, в отличие от микроконтроллеров F0/L0, где конфигурация распространяется на все каналы АЦП.
Конфигурация канал/ранг выполняется с использованием экземпляра структуры Си ADC_ChannelConfTypeDef, которая определена следующим образом:
typedef struct { |
|
|
uint32_t Channel; |
/* Задает канал для конфигурации ранга АЦП |
*/ |
uint32_t Rank; |
/* Задает ID ранга |
*/ |
uint32_t SamplingTime; |
/* Значение времени выборки для выбранного канала |
*/ |
uint32_t Offset; |
/* Зарезервировано для будущего использования, может |
|
|
быть установлено на 0 |
*/ |
} ADC_ChannelConfTypeDef; |
|
|
•Channel: задает идентификатор канала. Может принимать значение ADC_CHANNEL_0, ADC_CHANNEL_1…ADC_CHANNEL_N, в зависимости от фактического количества доступ-
ных каналов.
•Rank: соответствует рангу, связанному с каналом. Может принимать значение от 1
до 16, являющимся максимальным числом определяемых пользователем рангов.
Аналого-цифровое преобразование |
377 |
•SamplingTime: задает значение времени одной выборки, которое будет установ-
лено для выбранного канала, и оно соответствует числу или тактам АЦП. Это число не может быть произвольным, и оно является частью списка конкретных значений. Как мы увидим позже, CubeMX очень помогает, предлагая список допустимых значений для конкретного микроконтроллера, который вы рассматриваете.
Для каждого АЦП существуют две группы:
•Регулярная группа (regular group), включающая в себя до 16 каналов, которая соответствует последовательности периодически сканируемых каналов во время преобразования.
•Инжектированная группа (injected group), включающая в себя до 4 каналов, которая соответствует последовательности инжектированных каналов, если выполняется преобразование инжектированных каналов.
12.2.3. Разрядность АЦП и скорость преобразования
Преобразования можно выполнять быстрее, уменьшив разрядность АЦП7. На самом деле время выборки определяется фиксированным количеством тактов (обычно 3) плюс переменное количество тактов в зависимости от разрядности АЦП. Минимальное время преобразования для каждой из разрядностей будет следующим:
•12 бит: 3 + 12 = 15 тактовых циклов ADCCLK
•10 бит: 3 + 10 = 13 тактовых циклов ADCCLK
•8 бит: 3 + 8 = 11 тактовых циклов ADCCLK
•6 бит: 3 + 6 = 9 тактовых циклов ADCCLK
Уменьшением разрядности можно увеличить максимальное число выборок в секунду, достигая даже более 15 Мвыборок/с в некоторых микроконтроллерах STM32. Помните, что ADCCLK получается от тактового сигнала периферии: это означает, что частоты SYSCLK и PCLK влияют на максимальное число выборок в секунду.
12.2.4. Аналого-цифровые преобразования в режиме опроса
Как и большинство периферийных устройств STM32, АЦП может работать в трех режимах: в режиме опроса, прерываний и DMA. Как мы увидим позже, последним режимом в конечном итоге может управлять таймер так, чтобы аналого-цифровые преобразования происходили через регулярные промежутки времени. Это чрезвычайно полезно, когда нам нужно получать выборки сигналов на заданной частоте, как это происходит в приложениях, обрабатывающих звук.
Когда контроллер АЦП сконфигурирован с использованием экземпляра структуры ADC_InitTypeDef, переданного в процедуру HAL_ADC_Init(), мы можем запустить периферийное устройство с помощью функции HAL_ADC_Start(). В зависимости от выбранного режима преобразования, АЦП будет преобразовывать каждый выбранный вход непрерывно или однократно: в последнем случае, чтобы снова преобразовать выбранные входы, нам нужно вызвать функцию HAL_ADC_Stop(), прежде чем снова вызывать функ-
цию HAL_ADC_Start().
7 Это невозможно в микроконтроллерах STM32F1.
Аналого-цифровое преобразование |
378 |
В режиме опроса мы используем функцию
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout);
для определения, когда аналого-цифровое преобразование завершено и результат доступен в регистре данных АЦП. Функция принимает указатель на дескриптор АЦП ADC_HandleTypeDef и значение Timeout, которое представляет собой максимальное время, выраженное в миллисекундах, которое мы готовы ждать. В качестве альтернативы, мы можем передать HAL_MAX_DELAY, чтобы ждать бесконечно долго.
Чтобы получить результат, мы можем воспользоваться функцией:
uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc);
Теперь мы наконец готовы проанализировать полный пример. Мы начнем с просмотра API-интерфейсов, используемых для выполнения преобразований в режиме опроса. Как вы увидите, нет ничего нового по сравнению с тем, что мы видели до сих пор с другими периферийными устройствами.
Пример, который мы собираемся изучить, делает простую вещь: он использует внутренний датчик температуры, доступный во всех микроконтроллерах STM32, в качестве источника для АЦП. Датчик температуры подключен к внутреннему входу АЦП. Точный номер входа зависит от конкретного семейства микроконтроллера и корпуса. Например, в микроконтроллере STM32F401RE датчик температуры подключен к IN18 периферийного устройства ADC1. Тем не менее, HAL предназначен для абстрагирования этого конкретного аспекта. Прежде чем мы проанализируем реальный код, лучше взглянуть на электрические характеристики датчика температуры, которые указаны в техническом описании рассматриваемого вами микроконтроллера.
В таблице 3 приведены характеристики датчика температуры в микроконтроллере STM32F401RE. Он обладает типовыми точностью до 1°C8 и средним наклоном линейной характеристики (average slope) 2,5 мВ/°C. Кроме того, известно, что при 25°C падение напряжения составляет 760 мВ. Это означает, что для расчета обнаруженной температуры мы можем использовать формулу:
|
(V |
− V |
) |
|
Температура ( C ) = |
SENSE |
25 |
|
+ 25 |
Avg _ Slope |
|
|||
|
|
|
[1]
8 Внутренние датчики температуры STM32 откалиброваны на заводе во время производства ИС. Обычно отбираются две температуры при 30°C и 110°C. Они называются TS_CAL1 и TS_CAL2 соответственно. Обнаруженные температуры сохраняются в энергонезависимой системной памяти. Точный адрес памяти указывается в техническом описании на конкретный микроконтроллер. Используя эти данные, можно выполнить линеаризацию обнаруженных температур, чтобы погрешность сводилась к типовому значению 1°C точности. ST предоставляет руководство по применению, посвященное этой теме: AN3964 (http://www.st.com/content/ccc/resource/technical/document/application_note/b9/21/44/4e/cf/6f/46/fa/DM000359 57.pdf/files/DM00035957.pdf/jcr:content/translations/en.DM00035957.pdf). Однако имейте в виду, что внутрен-
ний датчик температуры измеряет температуру микросхемы (и, следовательно, платы). В соответствии с конкретным семейством STM32, рабочей частотой микроконтроллера, выполняемыми операциями, включенными периферийными устройствами, доменом питания и т. д. Снятая температура может быть намного выше, чем действующая температура окружающей среды. Например, автор книги подтвердил, что микроконтроллер STM32F7, работающий на частоте 200 МГц, имеет рабочую температуру ~45°C при комнатной температуре 20°C.
Аналого-цифровое преобразование |
379 |
Таблица 3: Электрические характеристики датчика температуры в микроконтроллере
STM32F401RE
В следующем коде показано, как выполнить аналого-цифровое преобразование выходного сигнала внутреннего датчика температуры в микроконтроллере STM32F401RE.
Имя файла: src/main-ex1.c
6/* Переменные ----------------------------------------------------------------*/
7extern UART_HandleTypeDef huart2;
8ADC_HandleTypeDef hadc1;
9
10/* Прототипы функций ---------------------------------------------------------*/
11static void MX_ADC1_Init(void);
12
13 int main(void) {
14
15HAL_Init();
16Nucleo_BSP_Init();
18/* Инициализация всей сконфигурированной периферии */
19 |
MX_ADC1_Init(); |
20 |
|
21 |
HAL_ADC_Start(&hadc1); |
22 |
|
23while (1) {
24char msg[20];
25uint16_t rawValue;
26float temp;
27
28 HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); 29
30rawValue = HAL_ADC_GetValue(&hadc1);
31temp = ((float)rawValue) / 4095 * 3300;
32temp = ((temp - 760.0) / 2.5) + 25;
33
34sprintf(msg, "rawValue: %hu\r\n", rawValue);
35HAL_UART_Transmit(&huart2, (uint8_t*) msg, strlen(msg), HAL_MAX_DELAY);
37sprintf(msg, "Temperature: %f\r\n", temp);
38HAL_UART_Transmit(&huart2, (uint8_t*) msg, strlen(msg), HAL_MAX_DELAY);
39}
40}
41
Аналого-цифровое преобразование |
380 |
42/* Функция инициализации ADC1 */
43void MX_ADC1_Init(void) {
44ADC_ChannelConfTypeDef sConfig;
46/* Разрешение тактирования АЦП */
47 |
__HAL_RCC_ADC1_CLK_ENABLE(); |
48 |
|
49/* Конфигурирование глобальных функций АЦП (тактирование, разрядность, выравнивание
50данных и количество преобразований) */
51hadc1.Instance = ADC1;
52hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
53hadc1.Init.Resolution = ADC_RESOLUTION_12B;
54hadc1.Init.ScanConvMode = DISABLE;
55hadc1.Init.ContinuousConvMode = ENABLE;
56hadc1.Init.DiscontinuousConvMode = DISABLE;
57hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
58hadc1.Init.NbrOfConversion = 1;
59hadc1.Init.DMAContinuousRequests = DISABLE;
60hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
61HAL_ADC_Init(&hadc1);
62
63/* Конфигурирование выбранного регулярного канала АЦП: соответствующего ему ранга в
64последовательности преобразования и его времени выборки. */
65sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
66sConfig.Rank = 1;
67sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
68HAL_ADC_ConfigChannel(&hadc1, &sConfig);
69}
Первой частью анализа кода является функция MX_ADC1_Init(), которая инициализирует периферийное устройство ADC1. Прежде всего, в строке 52 АЦП сконфигурирован так, что ADCCLK (то есть тактовая частота аналоговой части АЦП) составляет половину частоты PCLK, которая в STM32F401RE, работающем на своей максимальной частоте, составляет 84 МГц. Далее разрядность АЦП конфигурируется максимальной: 12 бит.
Режим сканирования отключен (строка 54), в то время как режим непрерывного преобразо-
вания включен (строка 55), так что мы можем многократно опрашивать преобразование без остановки, а затем перезапускать АЦП. Поэтому флаг EOC установлен в ADC_EOC_SEQ_CONV в строке 60. Обратите внимание, что параметр NbrOfConversion в строке 58 совершенно бессмысленен и избыточен в данном случае, потому что режим однократного преобразования автоматически предполагает, что количество выбранных каналов равно 1.
Строки [65:68] конфигурируют канал датчика температуры и присваивают ему ранг 1: несмотря на то что мы не выполняем режим сканирования, нам необходимо указать ранг для используемого канала. Время одной выборки установлено на 480 тактов: это означает, что с учетом тактовой частоты в 84 МГц и того, что ADCCLK установлен на
Аналого-цифровое преобразование |
381 |
половину частоты PCLK, мы получим, что аналого-цифровое преобразование выполняется каждые 10 мкс9.
Почему мы выбираем такую скорость преобразования? Причина в таблице 3, в которой говорится, что время выборки АЦП, TS_temp, равно 10 мкс с точностью до 1°C. Например, если вы увеличите скорость до 3 тактов, установив для поля
SamplingTime значение ADC_SAMPLETIME_3CYCLES, то увидите, что преобразован-
ный результат часто совсем неверен.
В той же таблице всегда можно найти другой интересный параметр: время запуска (startup time) датчика температуры (то есть время, необходимое для стабилизации выходного напряжения при включении датчика) находится в диапазоне от 6 до 10 мкс. Однако нам не нужно заботиться об этом аспекте, поскольку процедура HAL_ADC_ConfigChannel() предназначена для правильной обработки времени запуска. Это означает, что функция будет выполнять ожидание в течение 10 мкс, чтобы дать установиться рабочему режиму датчика.
Теперь мы можем сосредоточиться на процедуре main(). После запуска периферийного устройства ADC1 (строка 21) мы запускаем бесконечный цикл, который циклически опрашивает АЦП для аналого-цифрового преобразования. По завершении мы можем получить преобразованное значение и применить уравнение [1] для вычисления температуры в градусах Цельсия. В конечном итоге результат отправляется по интерфейсу
UART2.
Модуль HAL_ADC в HAL CubeF1 немного отличается от других HAL. Для запуска преобразования, управляемого программным обеспечением, необходимо, чтобы во время ини-
циализации АЦП был указан параметр hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START.
Это полностью отличается от того, что делают другие HAL, и неясно, почему разработчики ST приняли другой подход. Более того, даже CubeMX предлагает другую конфигурацию, чтобы учесть эту особенность, когда он генерирует соответствующий код инициализации. Обратитесь к примерам книги для ознакомления с полной процедурой конфигурации.
12.2.5.Аналого-цифровые преобразования в режиме прерываний
Выполнение аналого-цифрового преобразования в режиме прерываний не слишком отличается от того, что мы рассматривали до сих пор. Как обычно, мы должны определить ISR, подключенную к прерыванию АЦП, назначить требуемый приоритет прерывания и разрешить соответствующий IRQ. Как и все другие периферийные устройства HAL, мы должны вызвать HAL_ADC_IRQHandler() из ISR АЦП и реализовать процедуру обратного вызова HAL_ADC_ConvCpltCallback(), которая автоматически вызывается HAL по окончании преобразования. Наконец, все связанные с АЦП прерывания разрешаются путем запуска АЦП с помощью функции HAL_ADC_Start_IT().
9 Это число связано с тем, что интерфейс ADCCLK, работающий на частоте 48 МГц, выполняет 48 тактов каждые 1 мкс. Таким образом, 480 тактов, разделенных на 48 тактов/мкс, дают 10 мкс.