- •Оглавление
- •Предисловие
- •Почему я написал книгу?
- •Для кого эта книга?
- •Как использовать эту книгу?
- •Как организована книга?
- •Об авторе
- •Ошибки и предложения
- •Поддержка книги
- •Как помочь автору
- •Отказ от авторского права
- •Благодарность за участие
- •Перевод
- •Благодарности
- •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
Цифро-аналоговое преобразование |
396 |
13.2. Модуль HAL_DAC
После краткого ознакомления с наиболее важными функциями, предлагаемыми периферийным устройством ЦАП в микроконтроллерах STM32, самое время погрузиться в связанные с ним API-интерфейсы CubeHAL.
Чтобы манипулировать периферийным устройством ЦАП, HAL объявляет структуру Си DAC_HandleTypeDef, которая определена следующим образом:
typedef struct { |
|
|
|
DAC_TypeDef |
*Instance; |
/* Указатель на дескриптор ЦАП |
*/ |
__IO HAL_DAC_StateTypeDef |
State; |
/* Состояние работы ЦАП |
*/ |
HAL_LockTypeDef |
Lock; |
/* Блокировка объекта ЦАП |
*/ |
DMA_HandleTypeDef |
*DMA_Handle1; /* Указатель на дескриптор DMA |
|
|
|
|
для канала 1 |
*/ |
DMA_HandleTypeDef |
*DMA_Handle2; /* Указатель на дескриптор DMA |
|
|
|
|
для канала 2 |
*/ |
__IO uint32_t |
ErrorCode; |
/* Код ошибки ЦАП |
*/ |
} DAC_HandleTypeDef; |
|
|
|
Давайте проанализируем наиболее важные поля данной структуры.
•Instance (экземпляр): это указатель на дескриптор ЦАП, который мы будем ис-
пользовать. Например, DAC1 является дескриптором первого ЦАП.
•DMA_Handle{1,2}: это указатель на дескриптор DMA, сконфигурированный для вы-
полнения цифро-аналоговых преобразований в режиме DMA. В ЦАП с двумя выходными каналами существуют два независимых дескриптора DMA, используемых для выполнения преобразований для каждого канала.
Как видите, структура DAC_HandleTypeDef отличается от дескрипторов других периферийных устройств, используемых до сих пор. Фактически, она не предоставляет специальный параметр Init, используемый функцией HAL_DAC_Init() для конфигурации ЦАП. Это связано с тем, что действующая конфигурация ЦАП выполняется на уровне канала, и она требуется для структуры DAC_ChannelConfTypeDef, которая определена следующим образом:
typedef struct { |
|
|
uint32_t DAC_Trigger; |
/* Задает внешний источник запуска для выбранного |
|
|
канала ЦАП */ |
|
uint32_t DAC_OutputBuffer; |
/* Определяет, будет ли выходной буфер канала ЦАП |
|
|
включен или отключен |
*/ |
} DAC_ChannelConfTypeDef; |
|
|
•DAC_Trigger: задает источник, используемый для запуска преобразования ЦАП.
Может принимать значение DAC_TRIGGER_NONE, когда ЦАП управляется вручную с
помощью функции HAL_DAC_SetValue(); значение DAC_TRIGGER_SOFTWARE, когда ЦАП
управляется в режиме DMA без таймера для «синхронизации» преобразований; значение DAC_TRIGGER_Tx_TRGO, определяющее преобразование, управляемое предназначенным для этого таймером.
•DAC_OutputBuffer: включает выделенный выходной буфер.
Цифро-аналоговое преобразование |
397 |
Для фактической конфигурации канала ЦАП мы используем функцию:
HAL_StatusTypeDef HAL_DAC_ConfigChannel(DAC_HandleTypeDef* hdac, DAC_ChannelConfTypeDef* sConfig, uint32_t Channel);
которая принимает указатель на экземпляр структуры DAC_HandleTypeDef, указатель на экземпляр структуры DAC_ChannelConfTypeDef, рассмотренной ранее, и макрос DAC_CHANNEL_1 для конфигурации первого канала или DAC_CHANNEL_2 – для второго.
В некоторых более новых микроконтроллерах STM32, таких как STM32L476, ЦАП также предоставляет дополнительные функции с пониженным энергопотреблением. Например, можно включить схему выборки и хранения, которая позволяет поддерживать стабильное выходное напряжение, даже если ЦАП отключен. Это чрезвычайно полезно в приложениях с батарейным питанием. В данных микроконтроллерах структура DAC_ChannelConfTypeDef отличается, и она позволяет конфигурировать эти дополнительные функции. Обратитесь к исходному коду HAL для микроконтроллера, который вы рассматриваете.
13.2.1. Управление ЦАП вручную
Периферийное устройство ЦАП может управляться вручную или с использованием контроллера DMA и источника запуска (например, предназначенный для этого таймер). Сейчас мы собираемся проанализировать первый метод, который используется, когда мы не нуждаемся в преобразованиях на высоких частотах.
Первый шаг состоит в запуске периферийного устройства путем вызова функции:
HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef* hdac, uint32_t Channel);
Функция принимает указатель на экземпляр структуры DAC_HandleTypeDef и активируе-
мый канал (DAC_CHANNEL_1 или DAC_CHANNEL_2).
Как только канал ЦАП включится, мы можем выполнить преобразование, вызвав функцию:
HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t Alignment, uint32_t Data);
где параметр Alignment может принимать значение DAC_ALIGN_8B_R для управления ЦАП в 8-разрядном режиме, DAC_ALIGN_12B_L или DAC_ALIGN_12B_R для управления ЦАП в 12-разрядном режиме, передавая выходное значение выравнивания по левому или правому краю соответственно.
В следующем примере, предназначенном для работы на Nucleo-F072RB, показано, как управлять периферийным устройством ЦАП вручную. Пример основан на том факте, что в большинстве плат Nucleo, предоставляющих периферийное устройство ЦАП, один из выходных каналов соответствует выводу PA5, который подключен к светодиоду LD2. Это позволяет нам включать/выключать LD2 с помощью ЦАП.
Цифро-аналоговое преобразование |
398 |
Имя файла: src/main-ex1.c
8 DAC_HandleTypeDef hdac;
9
10/* Прототипы функций ---------------------------------------------------------*/
11static void MX_DAC_Init(void);
12
13int main(void) {
14HAL_Init();
15Nucleo_BSP_Init();
17/* Инициализация всей сконфигурированной периферии */
18 |
MX_DAC_Init(); |
19 |
|
20HAL_DAC_Init(&hdac);
21HAL_DAC_Start(&hdac, DAC_CHANNEL_2);
23while(1) {
24int i = 2000;
25while(i < 4000) {
26HAL_DAC_SetValue(&hdac, DAC_CHANNEL_2, DAC_ALIGN_12B_R, i);
27HAL_Delay(1);
28i+=4;
29}
30
31while(i > 2000) {
32HAL_DAC_SetValue(&hdac, DAC_CHANNEL_2, DAC_ALIGN_12B_R, i);
33HAL_Delay(1);
34i-=4;
35}
36}
37}
38
39/* Функция инициализации ЦАП */
40void MX_DAC_Init(void) {
41DAC_ChannelConfTypeDef sConfig;
42GPIO_InitTypeDef GPIO_InitStruct;
44 |
__HAL_RCC_DAC1_CLK_ENABLE(); |
45 |
|
46/* Инициализация ЦАП */
47hdac.Instance = DAC;
48HAL_DAC_Init(&hdac);
49
50/**Конфигурация канала OUT2 ЦАП */
51sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
52sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
53HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_2);
55/* Конфигурация GPIO ЦАП
56PA5 ------> DAC_OUT2
Цифро-аналоговое преобразование |
399 |
57*/
58GPIO_InitStruct.Pin = GPIO_PIN_5;
59GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
60GPIO_InitStruct.Pull = GPIO_NOPULL;
61HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
62}
Код достаточно прост. Строки [40:62] конфигурируют ЦАП таким образом, чтобы канал 2 использовался в качестве выходного канала. По этой причине PA5 сконфигурирован в качестве аналогового выхода (строки [58:61]). Обратите внимание, что, поскольку мы собираемся управлять преобразованиями ЦАП вручную, для источника запуска канала установлено значение DAC_TRIGGER_NONE (строка 51). Наконец, main() – это не что иное, как бесконечный цикл, который увеличивает/уменьшает выходное напряжение, так что LD2 плавно включается/выключается.
13.2.2.Управление ЦАП в режиме DMA с использованием таймера
Наиболее распространенным использованием периферийного устройства ЦАП является генерация аналогового сигнала с заданной частотой (например, в аудио приложениях). Если это так, то лучший способ управлять ЦАП – использовать DMA и таймер для запуска преобразований.
Чтобы запустить ЦАП и выполнить передачу в режиме DMA, нам нужно сконфигурировать соответствующую пару канал/поток DMA и использовать функцию:
HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef* hdac, uint32_t Channel, uint32_t* pData, uint32_t Length, uint32_t Alignment);
которая принимает указатель на экземпляр структуры DAC_HandleTypeDef, активируемый канал (DAC_CHANNEL_1 или DAC_CHANNEL_2), указатель на массив значений для передачи в режиме DMA, его размер и выравнивание выходных значений в памяти, которое может принимать значение DAC_ALIGN_8B_R для управления ЦАП в 8-разрядном режиме, DAC_ALIGN_12B_L или DAC_ALIGN_12B_R для управления ЦАП в 12-разрядном режиме, передавая выходное значение с выравниванием по левому или правому краю соответственно.
Например, мы можем легко генерировать синусоидальный сигнал, используя ЦАП. В Главе 11 мы проанализировали, как использовать режим ШИМ таймера для генерации синусоидальных сигналов. Если наш микроконтроллер предоставляет ЦАП, то эту же операцию можно выполнить проще. Более того, в зависимости от конкретного приложения, включив выходной буфер, мы можем вообще избежать внешних пассивных фильтров.
Чтобы сгенерировать синусоидальный сигнал, работающий на заданной частоте, мы должны поделить полный период на несколько шагов. Обычно более 200 шагов являются хорошим приближением для выходного сигнала. Это означает, что если мы хотим сгенерировать синусоидальный сигнал частотой 50 Гц, нам нужно выполнять преобразование каждые:
fсинусоиды = 50 Гц 200 = 10 кГц [2]
Цифро-аналоговое преобразование |
400 |
Поскольку ЦАП STM32 имеет разрядность 12 бит, мы должны разделить значение 4095, соответствующее максимальному выходному напряжению, на 200 шагов, используя следующую формулу:
|
ЦАП |
|
|
|
2 |
+1 |
|
4096 |
|
||
|
OUT |
= sin x |
|
|
|
|
|
|
|||
|
|
|
|
n |
|
|
|
2 |
|||
|
|
|
|
|
|
|
|
|
|||
|
|
|
s |
|
|
||||||
где ns |
– количество выборок, то есть 200 в нашем примере. |
[3]
Используя приведенную выше формулу, мы можем сгенерировать вектор инициализации, подаваемый на ЦАП в режиме DMA. Как и для периферийного устройства АЦП, мы можем использовать таймер, сконфигурированный для запуска линии TRGO на частоте, указанной в [2]. В следующем примере показано, как генерировать синусоидальный сигнал частотой 50 Гц с использованием ЦАП в микроконтроллере STM32F072.
|
Имя файла: src/main-ex1.c |
|
|
|
|
7 |
#define PI |
3.14159 |
8 |
#define SAMPLES |
200 |
9 |
|
|
10/* Переменные ----------------------------------------------------------------*/
11DAC_HandleTypeDef hdac;
12TIM_HandleTypeDef htim6;
13DMA_HandleTypeDef hdma_dac_ch1;
14
15/* Прототипы функций ---------------------------------------------------------*/
16static void MX_DAC_Init(void);
17static void MX_TIM6_Init(void);
18
19int main(void) {
20uint16_t IV[SAMPLES], value;
22HAL_Init();
23Nucleo_BSP_Init();
25/* Инициализация всей сконфигурированный периферии */
26MX_TIM6_Init();
27MX_DAC_Init();
29for (uint16_t i = 0; i < SAMPLES; i++) {
30value = (uint16_t) rint((sinf(((2*PI)/SAMPLES)*i)+1)*2048);
31IV[i] = value < 4096 ? value : 4095;
32 |
} |
33 |
|
34HAL_DAC_Init(&hdac);
35HAL_TIM_Base_Start(&htim6);
36HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)IV, SAMPLES, DAC_ALIGN_12B_R);
38while(1);
39}
40
41 /* Функция инициализации ЦАП */
Цифро-аналоговое преобразование |
401 |
42void MX_DAC_Init(void) {
43DAC_ChannelConfTypeDef sConfig;
44GPIO_InitTypeDef GPIO_InitStruct;
46 |
__HAL_RCC_DAC1_CLK_ENABLE(); |
47 |
|
48/**Инициализация ЦАП */
49hdac.Instance = DAC;
50HAL_DAC_Init(&hdac);
51
52/**Конфигурация канала OUT1 ЦАП */
53sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
54sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
55HAL_DAC_ConfigChannel(&hdac, &sConfig, DAC_CHANNEL_1);
57/**Конфигурация GPIO ЦАП
58PA4 ------> DAC_OUT1
59*/
60GPIO_InitStruct.Pin = GPIO_PIN_4;
61GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
62GPIO_InitStruct.Pull = GPIO_NOPULL;
63HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
65/* Инициализация DMA периферии*/
66hdma_dac_ch1.Instance = DMA1_Channel3;
67hdma_dac_ch1.Init.Direction = DMA_MEMORY_TO_PERIPH;
68hdma_dac_ch1.Init.PeriphInc = DMA_PINC_DISABLE;
69hdma_dac_ch1.Init.MemInc = DMA_MINC_ENABLE;
70hdma_dac_ch1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
71hdma_dac_ch1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
72hdma_dac_ch1.Init.Mode = DMA_CIRCULAR;
73hdma_dac_ch1.Init.Priority = DMA_PRIORITY_LOW;
74 |
HAL_DMA_Init(&hdma_dac_ch1); |
75 |
|
76__HAL_LINKDMA(&hdac,DMA_Handle1,hdma_dac_ch1);
77}
78
79
80/* Функция инициализации TIM6 */
81void MX_TIM6_Init(void) {
82TIM_MasterConfigTypeDef sMasterConfig;
84 |
__HAL_RCC_TIM6_CLK_ENABLE(); |
85 |
|
86htim6.Instance = TIM6;
87htim6.Init.Prescaler = 0;
88htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
89htim6.Init.Period = 4799;
90HAL_TIM_Base_Init(&htim6);
91