Руководство по использованию обычных таймеров STM32 Печать
Добавил(а) microsin   

Таймер - очень важное периферийное устройство в наборе внутренней аппаратуры микроконтроллера. Количество таймеров и их функциональных возможностей отличается от одного семейства микроконтроллеров STM32 к другому, однако все же у большинства таймеров есть общие функции и рабочие режимы.

Таймер STM32 разрабатывался как краеугольный камень большинства встраиваемых приложений: он используется для самых разных задач от управления двигателями до генерации периодических событий в приложениях. Спецификации таймера доступны во всех руководствах STM32, и информации по таймерам очень много из-за их широких функциональных возможностей.

Назначение этого руководства (перевод [1]) - дать простое и ясное описание базовых функций и рабочих режимов таймеров STM32 общего назначения. Это так называемые general-purpose таймеры (сокращенно GP). Этот документ сопровождает спецификации периферийных устройств таймеров STM32, доступных в руководстве по каждой конкретной серии микроконтроллеров STM32.

Примечание: расшифровку некоторых непонятных терминов и сокращений можно найти в статье [5].

Этот документ поделен на 2 основные части:

• Первая часть представляет базовые функции таймеров STM32 и простыми словами объясняет некоторые специальные функции, которые обычно используются в приложениях таймеров.
• В последующих секциях уделено внимание описанию определенных сценариев использования таймера STM32. Здесь будет предоставлено более глубокое описание основных функций таймера STM32, используемых для создания демонстрационного приложения. Здесь также будет описана архитектура используемого исходного кода.

В этом документе обсуждаются только простые вопросы, и не будут затронуты такие сложные темы, как приложения управления двигателями. Информация, представленная здесь, применима к следующим сериям микроконтроллеров STM32:

STM32F0, STM32F1, STM32F2, STM32F3, STM32F4, STM32F7, STM32L0, STM32L1, STM32L1W, STM32L4.

Микроконтроллеры STM32 имеют несколько таймеров, которые используются для генерации отсчета времени, подсчета импульсов, измерения длительности импульсов и периодов сигналов, генерации сигналов ШИМ, переключения внешних устройств. Однако в отличие от большинства 8-битных микроконтроллеров, в которых есть 2/3 таймера с ограниченным функционалом, таймеры STM32 весьма изощренные и сложные. Это объясняет тот факт, что описание модулей таймеров занимает примерно 25% даташита любого STM32.

Перед тем, как начать рассматривать таймеры STM32, следует заметить, что они слишком сложны, чтобы в одной статье рассмотреть все их функции. Поэтому здесь мы рассмотрим базовые вопросы работы с таймерами, что позволит начать их использовать. Полную информацию ищите в даташите на конкретную модель микроконтроллера.

[Классификация таймеров STM32]

Таймеры микроконтроллеров STM32 можно поделить на следующие категории:

• Продвинутые (Advanced Timers)
• Общего назначения (General Purpose Timers, сокращенно GP)
• Базовые (Basic Timers)

Из этих трех типов таймеров первые два будут общими для всех моделей STM32. Последний третий тип доступен только в старших моделях. Количество таймеров определенного класса также меняется в зависимости от емкости или размера микроконтроллера STM32. Например, у STM32F103C8T6 есть один продвинутый таймер, в то время как у STM32F103VET6 два продвинутых таймера. Библиотека STM32CubeMX может использоваться для определения того, какие таймеры доступны в имеющейся модели микроконтроллера, если Вы не хотите заблудиться в большом массиве документации.

В таблице ниже приведены основные функциональные параметры таймеров различных типов.

Тип таймера Таймер Разр. счетчика Направление счета Коэф. прескал. DMA Каналы Capt./Comp. Компл. выходы
Продвинутый TIM1, TIM8 16 бит Вверх, вниз, в двух направлениях 1..65535 Есть 4 Есть
GP TIM2, TIM5 32 бита Нет
TIM3, TIM4 16 бит
TIM9 16 бит Только вверх Нет 2
TIM10, TIM11 16 бит 1
TIM12 16 бит 2
TIM13, TIM14 16 бит 1
Базовый TIM6, TIM7 16 бит Есть 0

General purpose (GP) таймеры имеют все функции стандартного модуля таймера-счетчика, они почти такие же, как в большинстве 8-битных микроконтроллеров. GP-таймеры могут использоваться для любых связанных с отсчетом времени и подсчетом событий целей, в том числе и генерация ШИМ и захват импульсов. Обычно в микроконтроллере STM32 больше всего именно таймеров GP, чем таймеров других классов. Изучение GP-таймеров позволяет лучше понять базовые концепции.

У базовых таймеров нет каналов ввода/вывода для захвата входных импульсов (событий) и генерации ШИМ, поэтому такие таймеры используются только для целей отсчета времени. Базовые таймеры доступны только в старших моделях STM32, и это самый простой класс таймеров.

Продвинутые таймеры в основном похожи на GP-таймеры, но имеют дополнительные возможности по генерации комплементарных сигналов ШИМ, а также формировать сигнал торможения и фазы ШИМ с "мертвым" интервалом, предотвращающим сквозные токи силового моста (dead-time). Эти функции полезны для приложений, связанных с управлением двигателями, с силовыми инверторами, системами SMPS и другими задачами, связанными с источниками питания электроники и управлением мощностью. В большинстве микроконтроллеров STM32 есть как минимум один такой таймер. В старших моделях STM32, продвинутых таймеров может быть два.

Каждый таймер в микроконтроллере STM32 не зависит от других, и поэтому не использует никакие общие ресурсы. Единственное, что общее между таймерами, это типы регистров, принципы именования регистров и общий принцип работы. С очень малыми исключениями модули таймеров более или менее совместимы по всем семействам микроконтроллеров STM32. Например, Вы не найдете значительных различий в аппаратуре таймеров при миграции проекта с серии STM32F1xx на серию STM32F4xx. Это может быть совсем не так для других аппаратных устройств - портов GPIO, ADC, и т. п.

В таблице показано наличие таймеров разных классов в семействам микроконтроллеров STM32.

Тип таймера
STM32F0 STM32F101, 102, 103, 105, 107 STM32F100 STM32L1 STM32F2, STM32F4 STM32F30x, STM32F3x8 STM32F37x
Продвинутый TIM1 TIM1 TIM1 - TIM1 TIM1 -
- TIM8 - - TIM8 TIM8 -
- - - - - TIM20 -
GP 16 бит - TIM2 TIM2 TIM2 - TIM2 TIM2
TIM3 TIM3 TIM3 TIM3 TIM3 TIM3 TIM
- TIM4 TIM4 TIM4 TIM4 TIM4 TIM4
- TIM5 TIM5 - - - TIM5
- - - - - - TIM19
32 бита TIM2 - - - TIM2 TIM2 TIM2
- - - - TIM5 - TIM5
Базовый TIM6 TIM6 TIM6 TIM6 TIM6 TIM6 TIM6
- TIM7 TIM7 TIM7 TIM7 TIM7 TIM7
- - - - - - TIM18
1 канал - TIM10 - TIM10 TIM10 - -
- TIM11 - TIM11 TIM11 - -
- TIM13 TIM13 - TIM13 - TIM13
TIM14 TIM14 TIM14 - TIM14 - TIM14
2 канала - TIM9 - TIM9 TIM9 - -
- TIM12 TIM12 - TIM12 - TIM12
1 канал с комплементарным выходом TIM15 - TIM15 - - TIM15 TIM15
2 канала с комплементарным выходом TIM16 - TIM16 - - TIM16 TIM16
TIM17 - TIM17 - - TIM17 TIM17

[Обзор таймеров]

Обычно большинство таймеров STM32 состоит из 16-битного счетчика с автоматической загрузкой и 16-битного прескалера. Прескалер отвечает за деление приходящего тактового сигнала согласно потребностям приложения. Функция автоматической загрузки счетчика работает почти так же, как мы привыкли видеть в 8-битных микроконтроллерах, с единственным исключением. В 8-битных MCU старой школы нам нужно было перезагрузить таймер после каждого прерывания или после каждого переполнения таймера. Это не требуется в таймерах STM32, так как обрабатывается автоматически.

В отличие от многих других MCU, в которых таймеры обычно считают на увеличение (на инкремент), таймеры STM32 могут считать вверх, вниз или вверх/вниз относительно среднего значения. Однако в большинстве приложений традиционно и предпочтительно используется счет вверх.

За исключением базовых таймеров, все таймеры STM32 имеют 4 независимых канала ввода/вывода (I/O channels TIMx_CH1 .. TIMx_CH4). Они могут использоваться следующим образом:

• Input Capture (захват внешних событий)
• Output Compare, или PWM (ШИМ)
• One Pulse Mode (режим генерации одного импульса)

Таймеры могут тактироваться либо от внутреннего источника тактов (тактового генератора RC или от генератора, стабилизированного внешним кварцем), или от внешнего источника тактов. Внешние источники тактирования:

• External Mode 1 (сигнал на выводах TI1 и TI2)
• External Mode 2 (сигнал на выводе ETR)
• Internal Trigger (ITRx)

События прерывания и DMA происходит в следующих ситуациях:

• Обновление: переполнение при счете вверх (overflow) или обнуление при счете вниз (underflow), инициализация счетчика, другие события.
• Триггер: старт счета, остановка счета, инициализация счетчика, другие события.
• Input Capture / Output Compare.
• Другие события.

Таблица ниже дает обзор на общие функции таймеров STM32.

Тип таймера

Разр. счетчика
Счет
DMA
Каналов
Функц. сравн.
Синхронизация
Master Slave
Продвинутый 16 бит Вверх, вниз и с
выравниванием
по центру
Есть 5 3 Есть Есть
GP 16 бит, 32 бита(1) Есть 4 0 Есть Есть
Базовый 16 бит Только вверх Есть 0 0 Есть -
1 канал 16 бит - 1 0 Есть (сигнал OC) -
2 канала 16 бит - 2 0 Есть Есть
1 канал с комплементарным выходом 16 бит Есть 1 1 Есть (сигнал OC) -
2 канала с комплементарным выходом 16 бит Есть 2 1 Нет Нет

Примечание (1): TIM2 и TIM5 это 32-битные счетчики в сериях STM32F2 и STM32F4, устройствах STM32F303xB, STM32F303xC, STM32F303xD, STM32F303xE и STM32F3x8.

Из всей этой информации видна универсальность таймеров STM32, и по этой причине они не очень просты для освоения начинающими программистами.

[Регистры таймера]

Перед тем, как мы начнем программировать, следует обратить внимание на возможно наиболее сложный набор регистров микроконтроллера STM32, относящийся к модулям таймера-счетчика. В конкретном приложении все эти регистры могут не понадобиться, и чтобы упростить их использование, мы просто обсудим их назначение для определенной задачи. Некоторые регистры нужны будут всегда, однако некоторые только для таких задач, как input capture / output compare. Еще одна важная вещь, которую стоить отметить - все регистры в ядре микроконтроллера ARM имеют разрядность 32 бита, и для модулей таймеров и многих других периферийных устройств многие биты в этих регистрах зарезервированы (т. е. они не используются, но могут использоваться в будущих моделях микроконтроллеров). Это упрощает обработку бит. Чтобы еще больше упростить кодирование, в этом руководстве будут использоваться собственные определения и функции, подобные тем, что находятся в библиотеке SPL от ST. Библиотеки MikroC также используют похожий подход к кодированию.

Ниже в таблице качестве справочника приведена карта регистров модуля таймера.

STM32 timer registers map

При разработке кода для таймеров следует учитывать следующие моменты:

• Перед использованием модули таймеров должны быть сначала разрешены установкой соответствующих бит в регистре RCC_APBx_ENR. Работа отдельных счетчиков, функций DMA и прерываний разрешается после настройки всего остального.
• Сразу после сброса при включении питания каждый бит внутренних регистров микроконтроллера STM32 устанавливается в свое значение по умолчанию. Для регистров таймера значение по умолчанию это все нули, что означает запрет всех функций. Таким образом, не нужно эти биты принудительно очищать при старте (точно так же обстоят дела и с любым другим периферийным устройством STM32). Однако если Вам нужно поменять кое-что на лету, то лучше всего сначала сбросить все настройки, чтобы не попасть в ситуацию непредсказуемого поведения таймеров и обслуживающего их кода.
• Таймеры не могут использоваться в качестве часов реального времени (RTC) из-за определенных факторов, и они не всегда позволяют хранить и отслеживать точное время. Если точность не очень важна, то таймеры могут использоваться в качестве обычного средства отслеживания реального времени в программе. Без сомнений таймеры более точны и эффективны, чем тупые пустые циклы задержки, но они не очень хороши для использования вместо выделенной аппаратуры RTC.
• Когда ножки портов GPIO используются для функций режима capture/compare, тщательно изучите, какие можно использовать для этой цели выводы I/O, потому что иногда выводы I/O, связанные с этими функциями, могут быть привязаны к какой-то другой функции. Используйте STM32CubeMX, чтобы найти, какие выводы могут использоваться с каждым конкретным таймером.
• Может быть разрешен и использоваться блок AFIO для переназначения выводов I/O, поскольку capture/compare это альтернативные функции обычных портов ввода/вывода GPIO. Блок AFIO должен быть разрешен даже если переназначение не используется. Выводы GPIO должны быть сконфигурированы как AFIO для режимов compare/output.
• Когда используется режим захвата по входу (input capture), обеспечьте условия, чтобы максимальное входное напряжение поступающего сигнала не превысило максимально допустимого значения. Не все, но большинство ножек выводов I/O позволяют подавать входной уровень 5 вольт при питании подсистем ввода/вывода от стандартных 3.3 вольта (про такие выводы портов говорят, что они обладают функцией "5V tolerant"). Однако все равно не рекомендуется не превышать уровень напряжения питания VDD, который обычно составляет 3.3V.
• При использовании режима сравнения для генерации выходного сигнала (output compare mode) убедитесь, что нагрузка наподобие светодиода или оптронного изолятора не приводила к слишком большому току через драйвер выхода. Очень важно, чтобы ток через вывод микроконтроллера не превышал предел, указанный в спецификации на микроконтроллер. Если выходной ток недостаточен, то применяйте усиливающие транзисторные ключи и микросхемы буфера.
• Внутренний генератор микроконтроллеров STM32 довольно точный (с допуском 1%), однако если нужна намного более высокая точность, то лучше всего использовать калиброванные внешние генераторы или внешние точные кварцевые резонаторы.
• Учитывайте влияние на тактовую частоту прескалеров системных тактов, умножителей и источников тактирования.
• Помните, что периферийные устройства, подключенные к шине APB2, могут работать на максимальной системной тактовой частоте, в то время как периферийные устройства шины APB1 ограничены половиной этой скорости. Таким образом, таймеры APB1 не могут работать на той же тактовой частоте, как таймеры APB2.
• Поскольку внутренняя частота тактов каждого таймера зависит от его шины APB, то Вы должны знать, к какой шине APB подключен используемый таймер. Утилита Timer Calculator от MikroElektronika (MikroE) позволит учитывать эти факторы для реальной тактовой частоты микроконтроллера. Используйте редактор проекта STM32CubeMX, чтобы определить скорости шины APB. Ниже на картинке приведен пример, здесь таймеры APB1 получают такты 36 МГц, в то время как таймеры APB2 тактируются от 72 МГц.

[Отсчет времени]

Отсчет текущего времени в программе - основной режим таймера. В этом режиме работы таймер программируется так, чтобы он вызывал периодически генерируемые события с равными интервалами времени (так называемый генератор временной базы). Для этой цели мы можем использовать любой таймер, однако лучше всего использовать или базовый таймер (если он присутствует), или GP-таймер.

Для создания генератора временной базы рационально использовать метод прерываний. Сначала надо определиться, какой таймер использовать, и какая должна быть частота прерываний таймера. Затем нужно будет рассчитать значения для прескалера (PSC), регистра автоперезагрузки (auto-reload register, ARR) и регистра счетчика повторений (repetition counter register, RCR), если последний присутствует. Счетчики повторений доступны только в продвинутых таймерах. Можно использовать следующую формулу для определения частоты срабатывания прерываний:

                         TIMxCLK
Событие обновления = ----------------
                     ((PSC+1)(ARR+1))

RCR будет нулевым кроме случаев, когда он доступен и используется, тогда формула будет следующей:

                             TIMxCLK
Событие обновления = -----------------------
                     ((PSC+1)(ARR+1)(RCR+1))

Частота тактов TIMx зависит от частоты шины APB.

В завершение настройки разрешаются прерывания таймера и работа самого модуля таймера.

Для настройки таймера в качестве генератора базового времени нужно использовать следующие регистры (вместо x подставляется номер таймера):

Регистр управления 1 (TIMx_CR1), смещение адреса 0x00, значение после сброса 0x0000.

Разряд 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Бит Резерв CKD[1:0] ARPE CMS
DIR OPM URS UDIS CEN
Чтение/запись R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W

Регистр разрешения DMA/прерываний (TIMx_DIER), смещение адреса 0x0C, значение после сброса 0x0000.

Разряд 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Бит Рез. TDE Рез. CC4DE CC3DE CC2DE CC1DE UDE Рез. TIE
Рез. CC4IE CC3IE CC2IE CC1IE UIE
Чтение/запись R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W

Прескалер (TIMx_PSC), смещение адреса 0x28, значение после сброса 0x0000.

Разряд 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Регистр PSC[15:0]
Чтение/запись R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W

Регистр автозагрузки (TIMx_ARR), смещение адреса 0x2C, значение после сброса 0x0000.

Разряд 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Регистр ARR[15:0]
Чтение/запись R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W R/W

[Базовые рабочие режимы GP-таймеров]

Все микроконтроллеры STM32 оборудованы как минимум одним таймером, и многие из них имеют в своем составе периферии таймеры нескольких типов. В этом документе рассматриваются обычные таймеры (general purpose, GP-таймеры). GP-таймеры можно отличить от таймеров других типов по имени в руководстве микроконтроллера STM32.

В документации микроконтроллеров STM32 GP-таймер именуется как "TIMx timer", где "x" может быть любым числом, и это не отражает количество таймеров, встроенных в этот микроконтроллер. Например, микроконтроллеры серии STM32F100 имеют на борту таймер TIM17, однако общее количество таймеров в этом микроконтроллере меньше 17.

В основном через все семейства микроконтроллеров STM32 соблюдается принцип, что таймеры с одинаковым именем имеют один и тот же набор функциональных возможностей, но из этого правила есть несколько исключений. Например таймер TIM1 общий во всех сериях STM32F1, STM32F2 и STM32F4, но для специального случая семейства STM32F30x таймер TIM1 представляет несколько больший набор функций, чем таймер TIM1 в других семействах.

GP-таймеры, встроенные в микроконтроллеры STM32, используют одинаковую основную структуру; они отличаются только уровнем функций, встроенных в определенный таймер.

Периферийные устройства таймеров можно классифицировать следующим образом:

• Продвинутые таймеры, такие как TIM1 и TIM8.
• GP-таймеры, наподобие TIM2 и TIM3.
• Таймеры с облегченной конфигурацией, такие как TIM9, TIM10, TIM12 и TIM16.
• Базовые таймеры, такие как TIM6 и TIM7.

Апноут AN4013 [2] дает подробное описание периферийных устройств таймеров STM32 по всем различным семействам микроконтроллеров STM32.

TIM1. На рис. 1 блок-схемы таймера TIM1 показаны его четыре основных блока:

1. Блок контроллера master/slave.
2. Блок базы времени.
3. Блок каналов таймера.
4. Блок функции Break.

AN4776 TIM1 block diagram fig01

Рис. 1. Блок-схема внутреннего устройства таймера TIM1.

Блок контроллера master/slave. Блок master/slave предоставляет блок базового времени, отсчитывающий импульсы тактов (например CK_PSC), а также сигнал управления направлением счета. Этот блок в основном предоставляет управляющие сигналы для блока базового времени.

Контроллер master/slave применяет правильную конфигурацию счета для блока базового времени, основываясь на конфигурации master/slave; он также оценивает реальный статус счета.

Например, если таймер сконфигурирован в одном из режимов энкодера путем записи в управляющее битовое поле SMS регистра TIMx_SMCR, то сигнал подсчитываемых импульсов и сигнал управления направлением счета будет вычисляться на основе состояния входных сигналов фаз энкодера TI1FP1 и TI2FP2.

Контроллер master/slave обрабатывает синхронизацию между таймерами. Этот блок может быть сконфигурирован для вывода сигнала синхронизации (сигнал TRGO) рядом с определенным внутренним событием таймера. Он может быть сконфигурирован также для управления счетчиком базового времени в функции внешних событий (наподобие внутренних событий других таймеров или внешних сигналов).

Можно сконфигурировать один slave-таймер для инкремента своего счетчика, базируясь на событиях master-таймера, таких как его обновление. В этом примере событие master-таймера сигнализирует блок контроллера master/slave. Этот управляющий блок использует сигнал выхода master-таймера TRGO. Сигнал выхода master-таймера TRGO подключается как входной сигнал slave-таймера TRGI. Блок контроллера master/slave slave-таймера конфигурируется для использования входного сигнала TRGI в качестве источника тактов для инкремента счетчика таймера slave-таймера.

Не у всех таймеров STM32 есть функция контроллера master/slave. В таймере TIM1, который дан для примера, встроен полный функционал master/slave; в сравнении с ним базовые таймеры TIM6 и TIM7 имеют самый простой контроллер master/slave. У контроллера master/slave таймеров TIM6 и TIM7 нет управляющего поля бит.

Для таймеров TIM6 и TIM7 счетчик базы времени всегда считает вверх, без сброса содержимого по внешним событиям. Нельзя их тактировать ни от другого источника тактов, ни от внутренних тактов.

Блок базы времени. Блок базы времени сделан на основе счетчика вместе с каскадом прескалера и счетчиком повторений. Тактовый сигнал поступает в блок базы времени, проходя через каскад прескалера перед тем, как достичь счетчика базы времени.

В зависимости от содержимого регистра прескалера таймера TIMx_PSC, частота считаемых импульсов может быть снижена перед тем, как достичь стадии счетчика. Сигнал на выходе прескалера является тактовым сигналом счета, который поступает на каскад счетчика.

Счетчик таймера управляется двумя регистрами:

• TIMx_CNT, используется для чтения и записи содержимого счетчика таймера.
• TIMx_ARR, содержит значение для автоматической перезагрузки счетчика таймера.

Автоматическая перезагрузка счетчика работает следующим образом. Если счетчик таймера считает вверх, и достиг значения содержимого регистра TIMx_ARR, то счетчик таймера сбрасывается и начинается новый цикл счета. Если счетчик считает вниз, и достиг нуля, то в счетчик загружается значение из регистра TIMx_ARR, и начинается новый цикл счета.

Каждый раз, когда начинается новый цикл счета, срабатывает "событие обновления" таймера, пока счетчик повторений (repetition counter) равен 0. Если счетчик повторений не равен 0, то событие обновление не сработает, но перезапустится новый цикл счета, и содержимое счетчика повторений уменьшится на 1. Когда содержимое счетчика повторений достигнет нуля, произойдет событие обновления, и в счетчик повторений загрузится значение, сохраненное в регистре TIMx_RCR.

Не у всех таймеров STM32 есть счетчик повторений. Если его нет, то таймер ведет себя так, как если бы счетчик повторений был всегда равен 0.

Блок канала таймера. Каналы таймера это рабочие элементы таймера, с помощью них таймер взаимодействует с внешним аппаратным окружением. В целом каналы таймера отображаются на внешние выводы микроконтроллера STM32, с некоторыми исключениями, такими как каналы 5 и 6 таймера TIM1 семейства микроконтроллеров STM32F30x. Канал таймера, отображенный на вывод микроконтроллера STM32, может использоваться либо как вход, либо как выход.

Когда вывод сконфигурирован как выход, канал используется для генерации сигналов. Пока канал сконфигурирован в режиме выхода, содержимое регистра канала TIMx_CCRy сравнивается с содержимым счетчика таймера. На основе этого постоянного логического сравнения и сконфигурированного подрежима выхода (наподобие PWM1 mode или Inactive mode), канал таймера либо устанавливает, либо сбрасывает флаг OCyREF, и его значение поступает на каскад выхода канала. Каскад выхода применяет набор уточняющих операций к сигналу OCyREF, базируясь на наборе сконфигурированных параметров (наподобие полярности канала или генерации интервала dead-time, и других параметров).

Выходной сигнал каскада выхода отображается на выводы микроконтроллера как их альтернативная функция порта. Обратите внимание, что некоторые каскады выхода каналов таймера, как показано на рис. 2, могут быть организованы как два комплементарных сигнала (это используется для управления плечами силового моста).

AN4776 timer channel output fig02

Рис. 2. Блок-схема канала таймера, когда он сконфигурирован на вывод.

Управляющие битовые поля для такого выходного каскада обеспечивают средства настройки каждого выходного сигнала по отдельности (наподобие разрешения/запрета сигнала на выходе или настройки полярности).

Когда канал сконфигурирован на вход, он может использоваться для запоминания меток времени в моменты переходов уровня внешнего сигнала - либо по его нарастанию уровня, либо по спаду, либо по обоим перепадам. Для поддержки этой функции вход канала отображается на один из выводов микроконтроллера.

Некоторые входы канала таймера также могут отображаться на некоторые внутренние сигналы чипа, например на выход генератора - с целью калибровки частоты. На вход канала таймера TIy обрабатывается схемой кондиционирования сигнала, что показано на рис. 3. Схема кондиционирования включает каскад фильтрации и детектор перепада. Каскад фильтра вырезает импульсы, длительность которых меньше сконфигурированной. Детектор перепада определяет, присутствует ли на нужном входе после фильтрации активный перепад уровня.

AN4776 timer channel input fig03

Рис. 3. Блок-схема канала таймера, когда он сконфигурирован на ввод.

Конфигурация активного перепада устанавливается путем настройки битовых полей полярности в регистре TIMx_CCER. Схема кондиционирования выводит два сигнала:

• TIyFPy: входной сигнал таймера TIy, который был отфильтрован, и у которого был детектирован активный перепад в зависимости от полярности канала таймера “y”.
• TIyFPz: всегда входной сигнала таймера TIy, который был отфильтрован, но на котором был определен активный перепад в зависимости от полярности канала таймера “z”.

Сигнал TIyFPz перенаправляется на вход прескалера канала “z”, где сигнал TIzFPy перенаправляется на вход прескалера канала “y”, как показано на рис. 3 выше. Перекрестное переключение фильтрованных входных сигналов очень полезно для фиксации моментов времени как для нарастания уровня, так и для спада уровня входного сигнала (применяется для реализации приложений оценки ШИМ).

Каждый канал таймера может быть сконфигурирован в один из трех возможных режимов. Каждый входной режим соответствует одному из возможных трех входов мультиплексора прескалера, подключенного к прескалеру канала таймера. Битовое поле CCyS влияет на поведение таймера, если он сконфигурирован в режиме вывода (наподобие CCyS[1:0] = 00), или если он сконфигурирован в одном из режимов ввода (когда биты CCyS[1:0] отличаются от 00).

Те же самые регистры таймера TIMx_CCMRn (n может быть любым числом, но обычно это 1 или 2) используются для конфигурирования каналов таймера на ввод или вывод. Некоторые управляющие битовые поля регистров TIMx_CCMRn по-разному интерпретируются в зависимости от конфигурации канала, режимов ввода или вывода.

Прескалер канала таймера может быть сконфигурирован для снижения частоты активных перепадов, детектированных на входе таймера TIy. Детектирование активного перепада на выходе прескалера приводит к переносу содержимого счетчика таймера в регистр “y” канала таймера TIMx_CCRy.

Содержимое регистра “y” канала таймера TIMx_CCRy это метка времени последнего детектированного активного перепада на выходе прескалера канала “y”. Это метка времени последнего детектированного активного перепада на входе таймера TIy, если прескалер канала “y” сконфигурирован не снижать частоту входного сигнала (например, когда коэффициент деления прескалера = 1 и сигнал проходит через прескалер без изменений, т. е. прескалер отключен).

Блок функции Break. Функция Break встроена только в те таймеры, у которых есть комплементарные выходы. Другими словами, только те таймеры, у которых как минимум один канал снабжен комплементарными выходами, имеет функцию Break.

Функция Break действует на выходном каскаде каналов таймера в режиме вывода. Как только на входе break детектирован активный перепад, выходы каналов таймера, сконфигурированного в режиме вывода, либо выключаются, либо переводятся в предопределенное безопасное состояние. Функция Break обычно используется для реализации безопасного отключения силового моста в инверторах блоков питания в случае появления каких-то технических аномалий (например, перегрузки по току).

В апноуте AN4277 [3] предоставлено подробное описание работы функции Break в различных семействах микроконтроллеров STM32.

[Примеры конфигурирования]

Ниже представлены куски кода на языке C, показывающие базовые конфигурации таймера STM32.

Конфигурация базы времени. Реализация точного аппаратного цикла задержки на таймере TIM6. Можно для той же цели использовать любой другой таймер STM32, но был выбран TIM6, поскольку он не самый сложный. Другие таймеры могут быть зарезервированы для более сложных задач.

#define ANY_DELAY_RQUIRED 0x0FFF
 
/* Очистка флага события обновления: */
TIM6->SR = 0
 
/* Установка требуемой задержки: */
// Прескалер таймера установлен в значение 0:
// TIM6->PSC = 0;
// Если требуется более длинная задержка, то регистр прескалера
// может быть установлен в другое значение:
TIM6->ARR = ANY_DELAY_RQUIRED;
 
/* Запуск счета таймера */
TIM6->CR1 |= TIM_CR1_CEN;
 
/* Цикл до момента, когда установится флаг события обновления: */
while (!(TIM6->SR & TIM_SR_UIF));
 
/* Требуемая задержка времени истекла, дальше может быть
   исполняемый код пользователя. */
...

Конфигурация канала на ввод.

// Переменная для сохранения метки времени последнего
// детектированного активного перепада на входе:
uint32_t TimeStamp;
 
// Состояние сброса регистра ARR для таймера TIM3 равно
// 0x0000FFFF. Это должно подойти для нашего примера.
// Если нужно поменять значение ARR, то раскомментируйте
// следующую строку кода:
// TIM3->ARR = ANY_VALUE_YOU_WANT;
 
// Настройка канала 1 таймера TIM3 на ввод.
// Биты CC1S доступны на запись только когда канал 1 выключен.
// После сброса все каналы выключены.
TIM3->CCMR1 |= TIM_CCMR1_CC1S_0;
 
// Разрешение канала 1 таймера TIM3 и сохранение конфигурации
// канала по умолчанию (состояние после сброса) для полярности
// канала.
TIM3->CCER |= TIM_CCER_CC1E;
 
// Старт счета таймера:
TIM3->CR1 |= TIM_CR1_CEN;
 
// Очистка флага события захвата (Capture event flag)
// для канала 1:
TIM3->SR = ~TIM_SR_CC1IF;
 
// Цикл, пока не установится capture event flag:
while (!(TIM3->SR & TIM_SR_CC1IF));
 
// Был детектирован активный перепад, сохранение метки времени:
TimeStamp = TIM3->CCR1;

Конфигурация канала на вывод.

// Значение после сброса регистра ARR для таймера TIM3 равно
// 0x0000FFFF. Это должно подойти для нашего примера. Если
// нужно установить другое значение, то раскомментируйте
// следующую строку:
// TIM3->ARR = ANY_VALUE_YOU_WANT;
 
// Канал 1 таймера TIM3 после сброса сконфигурирован на вывод,
// TIM3->CC1S равен 0.
// Для выбора режима вывода ШИМ PWM2 битовое поле OC1M
// устанавливается в значение 111:
TIM3->CCMR1 |= TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
 
// Установка скважности 50%:
TIM3->CCR1 = TIM3->ARR / 2;
 
// По умолчанию после сброса предзагрузка для канала 1 выключена.
// Чтобы изменить это, раскомментируйте следующую строку:
// TIM3->CCMR1 |= TIM_CCMR1_OC1PE;
 
// Разрешение канала 1 таймера TIM3 и сохранение конфигурации
// по умолчанию (состояние после сброса) для полярности канала:
TIM3->CCER |= TIM_CCER_CC1E;
 
// Старт счетчика таймера:
TIM3->CR1 |= TIM_CR1_CEN; 

[Продвинутые функции таймера STM32]

В этом разделе приведено детальное описание некоторых общих функций таймера, после этого будут даны примеры.

Каскад фильтрации. Входы таймера (наподобие входа ETR или входов каналов) снабжены каскадом фильтрации, который может быть активирован для отбрасывания внешних импульсов сигнала, длительность которых меньше желаемого порога.

Максимальная длительность фильтруемых импульсов зависит от двух параметров:

• Конфигурация каскада фильтрации относительно определенного входа таймера. Например, каскад фильтрации входа ETR конфигурируется битами ETF[3:0] регистра TIMx_SMCR. Конфигурация каскада входной фильтрации подразумевает выбор источника тактов для оцифровки входных импульсов, установки частоты выборки тактов и установки минимального времени длительности допустимого импульса в единицах тактов уже сконфигурированной частоты оцифровки входного сигнала.
• В случае источника тактов FDTS в качестве тактовой частоты оцифровки, каскад фильтрации настраивается на минимально допустимую длительность проходящего импульса записью значения в поле бит CKD[1:0] регистра TIMx_CR1. Тактовый сигнал FDTS получается из тактового сигнала таймера, и поле бит CKD[1:0] устанавливает соотношение между этими двумя тактовыми сигналами.

Может использоваться один из двух источников тактов в качестве частоты оцифровки входного сигнала для фильтрации, либо сигнал таймера FCK_INT, либо источник тактов FDTS.

Рис. 4 показывает практический пример, где каскад фильтрации активируется для входа таймера ETR. Для этого демонстративного примера настроены следующие параметры:

• Частота тактов таймера FCK_INT = 1 МГц.
• CKD [1:0] = 01. Это означает, что частота тактового сигнала FDTS в 2 раза меньше тактовой частоты сигнала таймера: Fdts = Fck_int/2 = 500 кГц.
• ETF [3:0] = 0100. Это означает, что выбран сигнал тактов FDTS в качестве частоты оцифровки для фильтра, пониженной в 2 раза. Также это означает, что допустимый импульс, который пройдет через фильтр, должен быть как минимум быть длительность 6 тактовых импульсов оцифровки.

Для этого примера любой импульсный сигнал на входе таймера ETR, который короче 6 x Tsampling = 6 x 1 / 250 кГц = 24 мкс, будет отброшен.

AN4776 input signal filtering fig04

Рис. 4. Фильтрация входного сигнала (ETF [3:0]= 0100): FSAMPLING = FDTS/2, N=6.

Функция предзагрузки регистров таймера. Предзагрузка (preload) в контексте таймера STM32 относится к дублированию некоторых регистров таймера или некоторых битовых полей управления. Так как содержимое некоторых регистров таймера и некоторых битовых полей непосредственно влияет на выводимые из каналов таймера формы сигнала, обновление содержимого этих регистров и управляющих битовых полей должно быть четко синхронизировано с событием обновления таймера (update event), которое происходит на начале нового цикла счета. Эта жесткая синхронизация на практике не была бы возможна, если бы не было специальной функции предзагрузки регистров и управляющих битовых полей.

Когда у регистра таймера есть функция предзагрузки, то существует два экземпляра регистров таймера:

• Активный регистр (также называемый теневым регистром): его содержимое используется логикой таймера для генерации выходного сигнала в канале таймера.
• Регистр предзагрузки: этот регистр доступен со стороны программного обеспечения, когда разрешена функция предзагрузки соответствующего регистра.

Если функция предзагрузки выключена, как показано на рис. 5, то вступают в действие две основные характеристики:

• Регистр предзагрузки рассматривается как не существующий.
• Любая попытка доступа на запись в соответствующий регистр со стороны программного обеспечения будет выполнена над активным регистром.

AN4776 Preload disabled fig05

Рис. 5. Механизм предзагрузки регистра канала таймера запрещен.

Если функция предзагрузки включена, как показано на рис. 6, то вступают в действие две основные характеристики:

• Любой доступ на запись в соответствующий регистр выполняется над регистром предзагрузки, в то время как активный регистр не изменяется.
• Как только таймером сгенерируется "update event", содержимое регистра предзагрузки немедленно переносится в активный регистр. Содержимое регистра предзагрузки передается жестко синхронизированным с событием обновления. Другими словами, этот процесс строго синхронен с соответствующем новом цикле формирования выходного сигнала ШИМ.

AN4776 Preload enabled fig06

Рис. 6. Механизм предзагрузки регистра канала таймера разрешен.

Функция предзагрузки доступна для следующих регистров и управляющих битовых полей:

• Auto-reload timer register (TIMx_ARR).
• Timer prescaler register (TIMx_PSC) (его предзагрузка не может быть выключена).
• Timer channel registers (TIMx_CCRy).
• Битовые поля CCxE и CCxNE в регистре таймера TIMx_CCER.
• Битовое поле OCxM в регистрах таймера TIMx_CCMRn.

Функция предзагрузки представляет большой интерес при выводе сигнала ШИМ (PWM) на определенном канале таймера. Уровень на выходе канала зависит от постоянного сравнения между значением счетчика таймера и регистром TIMx_CCRy, по этой причине любое изменение регистра канала таймера может привести к немедленному изменению уровня на выходе таймера. В следствие этого прямая запись в регистр канала посередине периода PWM может привести к генерации случайных сигналов.

Чтобы решить эту проблему, должна быть разрешена функция предзагрузки для соответствующего регистра канала таймера. Когда функция предзагрузки разрешена, любой доступ на запись в регистр канала приведет к записи в регистр предзагрузки, в то время как активный регистр канала останется нетронутым. Это устранит пертурбации генерируемого периода ШИМ.

Как только произойдет событие обновления таймера, содержимое регистра предзагрузки будет передано в активный регистр. Содержимое активного регистра будет использоваться для формирования следующего периода ШИМ для осуществления операции сравнения и определения новой скважности периода ШИМ.

Таким образом, функция предзагрузки гарантирует отсутствие ошибочных периодов ШИМ на выходе таймера, когда осуществляется доступ на запись в соответствующие регистры таймера и битовые поля, которые оказывают непосредственное влияние на формирование ШИМ, особенно это важно посередине периода сигнала ШИМ.

[Тактирование таймера STM32 от внешнего источника]

Таймер STM32 может тактироваться от внешнего источника тактирования, но это не означает, что не нужно тактировать шину APB (advanced peripheral bus). Таймер STM32, синхронизирован внешним тактовым сигналом со своей собственной частотой ядра (которая является тактами APB). Результирующий синхронизированный сигнал тактов поступает на прескалер таймера, который после прескалера идет на счетчик.

Таймер STM32 требует 2 источника сигнала, чтобы постоянно обновлялась временная база (см. рис. 7). Период внешнего сигнала тактов это единица времени, используемая для обновления базы времени таймера.

AN4776 timer sync ext clock fig07

Рис. 7. Синхронизация таймера внешним тактовым сигналом.

Есть два способа синхронизации (или внешнего тактирования) таймера STM32:

• Режим 1 внешнего тактирования: внешний тактовый сигнал поступает на один из входов канала таймера TIx.
• Режим 2 внешнего тактирования: внешний тактовый сигнал поступает на вход ETR (если это реализовано в таймере и доступно).

Рис. 8 показывает прохождение тактового сигнала для обоих этих режимов.

AN4776 clock path ext clock modes fig08

Рис. 8. Распространение тактов для режимов внешнего тактирования.

Блок синхронизации. Перед введением в режимы синхронизации таймера внешним сигналом важно сначала показать механизм синхронизации, реализованный в таймере STM32, когда аппаратура STM32 работает с внешними сигналами. Внешние сигналы это такие сигналы, когда сигнал поступает извне таймера. Этот сигнал может быть как синхронизирован с тактовым сигналом, так и может быть полностью асинхронным.

Таймер должен обрабатывать внешние сигналы, которые могут быть полностью асинхронными, и соответствующим образом подстраивать выходное состояние формируемых сигналов. Таймер также должен быть способен информировать программное обеспечение о метках времени, на которых сигнал определенного таймера меняет свое состояние (например переключение сигнала).

Чтобы обработать полностью асинхронный сигнал, периферийное устройство таймера сначала нуждается в том, чтобы пересинхронизировать свой собственный сигнал тактов. Его может понадобиться пересинхронизировать например с тактовым сигналом логики ядра перед тем, как передать результирующий синхронизированный сигнал в разные субблоки таймера. Это действие защитит логику ядра таймера от проблем метастабильности.

Рис. 9 показывает синоптическую диаграмму для схемы синхронизации, используемой для синхронизации внешних сигналов, поступающих на входы таймера. Схема синхронизации составлена главным образом из двух соединенных каскадом D-триггеров, которые тактируются сигналом ядра таймера. Внешний сигнал приходит на вход первого каскада D-триггера, и синхронизированный сигнал получается на выходе второго каскада D-триггера. Этот блок синхронизации вводит задержку как минимум 2 такта ядра таймера и максимум 3 такта.

AN4776 synchronization block fig09

Рис. 9. Блок синхронизации.

В таймере реализована “первоначальная синхронизация” на всех входах, кроме ETR, где первым идет прескалер, после него сигнал пересинхронизируется.

Как показано формулой ниже, частота входного сигнала должна быть в 3 раза меньше, чем частота тактирования ядра.

FreqTIMCLK ≥ 3 x Freqinputsignal

Режим 1 внешнего тактирования. Когда активирован external clock-source mode 1, любой сигнал, который может быть направлен на внутренний сигнал таймера TRGI, может использоваться также как такты счетчика таймера. Рис. 8 показывает возможные источники тактов для счетчика таймера:

• Входной сигнал ETRF: сигнал ETR после прескалера синхронизируется и затем фильтруется.
• Внутренние сигналы синхронизации таймера (входы ITR).
• Сигнал TI1FD, который является выходом канала 1 таймера, но которые чувствительны к обоим перепадам сигнала (каждый перепад на входе таймера 1 генерирует импульс).
• Входные сигналы TI1FP1 и TI2FP2 синхронизируются, фильтруются, затем подаются соответственно на прескалированные входы таймера TI1 и TI2.

В этой секции рассматривается только external clock mode 1, когда внешний тактовый сигнал подается на таймер через один из его входов, другими словами, когда такты подаются на таймер через входы ETR, TI1 или TI2.

Использование входа ETR для таймера это альтернативная конфигурация для external clock-source mode 2, так что подробно она в этой секции не описывается. Соответствующее руководство содержит правильную конфигурацию для активации этой альтернативы тактирования.

Входы таймера, TI1 и TI2 в качестве источников тактов. Когда активирован external clock mode 1, только входы TI1 и TI2 могут использоваться для подачи тактового сигнала на счетчик таймера. Если в таймере не встроено 4 канала, в этом режиме входы TI3 и TI4 не могут тактировать таймер.

Тактовый сигнал, поступающий на входы таймера TI1 или TI2, сначала кондиционируется перед поступлением на счетчик. Кондиционирование входа осуществляется каскадом внешней синхронизации, затем сигнал проходит через прескалер и каскад фильтрации.

Входной фильтр и прескалер конфигурируются. Канал, связанный с целевым входом таймера, должен быть сконфигурирован как входной; затем те же самые управляющие битовые поля, используемые для конфигурирования входного канала, используются для конфигурирования входа внешнего сигнала тактов.

Ниже показана типовая последовательность конфигурирования входов TI1 или TI2 как входа для внешнего сигнала тактов:

1. Конфигурирование канала, связанного со входом таймера, на который подается внешний тактовый сигнал. Даже при том, что любое значение бит, кроме 00, записанное в поле capture/compare selection (CCxS), установит канал таймера в режим входа, правильное значение для конфигурации CCxS = 01.

Примечание: битовое поле записывается только когда связанный с ним канал таймера запрещен (когда сброшено битовое поле разрешения/запрета для этого канала в регистре TIMx_CCER, CCxE = 0.

2. Конфигурирование полярности активного перепада. Встроенные таймеры в некоторых микроконтроллерах STM32 имеют входы входы, чувствительные к спаду уровня, нарастанию уровня или к обоим перепадам (наподобие серии STM32F2); в других семействах STM32 встроенные таймеры имеют входы, чувствительные только для спада или нарастания уровня (наподобие серии STM32F1). Справочный документ руководства для каждого микроконтроллера STM32 указывает правильное значение для записи в битовые поля управления полярностью. В качестве примера, чтобы настроить вход таймера микроконтроллеров STM32F30x на чувствительность к обоим перепадам, битовые поля полярности для интересующего канала должны быть сконфигурированы как CCxP = 1 и CCxNP = 1.

3. Если необходимо, конфигурирование входного фильтра, связанного с интересующим каналом таймера, чтобы вырезать импульсы с длительностью, меньше чем указанное значение. Порог для отбрасывания или пропуска сходного импульса конфигурируется через битовое поле ICxF[3:0] в регистре TIMx_CCMRx, связанным с используемым каналом таймера.

4. После правильного сконфигурированного входа таймера с требуемыми параметрами, кондиционированный входной сигнал перенаправляется в счетчик таймера. Этот шаг осуществляется путем записи правильного значение в битовое поле выбора триггера TS[2:0], находящееся в регистре TIMx_SMCR. Например, если используется вход TI1 в качестве внешнего тактового входа, то правильная конфигурация должна быть TS[2:0]=101.

5. В завершение активируется режим 1 внешнего тактирования (external clock-source mode 1). Это делается записью правильного значение в битовое поле выбора slave/master (SMS) в регистре TIMx_SMCR. Обратите внимание, что это битовое поле имеет разную ширину для разных семейств микроконтроллеров STM32. Руководство пользователя задает правильное значение для записи в битовое поле SMS, чтобы активировать разные режимы тактирования. Например, для серии STM32F1 поле SMS имеет длину 3-бита и правильное значение для конфигурирования SMS[2:0] = 111, в то время как для микроконтроллеров STM32F30x битовое поле SMS длиной 4 бита, и правильное значение SMS[3:0] = 0111.

6. Установка битового поля CEN в регистре TIMx_CR1, чтобы разрешить счетчик таймера.

Рис. 10 показывает типовую последовательность счета счетчика таймера, когда таймер сконфигурирован для счета вверх. Содержимое счетчика равно null в момент установки битового поля CEN, и таймер получает внешнее тактирование в режиме 1 через вход TI1.

AN4776 timer increment external clock mode 1 fig10

Рис. 10. Инкремент счетчика таймера (external clock mode 1).

Этот пример показывает, что сконфигурирован активный перепад нарастания уровня, где битовые поля управления фильтром и прескалером сохранены в своем значении по умолчанию (в том состоянии, в каком они находятся после сброса). Рис. 10 также показывает эффект каскада ресинхронизации на входе TI1 таймера.

Есть задержка между фронтом нарастания уровня тактового сигнала на входе TI1 таймера и фронтом нарастания уровня внутреннего подсчитываемого сигнала, который поступает на счетчик таймера CK_CNT. В этом примере регистр прескалера TIMx_PSC равен null, поэтому сигнал CK_CNT такой же, как и сигнал CK_PSC (CK_CNT = CK_PSC).

Из-за каскада ресинхронизации требуется, чтобы частота внешних тактов была в 3 раза меньше внутренней частоты тактирования ядра таймера, как показано следующей формулой:

TIMxCLKfreq ≥ 3 x ITxfreq

Режим 2 внешнего тактирования. Когда активирован режим внешнего тактирования, счетчик таймера будет обновляться в моменты детектирования активных перепадов сигнала, поступающего на вход ETR таймера. Для некоторых таймеров определенных семейств STM32 вход ETR не может быть выведен наружу из корпуса микроконтроллера.

Для некоторых ETR вход не отображается на выводы IO микроконтроллера как альтернативная функция. В некоторых других таймерах вход ETR таймера мультиплексируется со входом канала 1 таймера.

Главное достоинство использования режима 2 внешнего тактирования (external clock-source mode 2) в сравнении с режимом 1 в том, что предоставленный внешний сигал может быть равным или даже больше, чем внутренняя частота тактирования ядра таймера (такая как частота шины APB). Это не означает, что счетчик таймера может быть обновлен с частотой выше, чем частота ядра таймера (например, частота инкремента, если таймер сконфигурирован для счета вверх).

Только у входа ETR таймера каскад прескалера находится перед каскадом ресинхронизации. Этот каскад прескалера полностью асинхронен, и может поделить асинхронную входную частоту на коэффициент до 8 раз.

Сигнал на выходе каскада прескалера с именем ETRP передается в каскад ресинхронизации перед подачей его в счетчик таймера. Выход схемы ресинхронизации называется сигналом ETRF. Сигнал ETRP имеет то же самое ограничение, которое накладывается на любые асинхронные сигналы, подаваемые на таймер, т. е. его частота должна быть в 3 раза меньше, чем внутренняя частота тактирования ядра таймера.

Режим 2 внешнего тактирования представляет большой интерес во многих случаях практического применения. Например, нужно подсчитывать количество импульсов, приходящих от определенного датчика, но частота на выходе этого датчика больше, чем частота тактирования ядра таймера. В этом случае прескалер должен быть сконфигурирован таким образом, чтобы снизить частоту входного сигнала с определенным коэффициентом, чтобы частота стала совместима с ограничением каскада ресинхронизации, накладываемым на его входную частоту сигнала. При интерпретации подсчитанного количества импульсов нужно учитывать коэффициент деления, который был внесен прескалером.

Рис. 11 показывает пример, где таймер сконфигурирован в режиме 2 внешнего тактирования, и где сигнал тактов поступает на таймер через вход ETR. В этом примере сигнал внешних тактов выше, чем внутренняя частота тактирования ядра таймера (частота шины APB). Асинхронный прескалер ETR был сконфигурирован для деления входного сигнала на 4 путем установки битового поля ETPS = 10 в регистре TIMx_SMCR.

AN4776 timer increment external clock mode 2 fig11

Рис. 11. Инкремент счетчика таймера (external clock mode 2).

Также рис. 11 показывает задержку между выходом прескалера (сигналом ETRP) и сигналом тактов таймера CK_CNT, используемым для обновления счетчика таймера. Эта задержка вставляется перед каскадом ресинхронизации.

Ниже показана типовая и рекомендуемая последовательность для конфигурирования таймера в external clock-source mode 2:

1. Вычислить максимальную частоту входного сигнала тактов, и выбрать коэффициент деления асинхронного прескалера. Если частота внешнего сигнала в 3 раза меньше, чем внутренняя частота ядра таймера, то использование прескалера необязательно, и он может не использоваться. В случае, когда асинхронный прескалер не используется, битовое поле ETPS должно быть сброшено (это состояние по умолчанию после сброса).

2. Если необходимо, активировать каскад фильтрации, чтобы вырезать импульсы тактов, длительность которых меньше определенного порога. Для дополнительной информации о том, как настроить функцию фильтрации, см. секцию "Каскад фильтрации" выше в этой статье.

3. Сконфигурировать активный перепад внешнего тактового сигнала. Бит ETP устанавливает, на какой перепад будет реагировать счетчик в external clock-source mode 2. По умолчанию после сброса ETP = 0, что определяет активный фронт нарастания уровня внешнего сигнала тактов (т. е. перепад лог. 0 -> лог. 1 внешних тактов приведет к срабатыванию обновления счетчика таймера).

4. Разрешить external clock-source mode 2 установкой бита разрешения внешнего тактирования ECE =1.

5. В завершение нужно обязательно установить бит разрешения счетчика в регистре TIMx_CR1.

Примечание: вход ETR может использоваться также как вход для внешнего тактового сигнала, когда сконфигурирован external clock-source mode 1. Можно одновременно активировать external clock-source mode 1 и external clock-source mode 2, и одновременно использовать их для входа ETR. В этом случае приоритет отдается external clock-source mode 2, и он будет использоваться для подачи тактов на счетчик таймера.

Отличия режима 1 и режима 2 внешнего тактирования. На первый взгляд кажется, что функционал режимов 1 и 2 внешнего тактирование одинаковый, однако тщательное изучение их различий позволяет выделить из специфические характеристики, которые делают каждый режим больше подходящим для специальных случаев применения.

Ниже показаны основные отличия между режимами 1 и 2:

• Можно использовать external source clock mode 1 для обновления счетчика таймера по обоим перепадам внешнего сигнала. Для external clocksource mode 2 это невозможно.

• При использовании external clock-source mode 2, можно подавать такты на таймер от внешнего источника. При этом все еще можно одновременно конфигурировать таймер в одном из совместимых slave-режимов. Например, если требуется считать количество импульсов, генерируемых определенным датчиком в заданный период времени, с повторениями:

   – один из таймеров, наподобие TIMy, настраивается на подсчет импульсов в external clock-source mode 2, генерируемых датчиком.
   – второй таймер, наподобие TIMz, настраивается на генерацию выходного сигнала триггера (trigger-out signal, TRGO), повторяя его через заданный период времени.
   – первый таймер (TIMy) также должен быть сконфигурирован в slave reset mode, и использовать сигнал TRGO второго таймера (TIMz) в качестве триггера для сброса.

Есть только один способ настроить таймер на генерацию выходного импульса TRGO в регулярные интервалы времени - установить регистр таймера TIMx_ARR в определенное значение, чтобы генерировалось периодическое событие обновления (update event).

Событие "update event" может выдать импульс на сигнал таймера TRGO, если установлен master-mode таймера на "update value" (например, в регистре TIMx_CR2 поле бит MMS[2:0] установлено в значение 010).

Таймер может быть сконфигурирован в slave-режиме сброса путем установки правильного значения в поле бит управления подчиненным режимом (slave mode selection, SMS) в регистре TIMx_SMCR (например SMS[2:0] = 100).

Выбор правильного триггера для slave-режима сброса обеспечивается правильным значением управляющего битового поля выбора триггера TS[2:0]. Значение для записи в TS[2:0] зависит от того, какой вход ITR первого таймера (TIMy) соединен внутри кристалла с выходом TRGO второго таймера (TIMz). Руководство пользователя по каждому микроконтроллеру STM32 перечисляет все внутренние соединения между периферийными устройствами таймера.

В этом примере приложения описан один из случаев использования внешнего тактирования таймера. Приложение разработано на основе использования external clock-source mode 2, однако оно может быть легко переделано на использование external clock mode 1.

В приложении сделана базовая реализация счетчика частоты, с ограничением диапазона частот и точности. При разработке были сделаны следующие предположения:

– Микроконтроллер в качестве опорного источника тактов использует свой внутренний высокоскоростной генератор (high-speed internal oscillator, HSI).
– Это приложение используется в условиях, где есть точный источник тактов 10 МГц (например, лабораторный генератор с калиброванным выходом частоты 10 МГц).
– Это демонстрационное приложение поделено на 2 части. Первая часть - частотомер, тактируемый только от внутреннего генератора HSI. Вторая часть - частотомер имеет доступ к относительно более точному источнику тактов 10 МГц, сигнал которого подается на вход ETR.

Вторая часть подчеркивает уточнение измерений частотомера при переходе на более точный источник тактирования.

AN4776 frequency meter fig12

Рис. 12. Общий принцип работы частотомера.

Для запуска этого приложения требуется следующее аппаратное обеспечение:

– Плата разработчика STM32F302 Nucleo (NUCLEO-F302R8).
– Кабель USB для подключения платы Nucleo к PC разработчика (через кабель USB также подается питание на плату).
– Один или несколько генераторов частоты.

Для того, чтобы скомпилировать и отладить исходный код в разных конфигурациях, нужен также набор программного инструментария:

– Среда разработки, поддерживающая отладчик ST-LINK.
– Последняя версия утилиты STM32CubeMX (в момент разработки этого приложения использовалась версия v4.10.1).

Для приложения был выбран таймер TIM2, потому что у него самая большая разрешающая способность счетчика (32 бита), что позволяет больше всего накопить выборок PPM. Был выбран канал 2 для функции захвата по входу (input capture), потому что вывод ETR отображен на канал 1 таймера TIM2.

Идея этого приложения в том, чтобы вычислить период приходящего сигнала, который будет соответствовать разности двух соседних значений регистра CCR2, умноженной на период инкремента счетчика TIM2, после чего вывести частоту и PPM.

         df x 106
ppm = ---------------
            f

Здесь df = fm - f, fm это измеренная частота, f номинальная частота.

[Конфигурация]

Инициализация системных тактов. Инициализация осуществляется в функции main с помощью функции SystemClock_Config() после инициализации библиотеки HAL (HAL_Init).

Конфигурация DMA. DMA используется для копирования значений CCR2 в буфер, чтобы вычислить частоту приходящего сигнала. DMA конфигурируется следующим образом:

• DMA_Stream = DMA1_Stream6
• DMA_Channel = DMA_Channel_3
• Direction (направление передачи) = от периферийного устройства в память
• Incrementation memory = enable (разрешить инкремент адреса заполняемой памяти)
• Peripheral data alignment = alignment word (выравнивание данных периферии по слова)
• Memory data alignment = alignment word (выравнивание данных памяти по размеру слова)
• Mode = normal (нормальный режим DMA)
• FIFO mode = enable (разрешение режима стека FIFO).

AN4776 freq meter with internal HSI fig13

Рис. 13. Архитектура частотомера, тактируемого внутренним генератором HSI.

В этом примере таймер тактируется только от внутреннего генератора HSI с частотой 8 МГц. Измеряемый сигнал проходит через блок синхронизации тактов. Затем на каждом фронте нарастания уровня срабатывает функция захвата таймера, значение счетчика (доступное в регистре CCR2) сохраняет это значение в RAM с помощью DMA. В завершение по формуле вычисляется частота входного сигнала.

AN4776 freq meter with ext clock source mode 2 fig14

Рис. 14. Архитектура частотомера, тактируемого внешним источником тактов (external clock-source mode 2).

В этом примере таймер тактируется калиброванным внешним генератором с частотой 10 МГц. Этот тактовый сигнал проходит через асинхронный прескалер, обеспечивающий условие синхронизации этой тактовой частоты с внутренней частотой ядра таймера.

Измеренный сигнал проходит сначала через блок синхронизации таймера, и затем по каждому перепаду 0 -> 1 сигнала значение счетчика захватывается в регистр CCR2. Затем это значение сохраняется в RAM с помощью DMA. В завершение по формуле вычисляется частота входного сигнала.

[Функция захвата input capture]

Для измерения периода внешнего сигнала таймер используется в режиме захвата по входу (input capture mode). Максимальная частота, которую можно измерить 32-битным таймером, зависит от сигнала тактов TIM2CLK.

Частота внешнего сигнала не измеряется непосредственно, вместо этого она вычисляется по количеству импульсов, подсчитанных таймером за определенный промежуток времени (по такому же принципу работают обычные аппаратные частотомеры, построенные на жесткой логике). Для такой реализации должна быть предоставлена очень точная опорная частота.

После разрешения работы счетчика таймера, когда придет первый фронт опорного сигнала, значение счетчика таймера захватывается и сохраняется в регистре CC2R. Это значение также сохраняется в буфер с помощью DMA, чтобы оно не перезаписалось последующим значением от следующего фронта входного измеряемого сигнала.

AN4776 timing diagram input capture fig15

Рис. 15. Диаграмма времени захвата по входу (input capture).

Прошедшее время между двумя соседними фронтами измеряемого сигнала CC2Rtn - CC2Rtn-1 соответствует длительности периода измеряемого сигнала. Поскольку таймер тактируется от системной тактовой частоты (внутренний RC-генератор HSI), измеренная частота Fизм будет вычисляться по формуле относительно опорной частоты Fref:

Fизм = (CC2Rtn - CC2Rtn-1 ) * Fref

Ошибка (в Гц) вычисляется как абсолютная величина разности между измеренной частотой и типовым значением. Следовательно, ошибка частоты выражается формулой:

Error(Гц) = | Fизм - typicalvalue |

После вычисления ошибки для каждого обрезанного значения ppm вычисляется следующим образом:

        Error x 106
ppm = ----------------
        typicalvalue

В этом примере таймер тактируется частотой 8 МГц (TIM2CLK = 8 МГц), поэтому минимальная частота, которая может быть измерена без переполнения счетчика будет равна:

      TIM2CLK       8 x 106
F = ----------- = ------------ = 0.002 Гц
        ARR        0xFFFFFFFF

Входной сигнал может быть измерен от генератора 1 кГц. Режим input capture конфигурируется следующим образом:

– Внешний сигнал подключен к выводу CH2 таймера TIM2 (ножка порта PA01).
– В качестве активного перепада выбран фронт нарастания уровня.
– Регистр CCR2 таймера TIM2 используется для вычисления значения частоты.

Модуль input capture используется для захвата значения счетчика после детектирования перепада на входе канала 2. Чтобы получить длительность периода внешнего сигнала, нужны два следующие друг за другом захвата. Период вычисляется путем вычитания этих двух соседних значений CCR2.

Когда происходит событие захвата, установится бит CC2IF в регистре TIM2_SR. Если разрешена функция DMA, то будет сгенерирован запрос DMA. Если произошел захват, установится флаг CC2IF, затем установится флаг over sampling CC2OF.

Когда поступает перепад 0 -> 1, текущее значение счетчика (TIM2_CNT) будет записано в TIM2_CCR2. После ожидания следующего перепада 0 -> 1 запишется еще одно значение TIM2_CNT. По двум этим значениям данных мы затем можем вычислить период входного сигнала. Переполнение таймера не разрешено.

[Конфигурация external clock-source mode 2]

Вторая часть этого примера состоит в том, чтобы сохранить эту конфигурации, и поменять источник тактирования таймера на внешний (external source mode 2), когда вывод ETR используется как вход тактов таймера.

Внешний сигнал опорной частоты должен удовлетворять условию синхронизации (здесь fETRP это частота на выходе прескалера ETR):

TIM2Clk ≥ 3 x fETRP

В этом примере частота ядра таймера TIM2 равна частоте шины APB1 и равна 8 MHz, тогда:

         1
fETR =  --- x 8 МГц = 2.66 МГц.
         3

При использовании генератора 8 МГц и асинхронного делителя частоты fETR на 4, получится частота fETRP = 2 МГц, что удовлетворяет условию, чтобы входная частота была в 3 раза меньше частоты ядра таймера 8 МГц.

[Конфигурация TIM2]

// Разрешение тактирования TIM2:
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
// Установка прескалера таймера для получения 8 МГц
// в качестве тактов таймера:
Prescaler = (uint16_t) (SystemCoreClock / 8000000) - 1;
// Сброс регистра SMCR:
TIM2->SMCR = RESET;
 
#ifdef USE_ETR
/*----------------------*/
/* Внешнее тактирование */
/*----------------------*/
// Конфигурирование прескалера ETR на коэфф. деления 4:
TIM2->SMCR |= TIM_ETRPRESCALER_DIV4 |
// Конфигурирование полярности, активный перепад нарастание:
TIM_ETRPOLARITY_NONINVERTED |
// Конфигурирование источником тактов ETR:
                              TIM_SMCR_ECE;
#else
/*-------------------------*/
/* Внутреннее тактирование */
/*-------------------------*/
// Конфигурирование внутреннего тактирования:
TIM2->SMCR &= ~TIM_SMCR_SMS;
#endif
 
// Выбор счета вверх:
TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
 
/*--------------------------------*/
/* Конфигурирование input capture */
/*--------------------------------*/
// Разрешение DMA1:
DMA1_Channel7->CCR |= DMA_CCR_EN;
// Разрешение запроса DMA для TIM Capture/Compare канала 2:
TIM2->DIER |= TIM_DMA_CC2;
TIM2->CCER |= TIM_CCER_CC2E;
// Разрешение TIM2:
TIM2->CR1 |= TIM_CR1_CEN;
 
// Ожидание завершения передачи:
while ((DMA1->ISR & DMA_ISR_TCIF7) == RESET) {} 

После получения 1000 выборок производится вычисление PPM и строится гистограмма (см. ниже).

AN4776 PPM resulting int source clock fig16

Рис. 16. Результат PPM при внутреннем тактирования счетчика.

Распределение значений PPM отличается от 0, и имеет статическое смещение (соответствует погрешности измерения) и динамическое смещение (соответствует точности измерений). Статическое смещение происходит из-за нестабильности HSI (его частота зависит от отклонений техпроцесса производства кристалла MCU). Это систематическая ошибка, и она варьируется от одного микроконтроллера к другому. Динамическое смещение происходит из-за рабочих условий, таких как температура и помехи по питанию.

Любая ошибка из-за разности между актуальной частотой генератора базового времени и номинальной частотой напрямую транслируется в ошибку измерения. Эта разность носит кумулятивный эффект от всех отдельных ошибок частоты генератора базового времени.

Для второй части приложения, когда таймер синхронизирован с внешним более точным источником тактовой частоты, гистограмма на рисунке ниже составлена после получения 1000 выборок и вычисления соответствующего распределения PPM.

AN4776 PPM resulting ext source clock fig17

Рис. 17. Результат PPM при внешнем тактирования счетчика.

Здесь видно, что PPM попадают в 0, потому что все измеренные интервалы времени между фронтами нарастания сигнала одинаковы. Следует отметить, что в этом случае нет видимых ошибок измерения частоты, потому что эталонный генератор опорных тактов правильно откалиброван.

[Firmware]

Программное обеспечение микроконтроллера (firmware) было разработано в средах Keil μVision, IAR Embedded workbench и SYSTEM WORKBENCH. Проект firmware поставляется в виде ZIP-архива [4] (можно при желании найти на сайте st.com) и содержит все подкаталоги и файлы исходного кода (файлы .h и .c), которые составляют ядро приложения.

AN4776 project organization fig18

Рис. 18. Организация проекта.

Firmware содержит все исходные файлы приложения, и соответствующие файлы распределены по следующим папкам проекта:

• Библиотека STM32 MCU HAL (модули в папках Drivers / STM32F3xx_HAL_Driver и Drivers / CMSIS)
• Файл первоначальной настройки ядра микроконтроллера (папка Application / MDK-ARM, модуль ассемблера startup_stm32f302x8.s)
• Слой приложения (папка Application / User, модули stm32f3xx_hal_msp.c, stm32f3xx_it.c, main.c).

[Генерация сигнала из N импульсов с помощью OPM]

Режим одного импульса, one-pulse mode (OPM) в таймере STM32 это функция, которая может быть использована вместе с каналами таймера, сконфигурированными в режим вывода. Это позволяет таймеру генерировать импульс программированной длины после программируемой задержки на каналах таймера, сконфигурированных в режимах PWM1 или PWM2 output compare.

Режим одного импульса активируется установкой бита OPM в регистре TIMx_CR1. Каждый раз, когда установлен управляющий бит OPM и произошло событие обновления таймера, сбросится управляющий бит разрешения счетчика таймера, и счетчик заморозит свое значение на событии обновления. В конфигурации счета вверх регистр счетчика таймера заморозится на значении 0. Для другой конфигурации счета, такой как режим выравнивания по центру и режим счета вниз, см. руководство пользователя, чтобы определить замороженное состояние счетчика.

Если событие обновление каким-то образом замаскировано, то механизм one-pulse не сможет сбросить бит CEN, и счетчик продолжит свою работу. Выходы таймера будут продолжать выводить свои сконфигурированные сигналы.

Можно замаскировать эффект события обновления таймера установкой управляющего бита UDIS. Для получения подробностей по этому биту см. руководство пользователя микроконтроллера. Другой способ маскирования события обновления - сделать содержимое регистра счетчика повторений (repetition counter) не равным 0. Не все таймеры STM32 обладают счетчиком повторений.

С учетом предыдущего условия маскирования и считая, что каждый раз при событии обновления (с эффектом маскирования) счетчик повторений уменьшается на 1, то это поведение может использоваться для автоматической генерации серии импульсов.

Например, чтобы сгенерировать серию из 5 импульсов, счетчик повторений должен быть установлен в значение 4. Первые 4 события обновления будут маскированы, так как счетчик повторений не равен 0. Эти 4 первых событий обновления не сбросят бит управления CEN, но будут каждый раз декрементировать счетчик повторений, пока он не дойдет до 0. Пятое событие обновления сбросит бит CEN, потому что счетчик повторений равен 0. В этой реализации счетчик таймера будет переполнен 5 раз перед тем, как будет запрещен, и сгенерируется последовательность из 5 импульсов.

С полярностью выхода по умолчанию PWM2 output mode выдаст типовую форму импульса, наподобие задержки на заданное время, затем импульс с заданной длительностью. Для инверсной полярности либо должна быть инвертирована полярность выхода, либо должен использоваться PWM1 output mode.

Первый сценарий с полярностью выхода канала по умолчанию взят в качестве примера, и показан ниже на рис. 19. Выводимая форма сигнала характеризуется двумя параметрами: длиной импульса и длиной задержки.

AN4776 example one pulse mode fig19

Рис. 19. Пример работы one-pulse mode.

Интервал TDelay определяется значением, записанным в регистр TIM_CCRx capture/compare таймера. Интервал TPulse определяется разностью между значением, записанным в регистр автозагрузки (auto-reload register, TIMx_ARR) и значением TDelay. Длительность импульса соответствует TIMx_ARR – TIMx_CCRx + 1.

Цель этого демонстрационного приложения - генерировать сигнал, состоящий из определенного количества импульсов на выходе одного из каналов таймера. Это достигается использованием режима одного импульса (one-pulse mode, OPM) и функции счетчика повторений (repletion counter) таймера STM32.

Был выбран таймер TIM1, потому что он удовлетворяет необходимым требованиям.

Для запуска этого приложения требуется следующее аппаратное обеспечение:

– Плата разработчика STM32F302 Nucleo (NUCLEO-F302R8).
– Кабель USB для подключения платы Nucleo к PC разработчика (через кабель USB также подается питание на плату).
– Осциллограф для наблюдения за формируемым сигналом.

Для того, чтобы скомпилировать и отладить исходный код в разных конфигурациях, нужен также набор программного инструментария:

– Среда разработки, поддерживающая отладчик ST-LINK.
– Последняя версия утилиты STM32CubeMX (в момент разработки этого приложения использовалась версия v4.10.1).

AN4776 OPM architecture example fig20

Рис. 20. Пример архитектуры.

В этом приложении таймер тактируется внутренним генератором HSI. Для активации режима одного импульса устанавливается бит OPM в регистре TIMx_CR1. Чтобы получить на выходах N импульсов, в регистр повторений TIMx_RCR должно быть записано значение (N-1).

[Инициализация системных тактов]

Инициализация тактов осуществляется в функции main вызовом функции SystemClock_Config() сразу после инициализации библиотеки HAL (вызова функции HAL_Init). Ниже показан код конфигурации:

// Конфигурирование внутреннего источника тактов.
// Разрешение тактирования TIM1:
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
// Настройка таймера прескалера для получения
// частоты тактов счетчика 1 МГц:
Prescaler = (uint16_t) (SystemCoreClock / 1000000) - 1;
 
// Выбор режима счета вверх:
TIM1->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
TIM1->CR1 |= TIM_COUNTERMODE_UP;
TIM1->CR1 &= ~TIM_CR1_CKD;
// Установка деления тактов на 1:
TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1;
 
// Установка значения автозагрузки счетчика:
TIM1->ARR = PERIOD;
// Установка значения длительности импульса:
TIM1->CCR1 = PULSE;
// Установка значения прескалера:
TIM1->PSC = Prescaler;
// Установка значения счетчика повторений:
TIM1->RCR = PULSE_NUMBER - 1;
 
// Генерация события обновления для немедленной
// перезагрузки прескалера и счетчика повторений:
TIM1->EGR = TIM_EGR_UG;
// Сброс регистра SMCR:
TIM1->SMCR = RESET;
 
// Выбор режима OPM:
TIM1->CR1 |= TIM_CR1_OPM;
TIM1->CCMR1 &= (uint16_t)~TIM_CCMR1_OC1M;
TIM1->CCMR1 &= (uint16_t)~TIM_CCMR1_CC1S;
TIM1->CCMR1 |= TIM_OCMODE_PWM2;
 
// Выбор канала 1 и режима Output Compare:
TIM1->CCER &= (uint16_t)~TIM_CCER_CC1P;
// Установка полярности Output Compare:
TIM1->CCER |= TIM_OCPOLARITY_HIGH;
// Разрешение выхода Compare канала 1:
TIM1->CCER = TIM_CCER_CC1E;
// Разрешение основного выхода таймера: 
TIM1->BDTR |= TIM_BDTR_MOE;
// Разрешение периферийного устройства таймера:
TIM1->CR1 |= TIM_CR1_CEN;

[Firmware]

Программное обеспечение микроконтроллера (firmware) было разработано в средах Keil μVision, IAR Embedded workbench и SYSTEM WORKBENCH. Проект firmware поставляется в виде ZIP-архива [4] и содержит все подкаталоги и файлы исходного кода (файлы .h и .c), которые составляют ядро приложения.

AN4776 project organization fig21

Рис. 21. Организация проекта.

Firmware содержит все исходные файлы приложения, и соответствующие файлы распределены по следующим папкам проекта:

• Библиотека STM32 MCU HAL (модули в папках Drivers / STM32F3xx_HAL_Driver и Drivers / CMSIS)
• Файл первоначальной настройки ядра микроконтроллера (папка Application / MDK-ARM, модуль ассемблера startup_stm32f302x8.s)
• Слой приложения (папка Application / User, модули stm32f3xx_hal_msp.c, stm32f3xx_it.c, main.c).

[ШИМ-регулирование с использованием входа break]

Функция Break доступна в продвинутых таймерах, таких как TIM1 и TIM8, а также в облегченных таймерах наподобие TIM15, TIM16 и TIM17. Функция Break используется в основном для защиты выходного каскада силового инвертора, который управляется от выходов таймера; функция запрещает эти выходы, или переводит их в заранее определенное безопасное для драйвера состояние, когда что-то пошло не так в силовом блоке или с самим микроконтроллером.

Для детектирования внешних запросов остановки (на входе break), сгенерированных силовым каскадом, функция break связана с выделенным входом (например BKIN или BKIN2), который отображен как альтернативная функция на одну из нескольких ножек IO микроконтроллера. Будучи разрешенной, функция break запрещает выходы PWM, или переводит их в безопасное состояние, когда было детектировано событие break, даже если не присутствует тактирование. Например, можно асинхронно деактивировать выходы управления силовым мостом.

Руководство пользователя содержит больше информации о том, как конфигурировать безопасное предопределенное состояние для выходов таймера.

Как только определено достоверное событие break, асинхронно очистится управляющий бит MOE в регистре TIMx_BDTR. Он действует только на тех каналах таймера, которые сконфигурированы в режим вывода. Чтобы возобновить нормальное рабочее состояние выходов канала таймера, программа должна установить бит MOE, или установить бит AOE, чтобы выходы таймера перешли в рабочее состояние и начался новый цикл ШИМ.

Некоторые семейства микроконтроллеров STM32 (например семейство STM32F303) имеют встроенные таймеры, у которых есть два входа break: BKIN и BKIN2. Для таких таймеров вход BRK2 имеет меньший приоритет, чем вход BRK. Входы BKIN и BKIN2 могут запретить выходы канала таймера только принудительным переводом их в состояние отключено (Hi-Z), и они не могут перевести их в предопределенное безопасное состояние.

Сравнение входов Break с использованием OCxRef-clear. Как было упомянуто выше, основное использование входа break - управлять выходами канала таймера так, чтобы предотвращать аварийные ситуации. Благодаря гибкому дизайну вход break также может использоваться в других случаях, наподобие регулирования тока в каждом такте. Концептуально регулирование тока в каждом периоде ШИМ выполняется функцией OCxRef-clear таймеров STM32.

В некоторых случаях невозможно использовать функцию OCxRef-clear для управления регулированием тока в каждом цикле ШИМ. Это вследствие того, что вход таймера ETR, используемый этой функцией, может быть конкурентным с другой функцией таймера (например, внешняя синхронизация таймера использует вход ETR для подачи внешнего сигнала тактов). В такой ситуации может быть полезным использовать функцию Break для поддержки регулирования тока в каждом периоде ШИМ.

С одной стороны, функция OCxRef clear действует на выходах канала таймера (что также относится к функции Break); с другой стороны, функция OCxRef может быть активирована на каждом канале по отдельности (например, активация функции OCxRef clear осуществляется поканально через установку соответствующего управляющего бита OCxCE для регулируемых каналов). В этой второй ситуации функция Break действует на всех выходах каналов (например, нет способа управлять, на какой канал влияет событие break).

Концепция поциклового регулирования тока основана на факте, что как только регулируемая величина тока станет больше заданного порога, сигнал PWM (ШИМ) станет низким до начала следующего цикла PWM. Это поведение изначально поддерживается функцией OCxREf-clear, что иллюстрируется на рис. 22.

AN4776 timing TIMx OCxREF clear fig22

Рис. 22. Тайминг очистки OCxREF таймера TIMx.

Для функции Break аналогичное поведение управляется битом AOE. Если бит AOE удерживается в своем состоянии по умолчанию (состоянии после сброса), то как только регулируемый ток пересечет заданный порог, выходы таймера перейдут на низкий уровень. Таймер продолжит находиться в этом состоянии, пока бит MOE не будет установлен программно, что отличается от типичного поведения логики поциклового регулирования.

Установка бита управления AOE перед активацией функции регулирования с помощью Break автоматически установит управляющий бит MOE на начале каждого нового цикла PWM. Ранее описанное поведение функции Break по сравнению с конфигурацией бита управления AOE иллюстрировано на рис. 23, где построена форма сигнала на одном выходе канала таймера.

AN4776 timing Break function fig23

Рис. 23. Тайминг функции Break.

Также рис. 23 показывает разницу в поведении выхода таймера между этими двумя конфигурациями бита управления AOE.

• Если AOE = 0, то выход PWM будет запрещен даже если вход break больше не активен (аналогично срабатыванию защиты, которую нужно сбросить принудительно).
• Если AOE = 1, то выход PWM разрешается на следующем событии обновления, если вход break не активен (соответствует поцикловому ШИМ-регулированию тока, т. е. ограничению тока с помощью уменьшения скважности периода ШИМ).

Регулирование в каждом такте ШИМ это одна из применяемых техник реализации защиты от перегрузки по току в выходных каскадах импульсных преобразователей мощности. Эта функция отслеживает ток, который протекает в силовом мосте преобразователя. Как только ток превысит определенный порог (IRef), сигнал PWM (ШИМ) перейдет в низкий уровень, чтобы выходной ток уменьшился, чем достигается эффект регулирования (ограничения) тока.

Сигналу PWM не разрешено возобновить свою сконфигурированную скважность импульсов до начала нового периода PWM. Если ток все еще больше, чем порог IRef, то сигнал PWM останется в низком уровне до начала следующего периода PWM. И так далее, пока ток не снизится до уровня ниже IRef.

Сравнение тока в силовом каскаде с заданным порогом может быть реализовано с помощью датчика тока и схемы электронного компаратора. Сам компаратор может быть даже встроен в микроконтроллер (например, компаратором оборудованы микроконтроллеры STM32F302 и STM32F303). Выход схемы компаратора должен подаваться на вход break, и соответственно на вход ETR в том случае, когда используется функция OCxRef-clear.

Рис. 24 показывает поведение функции break, когда она разрешена. Здесь для сравнения показаны реально выводимый сигнал PWM (сплошная линия) и запрограммированный PWM (штриховая линия).

AN4776 timing cycle by cycle regulation fig24

Рис. 24. Тайминг поциклового ШИМ-регулирования.

Функция break переводит выход канала в низкий уровень (соответствует выключению мощности), когда поступит высокий уровень на вход BRK_ACTH (сработает ограничение тока за счет уменьшения скважности ШИМ). Выход канала останется в низком уровне (мощность выключена) до следующего события обновления таймера (т. е. до начала следующего цикла PWM), потому что установлен бит управления AOE.

Рис. 25 показывает эмуляцию реальной схемы поциклового ШИМ-регулирования с использованием функции Break. Для эмулирования обратной связи по току реального силового инвертора используется переменный резистор и конденсатор.

AN4776 cycle by cycle regulation architecture fig25

Рис. 25. Архитектура поциклового ШИМ-регулирования.

Как показано на рис. 25, таймер используется в режиме PWM, опорное напряжение Vref предоставлено с помощью ЦАП (его уровень сохранен в RAM), и оно сравнивается с напряжением "датчика тока" (Vsensed) с помощью аналогового компаратора. Выход компаратора перенаправлен внутри кристалла микроконтроллера на сигнал BRK_ACTH, который управляет состоянием PWM.

Рис. 26 показывает изменение скважности выходного сигнала PWM при изменении входного напряжения Vsensed по отношению к опорному Vref.

AN4776 oscilloscope screen shot fig26

Рис. 26. Скриншот осциллографа с полученной формой сигнала ШИМ.

На рис. 26 показано, что во время первого импульса PWM напряжение достигло предела Vref до окончания импульса PWM. В результате выходной импульс PWM выключился раньше (длина импульса ограничилась). В последующих периодах PWM длина импульса также ограничивалась до уровня, при котором средняя передаваемая мощность активной части периода PWM соответствует напряжению обратной связи Vsense.

Для запуска этого приложения требуется следующее аппаратное обеспечение:

- Плата разработчика STM32F302 Nucleo (NUCLEO-F302R8).
- Кабель USB для подключения платы Nucleo к PC разработчика (через кабель USB также подается питание на плату).
- Осциллограф для наблюдения за формируемым сигналом.
- Переменный резистор (10k .. 100к) и постоянный сухой конденсатор (10 нФ .. 0.1 мкФ).

Для того, чтобы скомпилировать и отладить исходный код в разных конфигурациях, нужен также набор программного инструментария:

– Среда разработки, поддерживающая отладчик ST-LINK.
– Последняя версия утилиты STM32CubeMX (в момент разработки этого приложения использовалась версия v4.10.1).

[Инициализация системных тактов]

В этом приложении таймер TIM1 тактируется внутренним генератором HSI. Инициализация тактов осуществляется в функции main вызовом функции SystemClock_Config() сразу после инициализации библиотеки HAL (вызова функции HAL_Init). Ниже показан код конфигурации:

// Конфигурирование внутреннего источника тактов.
// Разрешение тактирования TIM1:
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
// Настройка таймера прескалера для получения
// частоты тактов счетчика 500 кГц:
Prescaler = (uint16_t) (SystemCoreClock / 500000) - 1;
// Выбор режима счета вверх:
TIM1->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
TIM1->CR1 |= TIM_COUNTERMODE_UP;
TIM1->CR1 &= ~TIM_CR1_CKD;
// Установка деления тактов на 1:
TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1;
// Установка значения автозагрузки счетчика:
TIM1->ARR = PERIOD;
// Установка значения длительности импульса
// в регистре Capture Compare:
TIM1->CCR1 = PULSE;
// Установка значения прескалера:
TIM1->PSC = Prescaler;
// Генерация события обновления для немедленной
// перезагрузки прескалера и счетчика повторений:
TIM1->EGR = TIM_EGR_UG;
// Сброс регистров SMCR и BDTR:
TIM1->SMCR = RESET;
TIM1->BDTR = RESET;
// Установка мертвого времени в 0:
TIM1->BDTR |= DEAD_TIME;
// Запрет уровня Lock:
TIM1->BDTR |= TIM_LOCKLEVEL_OFF;
// Разрешение режима Output idle:
TIM1->BDTR |= TIM_OSSI_ENABLE;
// Запрет режима Output run:
TIM1->BDTR |= TIM_OSSR_DISABLE;
// Разрешение входа Break:
TIM1->BDTR |= TIM_BREAK_ENABLE;
// Установка положительной полярности Break:
TIM1->BDTR |= TIM_BREAKPOLARITY_HIGH;
// Разрешение автоматического выхода (бит AOE):
TIM1->BDTR |= TIM_AUTOMATICOUTPUT_ENABLE;
// Выбор Output Compare и режима для канала 1:
TIM1->CCMR1 &= ~TIM_CCMR1_OC1M;
TIM1->CCMR1 &= ~TIM_CCMR1_CC1S;
TIM1->CCMR1 |= TIM_OCMODE_PWM1;
// Установка положительной полярности Output Compare:
TIM1->CCER &= ~TIM_CCER_CC1P;
TIM1->CCER |= TIM_OCPOLARITY_HIGH;
// Разрешение выхода Compare канала 1:
TIM1->CCER |= TIM_CCER_CC1E;
// Разрешение работы таймера TIM1:
TIM1->CR1 |= TIM_CR1_CEN;

[Firmware]

Программное обеспечение микроконтроллера (firmware) было разработано в средах Keil ?vision, IAR Embedded workbench и SYSTEM WORKBENCH. Проект firmware поставляется в виде ZIP-архива [4] и содержит все подкаталоги и файлы исходного кода (файлы .h и .c), которые составляют ядро приложения.

AN4776 project organization fig27

Рис. 27. Организация проекта.

Firmware содержит все исходные файлы приложения, и соответствующие файлы распределены по следующим папкам проекта:

• Библиотека STM32 MCU HAL (модули в папках Drivers / STM32F3xx_HAL_Driver и Drivers / CMSIS)
• Файл первоначальной настройки ядра микроконтроллера (папка Application / MDK-ARM, модуль ассемблера startup_stm32f302x8.s)
• Слой приложения (папка Application / User, модули stm32f3xx_hal_msp.c, stm32f3xx_it.c, main.c).

[Генерация сигнала произвольной формы с помощью пакетных передач DMA таймера]

Прямой доступ к памяти (DMA) используется для осуществления автоматических, высокоскоростных пересылок данных между периферийным устройством и между областями памяти. DMA освобождает ядро процессора от осуществления тех же самых операций в программе, разгружая процессор для других задач.

Каждая транзакция DMA состоит из двух стадий:

• На первой стадии передаваемые данные загружаются из источника.
• На второй стадии полученные данные сохраняются в место, для которого они предназначены.

Двухстадийная операция перемещения данных связана с обновлением индексного регистра транзакции DMA; этот регистр используется для отслеживания, сколько данных осталось передать.

В семействах микроконтроллеров STM32 есть два варианта аппаратуры DMA:

• Функция DMA burst transfer (пакетный прямой доступ к памяти) поддерживается только в том варианте реализации, где DMA может перемещать конфигурируемое количество элементов данных для одиночной транзакции. Одному срабатыванию триггера транзакции соответствует перемещение целого блока данных.
• В другом варианте, как в одной из разновидностей STM32F1, DMA поддерживает перемещение только одного элемента данных на транзакцию; это означает, что по одному срабатыванию триггера транзакции перемещается один элемент данных, не блок.

Параграф выше не претендует на полное описание функции STM32 DMA-burst feature, поддерживаемой многими микроконтроллерами STM32. Это просто общая информация, предназначенная для устранения неправильного понимания пакетного DMA. Для дополнительной информации по аппаратуре DMA STM32 обратитесь к соответствующим руководствам, а также апноуту AN4013 [2].

DMA-burst таймера. У таймера есть возможность генерации нескольких следующих друг за другом запросов DMA, которые запускаются после одно события таймера. Основное использование этой функции - обновление содержимого нескольких регистров таймера каждый раз, когда сработает событие этого таймера. Это можно делать либо для динамического реконфигурирования рабочего режима таймера (переключаясь из одного режима вывода в другой, например из режима PWM2 в режим принудительной установки активного уровня, force-active-level mode), или для изменения рабочих параметров нескольких каналов одновременно (меняя параметры скважности сразу для нескольких каналов таймера).

Эта же функция DMA-burst также может использоваться для перемещения содержимого нескольких регистров таймера в буфер памяти.

DMA позволяет на лету модифицировать выводимую таймером форму сигнала путем подстройки содержимого регистров таймера. Например, это позволяет обновлять регистр TIMx_ARR, чтобы подстроить частоту выводимого сигнала или обновлять регистр TIMx_CCRx для подстройки скважности сигнала.

Чтобы использовать функцию DMA-burst, программист должен работать со следующими регистрами таймера:

– Регистр адреса DMA (TIMx_DMAR): это регистр перенаправления доступа на чтение/запись.
– Регистр управления DMA (TIMx_DCR): это регистр управления машиной состояния burst-транзакции.
– Регистр настройки контроллера DMA.

TIMx_DMAR. Регистр используется для конфигурирования адреса регистра назначения, когда DMA конфигурируется в режиме передачи из памяти в таймер. Он также используется как адрес регистра источника, когда DMA конфигурируется в режиме передачи из таймера в память.

Аппаратура DMA должна обновлять содержимое серии регистров таймера значениями из буфера памяти, где находятся заранее определенные или вычисленные значения, но это не означает, что адрес транзакции, указанный регистром адреса периферийного устройства, должен быть сконфигурирован для пост-инкремента контроллером DMA после каждой передачи данных. Регистр адреса периферийного устройства контроллера DMA должен указывать на регистр таймера TIMx_DMAR.

Регистр TIMx_DMAR таймера является виртуальным. Любой доступ к этому регистру будет перенаправлен логикой управления DMA-burst таймера на один из физических регистров таймера.

Доступ к регистру TIMx_DMAR может быть либо на чтение, либо на запись. Перенаправление реального доступа к регистру TIMx_DMAR на другой физический регистр таймера зависит от содержимого регистра TIMx_DCR настройки интерфейса DMA-burst. Также это зависит от реального состояния машины состояний (finite-state machine, FSM), управляющей интерфейсом DMA burst таймера.

Настройка регистров адреса контроллера DMA. Регистр адреса памяти в контроллере DMA используется для конфигурирования места назначения в памяти, когда DMA конфигурируется в режиме передачи из регистров периферийного устройства (в нашем случае в качестве периферийного устройства работает таймер) в память. Также регистр адреса контроллера DMA используется как адрес ячейки памяти источника, когда DMA сконфигурировано для передачи из памяти в регистры периферийного устройства.

Контроллер DMA должен обновлять содержимое серии регистров таймера содержимым из буфера памяти. Адрес, на который указывает регистр адреса DMA, должен быть сконфигурирован на пост-инкремент контроллером DMA для каждой транзакции данных.

Регистр управления DMA-burst таймера. Регистр управления машиной состояний функции таймера DMA burst, TIMx_DCR, используется для конфигурирования количества порций данных во время однократной burst-транзакции. Также он используется для идентификации целевого регистра таймера или источника первой транзакции данных во время первой передачи.

Поле бит DBL [4:0] устанавливает количество порций во время одной burst-передачи, которое должно быть равно количеству регистров таймера, вовлекаемых в процесс (записи или чтения) burst-транзакции. Содержимое поля бит DBA [4:0] идентифицирует начальный регистр, вовлеченный в burst-передачу следи других регистров таймера.

Поле бит DBA[4:0] может идентифицировать до 32 регистров таймера, потому что оно имеет длину 5 бит. Идентификационный номер регистра получается путем деления относительного адреса регистра в карте памяти на 4. Например, у регистра TIMx_CR1 относительный адрес на карте памяти процессора 0x00, поэтому его идентификационный номер 0.

Чтобы сделать burst-транзакцию с началом из регистра TIMx_CR1, поле бит DBA[4:0] должно быть установлено в 0. Чтобы сделать burst-транзакцию с началам из регистра TIMx_ARR, битовое поле DBA[4:0] должно быть установлено в 11 (десятичная форма числа), потому что относительный адрес регистра TIMx_ARR 0x2C, что в десятичной форме равно 44. Делением 44 на 4 получим 11, что будет индентификационным индексом регистра TIMx_ARR для использования в транзакции DMA.

Чтобы завершить одну последовательность транзакции DMA-burst таймера, как показано на рис. 28, должны совместно работать контроллер DMA и аппаратура таймера. Значения данных, используемые для обновления регистров таймера, должны быть сохранены где-нибудь в памяти микроконтроллера. Они могут быть сохранены в памяти SRAM, если шаблон сигнала ШИМ должен обновляться в процессе генерации ШИМ, или в постоянной памяти FLASH, если шаблон рассчитан так, что он не обновляется.

AN4776 conf timer DMA burst transfer sequence fig28

Рис. 28. Конфигурация для последовательности DMA-burst таймера.

Программа микроконтроллера должна сконфигурировать DMA для указания на буфер данных в качестве источника данных для транзакции таймера; также программа должна указать регистр таймера TIMx_DMAR в качестве места назначения передачи данных. И наконец, программа приложения должна сконфигурировать функцию DMA-burst таймера путем записи правильных настроек в регистр таймера TIMx_DCR.

Параграфы выше давали подробное описание того, как конфигурировать функцию DMA burst таймера. Как только правильная конфигурация установлена, вслед за разрешением счетчика таймера должен быть разрешен поток DMA или канал, используемый для передачи данных.

Будучи разрешенным, счетчик таймера будет периодически изменяться либо инкрементированием, либо декрементированием. Через некоторое время, в зависимости от разрешенных запросов DMA таймера, аппаратура таймера может привести к внутренней генерации запроса DMA. Запрос DMA перенаправляется внутри чипа на таймер с помощью логики управления DMA-burst таймера.

На основе значения, сконфигурированного полем длины DMA-burst (DBL[4:0], это битовое поле находится в регистре TIMx_DCR таймера), запрос DMA посылается в контроллер DMA однократно или несколько раз. Если содержимое DBL[4:0] нулевое, то запрос DMA посылается как есть; иначе количество запросов DMA умножается на значение DBL + 1.

Если содержимое битового поля DBL[4:0] равно 2, то как только сгенерируется запрос DMA таймера, логика управления DMA burst таймера пошлет первый запрос DMA в контроллер DMA. Контроллер DMA перешлет содержимое памяти в регистр таймера; место в памяти указывается в регистре источника TIMx_DMAR таймера. Затем указатель источника инкрементируется контроллером DMA, и для таймера подтверждается запрос DMA.

Как только принято первое подтверждение DMA, управляющая логика DMA-burst таймера посылает второй запрос DMA. Этот запрос DMA снова обрабатывается контроллером DMA, и снова таймеру посылается подтверждение запроса.

После получения второго подтверждения DMA, логика управления DMA-burst таймера посылает третий запрос DMA. Этот третий запрос снова обрабатывается контроллером DMA.

Как только таймер получил третье подтверждение от контроллера DMA, последовательность транзакции считается успешно завершенной. После этого логика управления DMA-burst таймера готова к новой последовательности транзакции DMA.

Для ранее описанной последовательности передачи данных регистр назначения передачи, указанный для контроллера DMA, остается тем же самым во время всей последовательности перемещения данных. Тогда этот регистр остается равным регистру таймера TIMx_DMAR.

Логика управления DMA-burst таймера каждый раз перенаправляет доступ на запись в регистр TIMx_DMAR на правильный физический регистр таймера.

Для предыдущего примера, и если поле базового адреса DBA[4:0] регистра TIMx_DCR установлено в 11 (десятичное значение), обратите внимание на следующее:

• Первый DMA-доступ на запись в регистр таймера TIMx_DMAR перенаправляется в регистр таймера TIMx_ARR. Регистр таймера TIMx_ARR выбран базовым адресом для burst-транзакции.
• Второй доступ к регистру TIMx_DMAR таймера со стороны DMA перенаправляется в регистр TIMx_RCR таймера (предполагается, то таймер, используемый для этого примера, оборудован регистром TIMx_RCR).
• Третий доступ DMA к регистру TIMx_DMAR перенаправляется в регистр TIMx_CCR1 таймера.
• По окончании третьего доступа DMA к регистру TIMx_DMAR, управляющая логика DMA-burst таймера возвращает обратно машину состояний перенаправления доступа. Она указывает снова на сконфигурированный базовый регистр для burst-транзакции (регистр TIMx_ARR таймера в этом примере).

Для каждого нового внутреннего запроса DMA, сгенерированного таймером, описанная выше последовательность операций повторяется.

Для использования DMA burst таймера с целью периодического чтения содержимого регистров таймера в определенный буфер в памяти, описанная выше последовательность будет также достоверна. Изменятся только направление транзакции DMA, адрес источника и адрес назначения.

Этот пример демонстрирует одно из возможных применений таймера STM32 для генерации произвольного сигнала без загрузки ядра CPU. Тестовое приложение разработано на плате разработчика NUCLEO-F302R8 для микроконтроллера STM32F302x8. Тем не менее это приложение может быть легко портировано на любой микроконтроллер платформы STM32.

На плате разработчика Nucleo встроен собственный отладчик ST-Link/V2. Для подключения к компьютеру, прошивки FLASH-памяти микроконтроллера и отладки нужен только кабель USB.

Рис. 29 показывает упрощенную диаграмму генератора сигналов произвольной формы, реализованного в этом примере приложения. Генерируемый сигнал выводится через ножку IO порта PA.08 микроконтроллера STM32F302, которая отображается на вывод 8 коннектора CN9 платы Nucleo.

AN4776 arbitrary waveform generation using DMA burst fig29

Рис. 29. Схема генерации сигнала произвольной формы с помощью функции DMA-burst.

Генератор сигналов произвольной формы, описанный в этом примере, разработан для вывода сигнала, как показано на рис. 30. Исходный код этого приложения можно легко перенастроить для вывода других сигналов, но в целях демонстрации реализован вывод сигнала на рис. 4.

AN4776 targeted waveform fig30

Рис. 30. Генерируемый целевой сигнал.

Целевая форма сигнала рисунка 30 составлена из трех порций:

• Первая порция составлена из двух следующих друг за другом импульсов, у которых задано определенное время включения и выключения: t1_on и t1_off.
• Вторая порция построена из одного импульса с другими временами включения и выключения: t2_on и t2_off.
• Третья порция построена из трех импульсов, где задан третий вариант времени включения и выключения: t3_on и t3_off.

Чтобы таймер выводил этот сигнал, может быть задействована функция счетчика повторений таймера (repetition counter). В таймере есть регистр счетчика повторений TIMx_RCR и как минимум один канал таймера. Для этого примера использовался таймер TIM1, потому что в нем есть 4 канала, а также счетчик повторений.

Канал таймера может генерировать сигнал PWM с постоянными, заданными заранее параметрами частоты и скважности. Параметр частоты управляется содержимым регистра автозагрузки TIMx_ARR. В этом регистре параметр скважности управляется содержимым регистра канала 1 таймера (TIM1_CCR1). Чтобы заставить канал таймера выводить запрашиваемую форму сигнала (см. рис. 4), содержимое этих двух регистров таймера должно обновляться по окончанию каждого цикла PWM.

Другими словами, требуется обновлять содержимое этих двух регистров синхронно с каждым событием обновления (update event) таймера. Интуитивный способ добиться этого - написать программу, которая обновляет содержимое этих двух регистров каждый раз, когда таймер производит "update event". Понятно, что это приведет к чрезмерной нагрузке на CPU, и даже может привести к некачественно выводимой форме сигнала. Решить эту проблему как раз помогает функция DMA, которая устраняет нагрузку CPU и позволяет автоматически и стабильно генерировать сигнал строго определенной формы.

Чтобы обновить регистры таймера TIMx_ARR и TIMx_CCR1 одновременно сразу за одним событием таймера "update event", должна использоваться функция DMA-burst таймера в дополнение к одному каналу или потоку DMA. Как конфигурировать и использовать функцию DMA-burst таймера описано в предыдущих секциях этого документа.

Чтобы предотвратить генерацию на канале таймера нежелательных импульсов из-за обновления регистров канала таймера, используется функция предзагрузки таймера STM32.

Чтобы заставить канал таймера выводить повторяющиеся импульсы с одними и теми же временами включения и выключения t_on и t_off, и без генерации при этом "update event" на каждом цикле PWM, должен использоваться счетчик повторений таймера (repetition counter).

Чтобы вывести форму сигнала, показанную на рис. 29, через канал 1 таймера TIM1, должны быть обновлены 3 регистра следующим образом:

• TIM1_ARR: содержит сумму периодов t_on и t_off для генерируемого импульса.
• TM1_RCR: содержит количество одинаково формируемых периодов импульсов одной из порций сигнала минус 1  (например, TIM1_RCR = Number_of_pulses_per_portion – 1).
• TIM1_CCR1: содержит длительность периода t_on генерируемого импульса.

Ниже показана конфигурация регистров таймера для каждой из трех порций сигнала рис. 29. Для первой порции сигнала правильная конфигурация следующая:

• TIM1_ARR = t1_on + t1_off, TIM1_RCR = 1 (два повтора), TIM1_CCR1= t1_on;

Для второй порции сигнала правильная конфигурация следующая:

• TIM1_ARR = t2_on + t2_off, TIM1_RCR = 0 (без повторов), TIM1_CCR1= t2_on;

Для третьей порции сигнала правильная конфигурация следующая:

• TIM1_ARR = t3_on + t3_off , TIM1_RCR = 2 (два повтора), TIM1_CCR1= t3_on;

Содержимое буфера памяти. Показанные выше значения регистров таймера TIM1_ARR, TIM1_RCR и TIM1_CCR1 сохраняются в таблицу, хранящуюся в памяти микроконтроллера, что показано на рис. 31.

AN4776 waveform generation data pattern fig31

Рис. 31. Шаблоны данных для генерируемого сигнала, сохраненные в памяти микроконтроллера.

Обратите внимание, что порядок значений данных в таблице такой же, как у соответствующих регистров таймера на карте памяти микроконтроллера. Правильный порядок данных регистров должен быть TIM1_ARR, TIM1_RCR и затем TIM1_CCR1.

Исходный код на языке C для описанной таблицы показан ниже в виде массива 32-битных констант aSRC_Buffer. Ключевое слово const используется для того, чтобы показать, что содержимое таблицы не модифицируется на лету в процессе выполнения программы, когда генерируется сигнал.

uint32_t const aSRC_Buffer[9] =
{
   t1_on+t1_off,
   1,
   t1_on,
   t2_on+t2_off,
   0,
   t2_on,
   t3_on+t3_off,
   2,
   t3_on
};

Этот массив хранится в памяти FLASH микроконтроллера (постоянная память программ). Если требуется поменять параметры формы сигнала run-time (во время выполнения программы), то не нужно использовать ключевое слово const. В этом случае массив с таблицей будет размещен в памяти SRAM.

Конфигурация DMA-burst таймера. Чтобы вывести сигнал требуемой формы, функция DMA-burst таймера TIM1 должна быть сконфигурирована следующим образом:

• Поскольку обновляется 3 регистра таймера, то длина пакета DMA транзакции (burst transfer length) равняется 3. Поле бит DBL[4:0] в регистре TIM1_DCR должно быть установлено в 2. Каждое событие обновления (update event) передается 3 слова данных, и для трех порций сигнала произойдет 3 события обновления.
• Среди обновляемых регистров таймера TIM1_ARR будет первым на карте регистров таймера TIM1, поэтому он определен базовым для DMA транзакции. Тогда битовое поле DBA[4:0] должно быть установлено так, чтобы оно указывало на регистр TIM1_ARR. (в поле DBA[4:0] = записывается десятичное значение 11. Это число получается делением на 4 смещения адреса регистра TIM1_ARR. Это смещение равно 44, следовательно в поле DBA[4:0] должно быть записано 44 / 4 = 11).

Рис. 28 показывает блок-диаграмму описанной выше конфигурации.

Конфигурация тактов. В этом примере, чтобы счетчик таймера TIM1 работал на частоте 32 МГц, делаются следующие настройки:

• Входная частота TIM1 (TIM1CLK) устанавливается на такты APB2 (PCLK2):

TIM1CLK = PCLK2, и PCLK2 = HCLK => TIM1CLK = HCLK = SystemCoreClock.

• Прескалер TIM1 настраивается следующим образом:

Prescaler = (TIM1CLK / частота счетчика TIM1) - 1
Prescaler = (SystemCoreClock / 32 МГц) – 1

Вычисление частот и скважностей. В этом примере шаблон для генерируемого сигнала будет следующий:

uint32_t aSRC_Buffer[9] = {4000, 1, 800, 10000, 0, 8500, 4000, 2, 200};

Показанные данные основаны на следующих вычислениях. Вычисление частоты TIM1 (F1,F2):

                     TIM1counterclock      32 МГц
TIM1Frequency(F1) = ------------------ = ---------- = 8.0 кГц
                          TIMARR            4000

                     TIM1counterclock      32 МГц
TIM1Frequency(F2) = ------------------ = ---------- = 3.2 кГц
                          TIMARR            10000

Вычисление скважности канала 1 (D1, D2, D3):

                     TIM1CCR1            800
TIM1dutycycle(D1) = ---------- x 100 = ------ x 100 = 20%
                      TIMARR            4000

                     TIM1CCR1           8500
TIM1dutycycle(D2) = ---------- x 100 = ------ x 100 = 85%
                      TIMARR           10000

                     TIM1CCR1            200
TIM1dutycycle(D3) = ---------- x 100 = ------ x 100 = 50%
                      TIMARR            4000

AN4776 arbitrary signal generation on channel1 TIM1 fig33

Рис. 33. Генерация сигнала произвольной формы на канале 1 таймера TIM1.

[Firmware]

Чтобы заработала генерация сигнала произвольной формы, описанная в предыдущих секциях, нужно выполнить следующие шаги:

• Настройка системных тактов процессора (System clock).

– PLL устанавливается в качестве системной тактовой частоты 64 МГц.
– HSI выбирается в качестве генератора (не нужно запаивать HSE на плате Nucleo).
– AHB div = 1 / APB1 div = 2 / APB2 div = 1.

В этом примере используется DMA1 с таймером TIM1.

• Конфигурация DMA:

// Разрешение тактов DMA1:
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
// Конфигурируется управляющий регистр DMA1 Channel5.
// Сброс управляющего регистра DMA1 Channel5:
DMA1_Channel5->CCR = 0;
// Биты CHSEL устанавливаются в соответствии с DMA Channel 5.
// Биты DIR устанавливаются в направлении от памяти
// в периферийное устройство (здесь это таймер).
// Бит PINC устанавливается для DMA Peripheral Increment Disable.
// Бит MINC устанавливается для DMA Memory Increment Enable.
// Биты PSIZE устанавливаются для Peripheral DataSize = Word.
// Биты MSIZE устанавливаются для Memory DataSize = Word.
// Бит CIRC устанавливается для кольцевого режима.
// Биты PL устанавливаются для очень высокого приоритета.
// Биты MBURST устанавливаются для одиночной burst-передачи памяти.
// Биты PBURST устанавливаются для одиночной burst-передачи периферии.
DMA1_Channel5->CCR |= DMA_MEMORY_TO_PERIPH |
                      DMA_PINC_DISABLE | DMA_MINC_ENABLE |
                      DMA_PDATAALIGN_WORD | DMA_MDATAALIGN_WORD |
                      DMA_CIRCULAR | DMA_PRIORITY_HIGH;
// Запись в DMA1 Channel5 количества данных регистра:
DMA1_Channel5->CNDTR = 9;
// Запись в DMA1 Channel5 адреса регистра периферии:
DMA1_Channel5->CPAR = (uint32_t)TIM1_DMAR_ADDRESS;
// Запись в DMA1 Channel5 регистр адреса памяти. Здесь
// это адрес буфера aSRC_Buffer:
DMA1_Channel5->CMAR = (uint32_t)aSRC_Buffer;
// Разрешение DMA1 Channel5:
DMA1_Channel5->CCR |= (uint32_t)DMA_CCR_EN;

• Конфигурация таймера TIM1:

// Вычисление значения для прескалера таймера:
Tim1Prescaler = (uint16_t) (SystemCoreClock / 32000000) - 1;
// Конфигурирование периода:
TIM1->ARR = 0xFFFF;
// Конфигурирование прескалера таймера:
TIM1->PSC = Tim1Prescaler;
// Конфигурирование ширины импульса:
TIM1->CCR1 = 0xFFF;
// Выбор коэффициента деления 1. Сброс поля
// clockDivision:
TIM1->CR1 &= ~ TIM_CR1_CKD;
// Выбор DIV1 в качестве деления частоты тактов:
TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1;
// Сброс битового поля режима:
TIM1->CR1 &= ~( TIM_CR1_DIR | TIM_CR1_CMS);
// Выбор счета вверх:
TIM1->CR1 |= TIM_COUNTERMODE_UP;
// Установка режима PWM1. Сброс бит Output Compare Mode:
TIM1->CCMR1 &= ~TIM_CCMR1_OC1M;
TIM1->CCMR1 &= ~TIM_CCMR1_CC1S;
// Выбор output compare mode 1:
TIM1->CCMR1 |= TIM_OCMODE_PWM1;/
/ Разрешение output compare 1 Preload:
TIM1->CCMR1 |= TIM_CCMR1_OC1PE;
// Разрешение автозагрузки Preload:
TIM1->CR1 |= TIM_CR1_ARPE;
// Разрешение TIM1 DMA Update:
TIM1->DIER |= TIM_DMA_UPDATE;
// Сброс битовых полей DBA и DBL:
TIM1->DCR &= ~TIM_DCR_DBA;
TIM1->DCR &= ~TIM_DCR_DBL;
// Выбор базового регистра DMA и длины DMA burst:
TIM1->DCR = TIM_DMABase_ARR | TIM_DMABurstLength_3Transfers;
// Разрешение UEV установкой бита UG для загрузки данных
// буфера в регистры предзагрузки:
TIM1->EGR |= TIM_EGR_UG;
// Ожидание сброса бита UG:
while((TIM1->EGR & TIM_EGR_UG) == SET){}
// Разрешение UEV установкой бита UG для загрузки данных
// из предзагрузки в активные регистры:
TIM1->EGR |= TIM_EGR_UG;
// Разрешение основного выхода TIM1:
TIM1->BDTR |= TIM_BDTR_MOE;
// Разрешение вывода CC1:
TIM1->CCER |= TIM_CCER_CC1E;
// Разрешение счетчика TIM1:
TIM1->CR1 |= TIM_CR1_CEN;

• GPIO:

– Вывод PA8 настраивается на выход канала таймера TIM1 (TIM1_ch1_output).
– Режим выхода драйвера push pull (двухтактный выход).
– Подтяжка: pull-up.
– Скорость переключения драйвера: high.
– Альтернативная функция: GPIO_AF6_TIM1.

[Генерация сигнала из N-импульсов с использованием синхронизации таймера]

Примеры в этой главе разделены на 2 части, в которых описаны 2 похожих приложения. Оба примера используют внутреннюю синхронизацию таймеров для генерации сигнала из N-импульсов, с небольшим отличием примеров друг от друга:

• В первом примере (см. врезку "Пример генерации сигнала из N-импульсов, часть 1"), сигнал из N-импульсов генерируется на выходе и комплементарном выходе канала 1 таймера TIM1. По окончанию генерации N-импульсов канал 1 таймера TIM1 выводит свое последнее состояние, когда на выходе канала 1 лог. 0, и на комплементарном выходе лог. 1.
• Во втором примере (см. врезку "Пример генерации сигнала из N-импульсов, часть 2"), сигнал из N-импульсов также генерируется на выходе и комплементарном выходе канала 1 таймера TIM1. По окончанию генерации N-импульсов оба выхода канала 1 таймера TIM1 должны быть в лог. 0. Это может быть достигнуто функцией коммутации, встроенной в таймеры STM32. Это функция подробно описана во врезке, описывающей часть 2 примеров.

Обзор синхронизации таймера. Некоторые таймеры STM32 связаны друг с другом внутренней синхронизацией (chaining). Таймеры STM32, где есть возможность внутренней синхронизации таймеров, имеют только один вывод сигнала синхронизации с именем TRGO (аббревиатура "Trigger Out"). Таймеры также имеют 4 входа синхронизации (называемые ITRx, где x число от 1 до 4), подключаемые к выходам синхронизации других таймеров STM32. Руководство пользователя для любого микроконтроллера STM32 описывает матрицу внутренних соединений таймеров.

Обратите внимание, что только те таймеры, в которых есть блок контроллера master/slave, поддерживают внутреннюю синхронизацию таймеров (только с немногими исключениями). Например, таймер TIM2 содержит блок контроллера master/slave, и он может быть синхронизирован с другими таймерами STM32.

TIM2 может вызывать события триггера внутри других таймеров через выход своего сигнала синхронизации TRGO. В этом случае таймер TIM2 действует как master-таймер. Таймер TIM2 также может быть сконфигурирован для срабатывания от выходов синхронизации других таймеров; в этом случае TIM2 работает как slave-таймер. Таймер может работать как одновременно и как slave-таймер, и как master-таймер по отношению к другим таймерам.

Таймер TIM11 это пример таймера, у которого нет блока контроллера master/slave. У него нет функции вывода сигнала синхронизации TRGO, но TIM11 может работать как master-таймер для некоторых других таймеров. Это возможно через использование выхода канала TIM11 в качестве источника вывода сигнала синхронизации. Выход канала таймера TIM11 подключается к входам синхронизации других таймеров.

Конфигурация master-таймера. Когда таймер конфигурируется в качестве master, когда его выходной сигнал синхронизации TRGO может подключаться к любым из событий синхронизации таймера, перечисленным ниже. Обратите внимание, что представленный список не исчерпывающий, и в нем представлены только наиболее общие режимы. Список master-режимов может меняться от одного семейства микроконтроллеров к другому:

• Reset: бит UG регистра EGR используется в качестве выхода триггера (TRGO).
• Enable: сигнал разрешения счетчика используется как выход триггера (TRGO). Эта возможность используется для одновременного запуска нескольких таймеров, или для управления окном, в котором разрешен slave-таймер.
• Update: событие обновление выбрано как выход триггера (TRGO). Например, master-таймер может использоваться в качестве прескалера для slave-таймера.
• Compare pulse: выход триггера посылает положительный импульс, когда установлен флаг CC1IF (даже если он уже в лог. 1), когда срабатывает захват (capture) или событие совпадения (compare match).
• OC1Ref: сигнал OC1REF используется как выход триггера (TRGO).
• OC2Ref: сигнал OC2REF используется как выход триггера (TRGO).
• OC3Ref: сигнал OC3REF используется как выход триггера (TRGO).
• OC4Ref: сигнал OC4REF используется как выход триггера (TRGO).

Для конфигурирования события таймера или внутреннего сигнала для использования в качестве выхода синхронизации, должно быть записано правильное значение в поле MMS (master mode selection) регистра управления TIMx_CR2.

Конфигурация slave-таймера. Каждый таймер, оборудованный master/slave контроллером, имеет 4 входа синхронизации, готовых к подключению к выходам синхронизации других таймеров. Обратите внимание, что только один вход синхронизации может быть активен в любой момент времени, и битовое поле TS (trigger selection) используется для выбора, какой вход синхронизации будет активен.

Детектирование активного перепада на входе синхронизации одного таймера может вызвать одно событие таймера наподобие события обновления (update event, UEV) и сброса счетчика, или инкремента счетчика. Это зависит от сконфигурированного значения в поле бит SMS (slave mode selection) в регистре выбора slave-режима таймера TIMx_SMCR.

Для выбора используемого входа синхронизации slave-таймер подключается к master-таймеру через входной триггер. Каждый триггер ITRx подключается внутри к другому таймеру, и это соединение специфично для каждого продукта STM32.

Функция коммутации таймера STM32. Функция коммутации используется в комбинации с функцией предзагрузки (preload) для изменения конфигурации канала таймера в четкой синхронизации с внешними событиями таймера, которые поступают на него через один из внутренних или внешних входов таймера. Конфигурация, к которой это относится, может быть, например, режимом вывода канала, разрешения/запрещения канала или другое. Входы ITRx являются примерами внутренних входов, и ETR, TI1 или TI2 это примеры внешних входов.

Как было установлено в описании базовых режимов GP-таймеров (см. начало статьи), управляющие биты OCxM, CCxE и CCxNE предоставляют функцию предзагрузки (preload). Когда функция предзагрузки разрешена этими полями, любой доступ к ним на запись не меняет рабочий режим канала таймера, потому что на самом деле операция записи выполняется над теневыми полями предварительной загрузки. В активные поля, которые в настоящее время управляют работой выхода таймера, остаются неизменными.

Как только событие коммутации было сгенерировано внутри таймера, содержимое теневых preload-полей будут перенесены в активные поля, и следовательно режим выходного канала поменяется.

В зависимости от конфигурации битового поля CCUS control в регистре управления таймера TIMx_CR2, событие коммутации может генерироваться после детектирования активного перепада на сигнале входа триггера (timer trigger input, TRGI). В частности, оно может генерироваться после детектирования активного перепада на входе синхронизации таймера ITRx (входы ITRx являются частью источников сигнала TRGI).

Эта функция может использоваться для управления одним таймером, когда сработало событие коммутации на другом таймере, через внутреннюю синхронизацию между таймерами. Альтернативно событие коммутации может генерироваться программно путем установки битового поля COMG в регистре таймера TIMx_EGR.

Этот пример демонстрирует, как использовать функцию внутреннего соединения таймеров STM32 для генерации заданного количества импульсов в каждом конфигурируемом периоде.

Приложение разработано на плате разработчика NUCLEO-F302R8, на которой стоит микроконтроллер STM32F302x8. Тем не менее это приложение может быть легко портировано на любой микроконтроллер платформы STM32. На плате Nucleo встроен свой отладчик ST-Link/V2. Для подключения к компьютеру, прошивки программы приложения во FLASH-память микроконтроллера и отладки нужен только кабель USB (через этот же кабель подается питание на плату Nucleo).

Рис. 34 показывает упрощенную диаграмму приложения примера, которое периодически генерирует N импульсов. Генерируемый сигнал выводится через ножку PA.08 микроконтроллера STM32F302, которая выведена на вывод 8 коннектора CN9.

AN4776 periodic N pulses generation fig34

Рис. 34. Схема периодической генерации N-импульсов.

Таймеры используются следующим образом:

• TIM2 конфигурируется в режиме master-триггера для подачи сигнала на TIM1.
• TIM1 сконфигурирован в режиме slave-запуска, в режиме генерации одного импульса (one pulse mode, OPM).

Рис. 35 показывает целевую форму сигнала, которую мы хотим получить в этом примере: периодическая генерация пяти импульсов (N=5).

AN4776 periodic N pulses generation waveform fig35

Рис. 35. Форма генерируемого сигнала примера приложения.

Форма сигнала, описанная в этом примере, разработана для вывода 6 импульсов в каждом цикле PWM, подобно сигналу, показанному на рис. 35. Сигнал построен из двух частот с двумя запрограммированными периодами: T2 это период таймера TIM2, и T1 это период таймера TIM1. Исходный код этого приложения может быть легко переделан под другие генерируемые сигналы, но в целях демонстрации реализован сигнал, показанный на рис. 37.

[Функциональное описание]

Как видно на рис. 35, целевая форма сигнала PWM построена для периодической генерации N-импульсов (в этом примере 5 импульсов). Импульсы состоят из определенного времени включения и выключения: t1_on и t1_off, t2_on и суммы, равной T1. Каждый период T2, импульсы генерируются снова, и остальная часть цикла PWM сохраняется на уровне лог. 0.

Чтобы выводить эти периодические импульсы, соединяются друг с другом два таймера: TIM1 и TIM2. Таймер TIM1 будет генерировать сигнал PWM с запрограммированной через регистр TIM1_CCR1 скважностью T1_on, и период T1 программируется содержимым регистра TIM1_ARR. Таймер TIM2 обеспечивает периодичность генерации пачки импульсов с интервалом T2, что программируется содержимым регистра TIM2_ARR.

Как показано на рис. 36, таймеры TIM2 и TIM1 соединены друг с другом последовательно, как master (главный таймер) и slave (подчиненный таймер) соответственно.

AN4776 periodic N pulses generation schema fig36

Рис. 36. Схема генерации N-импульсов.

Таймер TIM2 сконфигурирован в режиме master-триггера для подачи сигнала триггера на таймер TIM1. Сигнал TRGO от TIM2 приходит на вход ITR1 таймера TIM1 на каждом событии обновления TIM2. Время между соседними событиями обновления TIM2 равно интервалу T2 генерируемого сигнала.

Таймер TIM1 сконфигурирован как подчиненный (slave) в режиме генерации одного импульса (OPM), чтобы генерировать импульс по сигналу от таймера TIM2.

Когда появится положительный перепад на входе триггера ITR1, счетчик TIM1 начнет считать вверх только один раз до момента, когда значение счетчика достигнет сконфигурированного периода (TIM1_CCR1), равного 1/F1, затем происходит событие обновления (UEV).

Для генерации повторов импульса (при счете вверх) мы используем счетчик повторений (repetition counter) таймера TIM1, который должен быть сконфигурирован на количество генерируемых импульсов минус 1 (TIM1_RCR = number_of_pulses_per_portion – 1 = 5 - 1). UEV будет сгенерирован количества импульсов TIM1_RCR + 1.

Диаграмма на рис. 37 показывает, как синхронизируются таймеры с описанной конфигурацией, чтобы получить желаемый сигнал.

AN4776 timing periodic N pulses generation fig37

Рис. 37. Интервалы времени генерации N импульсов.

[Firmware]

• Системные такты (System clock)

– PLL настраивается в качестве системной тактовой частоты: 64 МГц.
– В качестве задающего генератора используется HSI (не нужно запаивать HSE на плате Nucleo).
– AHB div = 1 / APB1 div = 2 / APB2 div = 1

• TIM1

Мы используем канал 1 таймера TIM1 в режиме output compare, чтобы генерировать сигнал PWM1.

– Прескалер APB2 = 64 - 1 (чтобы получить частоту тактов таймера 1 МГц).
– Период (ARR) = 50 мкс -> частота F1 = 20 кГц.
– Импульс (CCR1) = период / 2 (скважность 50%).
– RCR = 5-1 -> для получения повтора 5 импульсов.
– Выбран режим OPM.
– Выбран подчиненный режим запуска (slave mode trigger).
– Вход триггера: ITR1.
– Режим PWM: mode1.
– Режим счета вверх.
– Предзагрузка Output Compare разрешена.

// Вычисление значения для конфигурации прескалера, чтобы
// частота тактов таймера составила 1 МГц:
Tim1Prescaler= (uint16_t) (SystemCoreClock / 1000000) - 1;
// Вычисление периода PWM для получения 20 кГц
// из тактовой частоты 1 МГц:
Period = 1000000 / 20000;
// Конфигурирование прескалера TIM1:
TIM1->PSC = Tim1Prescaler;
// Конфигурирование периода:
TIM1->ARR = Period-1;
// Конфигурирование счетчика повторений:
TIM1->RCR = ((uint32_t) 5) - 1;
// Конфигурирование ширины импульса:
TIM1->CCR1 = Period / 2;
// Выбор коэффициента деления Clock Division 1.
// Сброс поля бит коэффициента деления тактов:
TIM1->CR1 &= ~ TIM_CR1_CKD;
// Выбор DIV1 в качестве коэффициента деления:
TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1;
// Выбор счета вверх для TIM1. Сброс полей выбора режима:
TIM1->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
// Выбор счета вверх:
TIM1->CR1 |= TIM_COUNTERMODE_UP;
// Установка режима PWM1. Сброс бит режима Output Compare:
TIM1->CCMR1 &= ~TIM_CCMR1_OC1M;
TIM1->CCMR1 &= ~TIM_CCMR1_CC1S;
// Выбор output compare mode 1:
TIM1->CCMR1 |= TIM_OCMODE_PWM1;
/****************** Конфигурация OPM ********************/
// Выбор One Pulse Mode (OPM):
TIM1->CR1 |= TIM_CR1_OPM;
/********************************************************/
/********* Конфигурация slave-режима запуска ************/
// Выбор сигнала TIM_TS_ITR1 в качестве триггера для TIM1:
TIM1->SMCR &= ~TIM_SMCR_TS;
TIM1->SMCR |= TIM_TS_ITR1;
// Выбор Slave Mode:
TIM1->SMCR &= ~TIM_SMCR_SMS;
TIM1->SMCR |= TIM_SLAVEMODE_TRIGGER;
/********************************************************/
// Разрешение предзагрузки Output Compare:
TIM1->CCMR1 |= TIM_CCMR1_OC1PE;
// Установка бита UG, чтобы разрешить UEV:
TIM1->EGR |= TIM_EGR_UG;
// Разрешение основного выхода TIM1:
TIM1->BDTR |= TIM_BDTR_MOE;
// Выбор активного нуля в качестве выходной полярности.
// Сброс уровня Output Polarity:
TIM1->CCER &= ~TIM_CCER_CC1P;
// Установка выхода на низком уровне:
TIM1->CCER |= TIM_OCPOLARITY_LOW;
// Разрешение выхода CC1 на высоком уровне:
TIM1->CCER |= TIM_CCER_CC1E;
// Разрешение счетчика TIM1:
TIM1->CR1 |= TIM_CR1_CEN;

• TIM2

Мы используем канал 1 таймера TIM2 в режиме Output Compare для генерации сигнала PWM1.

– APB1 прескалер = 64 -1 (для получения частоты тактов таймера 1 МГц).
– Период (ARR) = 20000 мкс -> частота F2 = 50 Гц.
– Импульс (CCR1) = период / 2 (скважность 50%).
– Выбран режим master: обновление TRGO.
– Счет вверх.

// Вычисление настройки для прескалера, чтобы получить
// частоту тактов таймера 1 МГц:
Tim2Prescaler= (uint16_t) ((SystemCoreClock ) / 1000000) - 1;
// Вычисление настройки периода PWM для получения 50 Гц
// из частоты тактов 1 МГц:
Period = 1000000 / 50;
// Конфигурация периода:
TIM2->ARR = Period-1;
// Конфигурирование прескалера таймера:
TIM2->PSC = Tim2Prescaler;
// Выбор коэффициента деления тактов (Clock Divison) = 1.
// Сброс битового поля деления частоты тактов:
TIM2->CR1 &= ~ TIM_CR1_CKD;
// Выбор DIV1 в качестве коэффициента деления тактов:
TIM2->CR1 |= TIM_CLOCKDIVISION_DIV1;
// Выбор счета вверх. Сброс полей выбора режима таймера:
TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
// Режим счета вверх:
TIM2->CR1 |= TIM_COUNTERMODE_UP;
/***** Конфигурация режима Master для обновления триггера ****/
// Срабатывание триггера TIM2 для обновления TIM1 Slave:
TIM1->CR2 &= ~ TIM_CR2_MMS;
TIM2->CR2 |= TIM_TRGO_UPDATE;
/*************************************************************/
// Разрешение счетчика таймера TIM2:
TIM2->CR1 |= TIM_CR1_CEN;

• GPIO

– Вывод PA8: выход канала 1 таймера 1 (TIM1_ch1_output).
– Режим драйвера двухтактный (push pull).
– Подтяжка: pull-up.
– Скорость переключения драйвера высокая.
– Альтернативная функция: GPIO_AF6_TIM1.

Приложение разработано на плате разработчика NUCLEO-F302R8, на которой стоит микроконтроллер STM32F302x8. Тем не менее это приложение может быть легко портировано на любой микроконтроллер платформы STM32. На плате Nucleo встроен свой отладчик ST-Link/V2. Для подключения к компьютеру, прошивки программы приложения во FLASH-память микроконтроллера и отладки нужен только кабель USB (через этот же кабель подается питание на плату Nucleo).

Рис. 38 показывает упрощенную диаграмму приложения примера, которое периодически генерирует N импульсов. Комплементарные выходные сигналы выводятся через порты PA.08 и PA.07 микроконтроллера STM32F302, отображенные соответственно на вывод 8 коннектора CN9 и вывод 26 коннектора CN10.

AN4776 periodic complementary N pulses generation fig38

Рис. 38. Схема периодической генерации N-импульсов на комплементарных выходах.

Таймеры используются следующим образом:

• TIM2 конфигурируется в режиме slave-reset и как master-триггер.
• TIM1 сконфигурирован как slave и master в режиме триггера.

На два выхода выводятся комплементарные сигналы из N импульсов, и у этих сигналов сделано одинаковое конечное состояние. Результат должен быть подобен выходным сигналам, как показано на рис. 39. Исходный код для этого приложения можно просто перенастроить на другие формы сигналов, просто в этом примере в целях демонстрации реализована именно форма как на рис. 39.

AN4776 output complementary N pulses fig39

Рис. 39. Форма генерируемых комплементарных сигналов примера приложения.

[Функциональное описание]

Форма комплементарного сигнала, как показано на рис. 39, состоит в нашем случае из 20 импульсов PWM. Импульсы состоят из времени включения и выключения (on-time и off-time), t1_on и t1_off. T2_on это активное время фрейма генерации импульсов. Оба комплементарных сигнала заканчиваются в одном и том же состоянии лог. 0.

Чтобы STM32 выводил эти сигналы PWM, нужно соединить друг с другом два таймера. Один из них будет работать как комплементарный генератор PWM, и другой будет управлять окончанием генерации пачки импульсов.

Первый таймер будет управлять началом и окончанием генерации импульсом путем подсчета T2_on и управлением срабатывания генерирующего таймера для выключения выхода PWM. Таким образом, оба таймера начинают считать одновременно путем синхронизации начала счета.

Интуитивный способ реализовать это - сконфигурировать таймер генератора в режиме master-триггера, и другой таймер в режиме slave reset, и сбрасывает счетчик первого таймера, когда таймер генератора разрешен. Другими словами, генерируемый таймер конфигурируется в режиме slave-триггера, и первый таймер в режиме master-триггера для генерации события обновления, когда переполнится время счета T2_on, чем остановится генерация PWM.

Когда T2_on завершит счет, и сгенерируется триггер для таймера генератора, есть два способа остановить генерацию сигналов PWM в обработчике прерывания (ISR): либо запретить оба выхода capture/compare, или принудительно перевести выходы в неактивный режим с помощью функции коммутации.

Управление обновлением коммутации в таймере TIM1 должно быть разрешено, и сконфигурировано на срабатывание по входу TRGI путем установки поля бит CCUS в регистре TIM1_CR2. Источник прерывания коммутации разрешается путем установки бита COMIE в регистре TIM1_DIER. Конфигурация для следующего шага события коммутации (COM) должно быть запрограммировано заранее, и эта конфигурация должна принудительно переводить к неактивному уровню путем установки битового поля OC1M[2:0] регистра TIM1_CCMR1 в значение 4.

Когда таймер TIM2 выдаст сигнал триггера на входе TRGI таймера TIM1, сработает событие коммутации (COM) путем детектирования фронта нарастания. Затем поле предварительной загрузки OC1M будет передано в теневые биты на событии COM. В завершение выходы TIM1 принудительно и одновременно будут переведены в лог. 0.

Оба таймера должны быть сконфигурированы в режиме master/slave, и в таймере генератора также должны быть задействованы комплементарные выходы. Для этого примера таймер TIM1 хороший кандидат на роль генератора, потому что у него есть как комплементарные выходы, так и поддержка события коммутации. Используются выходы channel1 и channel1N канала 1 таймера TIM1. В качестве другого таймера используется TIM2.

Чтобы предотвратить канал таймера от генерации нежелательных импульсов из-за обновления регистра канала таймера, используется функция capture compare preload таймера STM32.

Чтобы избежать потери циклов перед таймером TIM1, событие обновления генерируется после разрешения его регистра канала, для чего должно быть установлено битовое поле обновления генерации (update generation, UG) в регистре TIM1_EGR. Это сделает более точной синхронизацию обоих счетчиков таймеров.

Для вывода сигнала, показанного на рис. 39, через комплементарные выходы канала 1 таймера TIM1, два таймера TIM1 и TIM2 должны быть сконфигурированы следующим образом.

Таймер TIM1, конфигурация режима master trigger-reset mode / slave-trigger. TIM1 конфигурируется в режиме master trigger-reset, чтобы подать сигнал триггера на таймер TIM2 и сбросить его счетчик. Это делается для синхронизации момента начала счета обоих таймеров. TIM1 конфигурируется также в режиме slave-trigger, чтобы событие обновления TIM2 по завершению счета периода T2_on переводило комплементарные сигналы в лог. 0.

• TIM1_ARR: содержит период одного из импульсов пачки, равный сумме интервалов t1_on и t1_off.
• TIM1_CCR1: содержит длительность интервала t1_on импульса.
• TIM1 настраивается в режиме master trigger-update / slave-trigger reset.

TIM2 конфигурируется в master trigger mode, чтобы своим событием обновления по истечении периода T2_on подать сигнал триггера на TIM1 через выход TRGO. TIM2 конфигурируется также в режиме slave-trigger reset, чтобы быть сброшенным при разрешении TIM1.

• TIM2_ARR: содержит период пачки импульсов T2_on.

Конфигурация тактов. В это примере таймеры TIM1 и TIM2 ведут счет на частоте 1 МГц.

• Входные такты TIM1 (TIM1CLK) устанавливаются от частоты APB2 (PCLK2):

TIM1CLK = PCLK2 и PCLK2 = HCLK => TIM1CLK = HCLK = SystemCoreClock = 64 МГц.

• Входные такты TIM2 (TIM2CLK) также устанавливаются от частоты APB2 (PCLK2):

TIM2CLK = PCLK2, и PCLK2 = HCLK => TIM2CLK = HCLK = SystemCoreClock = 64 МГц.

• Прескалер TIM1. Чтобы получить частоту тактов таймера TIM1 равной 1 МГц, величина программирования прескалера вычисляется так:

Prescaler = (TIM1CLK / TIM1 counter clock) - 1
Prescaler = (SystemCoreClock /1 MHz) – 1

• Прескалер TIM2. Чтобы получить частоту тактов таймера TIM2 равной 1 МГц, величина программирования прескалера вычисляется так:

Prescaler = (TIM2CLK / TIM2 counter clock) - 1
Prescaler = (SystemCoreClock /1 MHz) – 1

В этом примере таймер TIM1 должен вывести 20 импульсов, каждый импульс имеет период (t1_on + t1_off) равный 500 мкс, и скважность (t1_on) 50%. Таким образом, таймер должен быть запрограммирован так:

• Период TIM1. TIM1_ARR = T1_on+T1_off = 500 мкс.
• Скважность TIM1. TIM1_CCR1 = 250 мкс.

Вычисление периода, который мы программируем на TIM2, чтобы получить точно 20 импульсов:

• Период TIM2. TIM2_ARR = T2_ON = 500 x 20 = 10000 мкс.

Диаграмма времени на рис. 40 показывает, как синхронизированные таймеры позволяют получить нужную форму сигнала.

AN4776 timing complementary N pulses generation fig40

Рис. 40. Диаграмма времени генерации комплементарных N импульсов с одинаковым конечным состоянием.

[Firmware]

• Системные такты (System clock)

– PLL настраивается в качестве системной тактовой частоты: 64 МГц.
– В качестве задающего генератора используется HSI (не нужно запаивать HSE на плате Nucleo).
– AHB div = 1 / APB1 div = 2 / APB2 div = 1

• TIM1

Канал 1 таймера TIM1 для генерации сигнала PWM1 используется в режиме output-compare.

– Прескалер APB2 = 64 - 1 (чтобы получить частоту тактов таймера 1 МГц).
– Период (ARR) = 500. 500 мкс -> частота F1 = 2 кГц.
– Импульс (CCR1) = период / 2 (скважность 50%).
– Режим 1 PWM.
– Output compare preload: разрешено.
– Установка события обновления генерации.
– Разрешение функции коммутации.
– Режим счета вверх.
– Выбран режим master trigger reset.
– Вход триггера ITR1.
– Выбран режим slave-mode trigger.

// Вычисление величины для настройки прескалера таймера, чтобы
// получить 1 МГц в качестве тактов счетчика при частоте
// ядра SystemCoreClock = 64 МГц:
Tim1Prescaler= (uint16_t) (SystemCoreClock / 1000000) - 1;
// Вычисление периода PWM для получения частоты 2 кГц:
Period = 1000000 / 2000;
// Конфигурирование прескалера таймера:
TIM1->PSC = Tim1Prescaler;
// Конфигурирование периода:
TIM1->ARR = Period-1;
// Конфигурирование ширины импульса:
TIM1->CCR1 = Period / 2;
// Выбор коэффициента деления тактов Clock Divison = 1.
// Сброс поля коэффициента деления:
TIM1->CR1 &= ~ TIM_CR1_CKD;
// Выбор DIV1 в качестве коэффициента деления тактов:
TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1;
// Выбор счета вверх для TIM1. Сброс полей выбора режима:
TIM1->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
// Настройка счета вверх:
TIM1->CR1 |= TIM_COUNTERMODE_UP;
// Установка режима PWM1. Сброс бит режима Output Compare:
TIM1->CCMR1 &= ~TIM_CCMR1_OC1M;
TIM1->CCMR1 &= ~TIM_CCMR1_CC1S;
// Выбор режима 1 для output compare PWM:
TIM1->CCMR1 |= TIM_OCMODE_PWM1;
// Выбор лог. 1 в качестве активной полярности выхода.
// Сброс уровня полярности выхода:
TIM1->CCER &= ~TIM_CCER_CC1P;
// Установка лог. 1 для Output Compare Polarity:
TIM1->CCER |= TIM_OCPOLARITY_HIGH;
// Разрешить вывод CC1 на высоком уровне:
TIM1->CCER |= TIM_CCER_CC1E;
// Выбор активной лог. 1 в качестве уровня полярности
// комплементарного выхода. Сброс выходного состояния N:
TIM1->CCER &= ~TIM_CCER_CC1NP;
// Установка полярности выхода N на высокий уровень:
TIM1->CCER |= TIM_OCNPOLARITY_HIGH;
// Разрешение вывода CC1 на высоком уровне:
TIM1->CCER |= TIM_CCER_CC1NE;
/*********** Обновление конфигурации управления COM **********/
// Установка предзагрузки Capture Compare:
TIM1->CR2 |= TIM_CR2_CCPC;
// Установка бита CCUS для выбора обновления управления COM
// по входу триггера TRGI:
TIM1->CR2 |= TIM_CR2_CCUS;
// Разрешение источников прерывания коммутации:
TIM1->DIER |= TIM_IT_COM;
/******* Конфигурация режима Master: Trigger Reset mode ******/
// Конфигурирования обновления выходе TIM1 для подачи
// сигнала на TIM2:
TIM1->CR2 &= ~ TIM_CR2_MMS;
TIM1->CR2 |= TIM_TRGO_RESET;
/******* Конфигурация режима Slave: Trigger mode *************/
// Выбор сигнала TIM_TS_ITR1 в качестве входного для таймера:
TIM1->SMCR &= ~TIM_SMCR_TS;
TIM1->SMCR |= TIM_TS_ITR1;
// Выбор режима Slave:
TIM1->SMCR &= ~TIM_SMCR_SMS;
TIM1->SMCR |= TIM_SLAVEMODE_TRIGGER;
/*************************************************************/
// Установка бита UG для разрешения UEV:
TIM1->EGR |= TIM_EGR_UG;
// Разрешение основного выхода TIM1:
TIM1->BDTR |= TIM_BDTR_MOE;
// Разрешение счетчика TIM1:
TIM1->CR1 |= TIM_CR1_CEN;

• TIM2

Канал 1 таймера TIM2 используется в режиме output-compare для генерации сигнала PWM1.

– Прескалер APB1 = 64 - 1 (для получения 1 МГц в качестве частоты тактов таймера).
– Период (ARR) = 10000 мкс.
– Режим счета вверх.
– Выбран режим master trigger update для генерации сигнала обновления на выходе TRGO.
– Входной триггер ITR0.
– Выбран режим slave trigger reset.

// Вычисление параметра для настройки прескалера, чтобы получить
// частоту тактирования таймера 1 МГц из системной частоты
// SystemCoreClock = 64 МГц:
Tim2Prescaler = (uint16_t) ((SystemCoreClock) / 1000000) - 1;
// Вычисление параметра для установки частоты периода PWM
// 100 Гц при частоте тактов таймера 1 МГц:
Period = 1000000 / 100;
// Конфигурирование периода:
TIM2->ARR = Period-1;
// Конфигурирование прескалера:
TIM2->PSC = Tim2Prescaler;
// Выбор деления частоты тактов Clock Divison = 1.
// Сброс битового поля настройки деления частоты:
TIM2->CR1 &= ~ TIM_CR1_CKD;
// Выбор DIV1 в качестве настройки деления частоты:
TIM2->CR1 |= TIM_CLOCKDIVISION_DIV1;
// Выбор счета вверх для таймера TIM1.
// Сброс битовых полей выбора режима:
TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
// Выбор режима счета вверх:
TIM2->CR1 |= TIM_COUNTERMODE_UP;
/***** Конфигурация режима Master: обновление триггера ******/
// Триггер обновления TIM2 подает сигнал на TIM1 Slave:
TIM2->CR2 &= ~TIM_CR2_MMS;
TIM2->CR2 |= TIM_TRGO_UPDATE;
/******* Конфигурация режима Slave: Trigger mode ************/
// Выбор сигнала TIM_TS_ITR0 в качестве входного сигнала
// триггера для TIM2:
TIM2->SMCR &= ~TIM_SMCR_TS;
TIM2->SMCR |= TIM_TS_ITR0;
// Выбор режима Slave, триггер сброса:
TIM2->SMCR &= ~TIM_SMCR_SMS;
TIM2->SMCR |= TIM_SLAVEMODE_RESET;
/************************************************************/
// Разрешение счетчика TIM1:
TIM2->CR1 |= TIM_CR1_CEN;

• GPIO

– Вывод PA8: выход TIM1_CH1.
– Вывод PA7: выход TIM1_CH1N.
– Режим драйвера выхода push-pull.
– Подтяжка: pull-up.
– Скорость переключения: высокая.
– Альтернативная функция: GPIO_AF6_TIM1.

• Управление обновлением коммутации

// Сброс бит OC1M в регистре CCMR1:
TIM1->CCMR1 &= TIM_CCMR1_OC2M;
// Конфигурирование бит OC1M в неактивный режим:
TIM1->CCMR1 |= TIM_OCMODE_FORCED_INACTIVE;

[Ссылки]

1. AN4776 General-purpose timer cookbook site:st.com.
2. AN4013 STM32 cross-series timer overview site:st.com.
3. AN4277 Using STM32 device PWM shut-down features for motor control and digital power conversion site:st.com.
4190614AN4776-cube-timcooker.zip - исходный код проектов, документация.
5STM32: аббревиатуры и термины.
6STM32F4xx: продвинутые таймеры TIM1 и TIM8.