Продолжая цикл публикаций по микроконтроллерам на ядре Cortex-M0 компании Megawin (см. предыдущие статьи 1, 2, 3, 4 и 5), сегодня рассмотрим таймеры общего назначения.
Функциональные возможности таймеров МК серии MG32F02
МК MG32F02x064, MG32F02x128 включают 7 таймеров общего назначения четырех типов TM00/01, TM10/16, TM20/26 и TM36. МК MG32F02A032 включает 5 таймеров трех типов TM00/01, TM10/16, и TM36. Таймеры имеют общий базовый принцип построения, но различаются функциональными возможностями, которые возрастают с увеличением первой цифры в названии.
Таймеры имеют следующие общие функциональные возможности:
основной счетчик (CT1) и предделитель (CT2) с одинаковой разрядностью (8 или 16);
три режима работы предделителя и счетчика: раздельный, каскадный, совмещенный (общая разрядность 16 или 32);
направление счета предделителя вверх или вниз;
выбор источника сигнала внутреннего тактирования модуля с делением частоты на 1, 2, 4 или 8;
выбор внешнего (с вывода МК) или внутреннего сигнала тактирования отдельно для CT1 и CT2;
выбор внешнего или одного из 8 внутренних сигналов (событий) МК в качестве входного триггерного сигнала;
выбор события для генерации выходного триггерного сигнала для других модулей МК;
коммутация выходного триггерного сигнала на внешний вывод МК;
коммутация сигнала переполнения от CT1 или CT2 на внешний вывод МК;
режим "автостоп";
генерация прерывания по выбранному событию в модуле;
работа в режимах ON и SLEEP.
Различия в функциональных возможностях таймеров приведены в таблице.
Функция | TM00/01 | TM10/16 | TM20/26 | TM36 |
|---|---|---|---|---|
Разрядность основного счетчика | 8 | 16 | 16 | 16 |
Разрядность предделителя | 8 | 16 | 16 | 16 |
Независимые каналы | - | - | 2 | 4 |
Входы захвата (IC) | - | - | 2 | 4 |
Входной сигнал отключения выходов (Input Break) | - | - | - | + |
Выходы схемы сравнения (OC) | - | - | 2 | 4 |
Комплементарные выходы схемы сравнения (OCN) | - | - | 2 | 3 |
Выходы схемы сравнения для раздельного 8-битного режима (OCH) | - | - | 2 | 4 |
Режим ШИМ | - | - | + | + |
Режим ШИМ с выравниванием по центру | - | - | - | + |
Формированием "мертвого" времени | - | - | - | + |
Направление счета вверх основного счетчика | + | + | + | + |
Направление счета вниз основного счетчика | - | TM16 | TM26 | + |
Дополнительный счетчик для режима "автостоп" | - | - | + | + |
Интерфейс квадратурного энкодера | - | - | TM26 | + |
Сигнал XOR из 3-х сигналов IC в качестве сигнала захвата канала 0 | - | - | - | + |
Задержка выходного сигнала | - | - | + | + |
Поддержка DMA | - | - | - | + |
Функциональная схема включает общую для всех таймеров часть, приведенную на следующем рисунке, и часть дополнительных функций, которая далее будет рассматриваться отдельно для каждого типа таймера.

Общая часть включает:
блок формирования внутреннего сигнала тактирования, сигналов тактирования счетчиков TMx_CK_TC и TMx_CK_TC2 (Clock Control);
блок формирования входного триггерного и выходного триггерного сигналов (Trigger Control);
блок счетчиков (Counter Stage), состоящий из основного счетчика Main Timer (далее — CT1) и предделителя 2nd Timer (Prescaler) (далее — CT2) с одинаковой разрядностью;
блок формирования сигнала прерывания модуля INT_TMx (Interrupt Control).
Тактирование
На следующем рисунке представлена более подробная схема блоков Counter Stage и Trigger Control.

Источник внутреннего тактового сигнала модуля CK_TMx определяется значением поля TMx_CLK.TMx_CKI_SEL:
0 — сигнал CK_TMx_PR из подсистемы тактирования МК, который, в свою очередь, определяется битом
CSC_CKS2.CSC_TMx_CKSиз сигналов CK_APB (0) или CK_AHB (1);2 — общесистемный НЧ-сигнал CK_LS, частота которого должна быть не выше половины частоты сигнала CK_TMx_PR.
Сигнал CK_TMx подается на делитель частоты с коэффициентом 1, 2, 4 или 8 (выбирается в поле TMx_CLK.TMx_CKI_DIV), на выходе которого формируется внутренний тактовый сигнал CK_TMx_INT. Альтернативный тактовый сигнал CK_TMx_EXT в зависимости от значения поля TMx_CLK.TMx_CKE_SEL формируется из одного из сигналов:
0 — внешний сигнал TMx_ETR с вывода МК,
1 — сигнал TMx_ITR с выхода мультиплексора выбора одного из доступных триггерных сигналов для данного таймера ITR_MUX (см. описание далее),
2 и 3 — дополнительные входные сигналы таймера TMx_IN0 и TMx_IN1 (только для таймеров TM20/26 и TM36).
Итоговый сигнал счетных импульсов TMx_CK_TC основного счетчика CT1 выбирается битом TMx_CLK.TMx_CKS_SEL из сигналов: CK_TMx_INT (0) или CK_TMx_EXT (1). Аналогично выбирается сигнал счетных импульсов TMx_CK_TC2 счетчика CT2 по значению бита TMx_CLK.TMx_CKS2_SEL.
В таймере TM36 сигнал CK_TMx также подается на другой делитель частоты с коэффициентом 1, 2, 4 или 8 (выбирается в поле TM36_CLK.TM36_DTG_DIV), на выходе которого сигнал TMx_CK_DTG используется для формирования "мертвого" времени в режиме ШИМ.
Режимы работы счетчиков
Выбор режима
В каждом таймере счетчики CT1 и CT2 могут быть настроены на работу в одном из трех режимов:
раздельном (Separate Mode) — каждый счетчик тактируется и работает независимо от другого;
каскадном (Cascade Mode) — счетчик CT2 выполняет функцию предделителя для основного счетчика CT1 (по-умолчанию);
совмещенном (Full-Counter Mode) — оба счетчика объединяются в единый счетчик с общей разрядностью 16 или 32.
Режим работы счетчиков задается в поле TMx_CR0.TMx_MDS. При использовании счетчика CT1 он должен быть включен установкой бита TMx_CR0.TMx_EN. При использовании счетчика CT2 в первых двух режимах необходимо установить бит TMx_CR0.TMx_EN2; в совмещенном режиме CT2 включается автоматически вместе с CT1 установкой бита TMx_CR0.TMx_EN.
Раздельный режим (Separate)
В раздельном режиме счетчики включаются и функционируют независимо друг от друга. Счетчик CT1 переключается под действием импульсов сигнала TMx_CK_TC. В таймерах TM00/01, TM10 и TM20 возможен счет только вверх, в остальных таймерах — в обе стороны, направление счета задается битом TMx_CR0.TMx_DIR. Текущее значение счетчика доступно по чтению и записи в регистре TMx_CNT (разряды 0-7 или 0-15 в зависимости от типа таймера). В регистре TMx_ARR (Auto-Reload Register) задается значение автозагрузки счетчика (разряды 0-7 или 0-15). При счете вверх при превышении этого значения генерируется событие Timer Overflow и устанавливается флаг TOF, а счетчик сбрасывается в 0. При счете вниз из нулевого состояния генерируется событие Timer Underflow и устанавливается флаг TUF, а в счетчик загружается значение TMx_ARR. По-умолчанию значение автозагрузки равно 0. Частота полного цикла счета будет определяться выражением
F1 = F(CK_TC) / (ARR + 1) ,
где F(CK_TC) — частота входных счетных импульсов счетчика CT1, ARR — значение регистра TMx_ARR.
Счетчик CT2 переключается под действием импульсов сигнала TMx_CK_TC2. Направление счета задается битом TMx_CR0.TMx_DIR2 для всех таймеров. Текущее значение счетчика доступно по чтению и записи в поле TMx_PSCNT регистра TMx_PSCNT (разряды 0-7 или 0-15). В этом же регистре в поле TMx_CNTA продублировано текущее значение счетчика CT1 (разряды 8-15 или 16-31 в зависимости от типа таймера), поле доступно только по чтению. В регистре TMx_PSARR (Prescaler Auto-Reload Register) задается значение автозагрузки счетчика CT2 (разряды 0-7 или 0-15), которое используется аналогично основному счетчику. При счете вверх при превышении этого значения генерируется событие Timer Overflow и устанавливается флаг TOF2, а счетчик сбрасывается в 0. При счете вниз из нулевого состояния генерируется событие Timer Underflow и устанавливается флаг TUF2, а в счетчик загружается значение TMx_PSARR. Частота полного цикла счета будет определяться выражением
F2 = F(CK_TC2) / (PSARR + 1) ,
где F(CK_TC2) — частота входных счетных импульсов счетчика CT2, PSARR — значение регистра TMx_PSARR.
Каскадный режим (Cascade)
В каскадном режиме счетчик CT2 выполняет функцию предделителя для основного счетчика CT1. Счетчик CT2 переключается под действием импульсов сигнала TMx_CK_TC2, а счетчик CT1 — по завершению каждого цикла CT2. В остальном счетчики настраиваются независимо. Частота FC полного цикла счета CT1 будет определяться выражением
FC = F(CK_TC2) / [ (ARR + 1)·(PSARR + 1) ] .
Совмещенный режим (Full-Counter)
В совмещенном режиме оба счетчика объединяются в единый счетчик с общей разрядностью 16 (для таймеров TM00/01) или 32 (для остальных таймеров). Счетчик CT1 представляет старшие разряды (High), а счетчик CT2 — младшие разряды (Low). Единый счетчик переключается под действием импульсов сигнала TMx_CK_TC2. В таймерах TM00/01, TM10 и TM20 возможен счет только вверх, в остальных таймерах — в обе стороны согласно значению бита TMx_CR0.TMx_DIR. Значение автозагрузки счетчика формируется из значений регистра TMx_ARR (старшие 8 или 16 бит) и TMx_PSARR (младшие 8 или 16 бит). При наступлении события Timer Overflow единого счетчика устанавливаются оба флага TOF и TOF2. При наступлении события Timer Underflow устанавливаются оба флага TUF и TUF2. Частота FF полного цикла счета будет определяться выражением
FF = F(CK_TC2) / ( 2N ·ARR + PSARR + 1) ,
где N — разрядность одного счетчика (8 или 16) в зависимости от типа таймера.
Событие обновления счетчиков
В таймере формируются два внутренних сигнала обновления счетчиков TMx_UEV и TMx_UEV2. Схема их формирования показана на следующем рисунке.

Сигнал TMx_UEV активируется при завершении каждого цикла счетчика CT1. В поле TMx_TRG.TMx_UEV_SEL определяется событие активизации: TOF, TUF или оба (по-умолчанию). В последнем случае можно генерировать событие программно установкой бита TMx_CR0.TMx_USW_EN, а также можно использовать сигнал TMx_TRGI_EX при установке бита TMx_CR0.TMx_UEX_EN. Сигнал TMx_TRGI_EX формируется из сигнала TMx_TRGI (см. описание далее) при установленном бите разрешения TMx_CR0.TMx_EX_EN с опциональным инвертированием при установленном бите TMx_CR0.TMx_EX_INV.
Сигнал TMx_UEV2 активируется при завершении каждого цикла счетчика CT2 по событиям TOF2 и TUF2. Сигналы TMx_UEV и TMx_UEV2 могут быть выбраны источником выходного триггерного сигнала TMx_TRGO, если в поле TMx_TRG.TMx_TRGO_MDS установлено соответствующее значение.
Выходной сигнал таймера CKO и функция автостопа
В каждом таймере имеется возможность коммутации выходного сигнала счетчиков на внешний вывод МК TMx_CKO. Схему иллюстрирует следующий рисунок.

Источником сигнала TMx_CKOM в зависимости от значения поля TMx_CKO.TMx_CKO_SEL может быть:
сигнал TMx_CKO1 с выхода счетчика CT1,
сигнал TMx_CKO2 с выхода счетчика CT2 (по-умолчанию).
Если установлен бит TMx_CKO.TMx_CKO_EN, сигнал TMx_CKOM проходит на выходной узел формирования сигнала TMx_CKO. Выходной сигнал формируется с помощью T-триггера: при каждом импульсе сигнала TMx_CKOM логическое состояние выхода TMx_CKO изменяется на противоположное. Таким образом, на выходе TMx_CKO формируется сигнал, частота которого в 2 раза ниже частоты сигналов TMx_CKO1 или TMx_CKO2. Начальное состояние выхода TMx_CKO определяется битом TMx_CKO.TMx_CKO_STA, изменение значения этого разряда возможно при одновременной записи логической "1" в разряд TMx_CKO_LCK этого же регистра.
В таймере ��меется возможность автоматической остановки счетчика CT2 при завершении цикла счетчика CT1. Данная функция включается установкой бита TMx_CR0.TMx_ASTOP_EN. Счетчик CT2 продолжит считать после программного сброса флагов TOF или TUF (в зависимости от направления счета), при этом в совмещенном режиме единый счетчик начнет считать с начального состояния. Если установлен бит TMx_CR0.TMx_ACLEAR_EN, то при срабатывании автостопа также сбрасываются флаги TOF и TUF.
Счетчик повторений
В состав таймеров TM20/26 и TM36 (кроме МК MG32F02A032) входит дополнительный блок, предназначенный для остановки счетчиков после заданного числа циклов счета. Блок основан на 8-разрядном счетчике обратного отсчета Repetition Counter (далее — RCT). В поле TMx_RCNT регистра TMx_RCNT по чтению и записи доступно значение счетчика, а в поле TMx_RARR — значение для его перезагрузки после достижения нуля. Работа счетчика разрешается установкой бита TMx_CR0.TMx_RC_EN. Останов счета основного счетчика CT1 при завершении цикла счета RCT разрешается установкой бита TMx_CR0.TMx_RC_STP. По завершению одного цикла счета RCT активируется флаг RTUF.
Источник тактовых импульсов для RCT выбирается в поле TMx_CLK.TMx_RC_CKS из числа следующих:
сигнал TMx_CKO1 с выхода счетчика CT1 (по-умолчанию),
сигнал TMx_CKOM.
Блок формирования входного триггерного сигнала
Все настройки блока осуществляются через регистр TMx_TRG. Входной триггерный сигнал таймера TMx_TRGI в зависимости от значения поля TMx_TRG_MUX формируется из одного из сигналов TMx_ETR, TMx_ITR, TMx_IN0 или TMx_IN1 (аналогично сигналу CK_TMx_EXT). В поле TMx_ITR_MUX выбирается один из восьми доступных для данного таймера источников сигнала TMx_ITR согласно приведенной ниже таблице.

Общесистемные триггерные сигналы ITR6 и ITR7 для всего МК выбираются через поля APB_ITR6_MUX и APB_ITR7_MUX регистра APB_CR2 согласно следующей таблице.

Для управления счетчиками используются следующие три сигнала:
Reset (TMx_RST, TMx_RST2) — для сброса счетчика в 0 при возрастающем счете или для перезагрузки значения из регистров
TMx_ARR/TMx_PSARRпри убывающем счете;Gated Clock (TMx_GT, TMx_GT2) — для отключения подачи счетных импульсов на вход счетчиков;
Trigger (TMx_TR, TMx_TR2) — для запуска счетчика по сигналу в соответствии с установленным условием.
Сигнал TMx_TRGI может быть использован для формирования одного из трех управляющих сигналов для каждого счетчика. Формируемый сигнал и активный уровень определяются полями TMx_TRGI_MDS и TMx_TRGI2_MDS для счетчиков CT1 и CT2 соответственно. Схема формирования управляющих сигналов счетчиков приведена на следующем рисунке.

Счетчики CT1 и CT2 могут быть сброшены программно установкой битов TMx_TRG.TMx_RST_SW и TMx_TRG.TMx_RST2_SW соответственно. Для возобновления счета эти биты должны быть сброшены. Также возможно отключение подачи счетных импульсов на входы счетчиков установкой битов TMx_TRG.TMx_GT_SW и TMx_TRG.TMx_GT2_SW соответственно. В совмещенном режиме сброс единого счетчика осуществляется установкой бита TMx_TRG.TMx_RST_SW, а отключение подачи счетных импульсов на вход — установкой бита TMx_TRG.TMx_GT_SW.
Блок формирования выходного триггерного сигнала
На следующем рисунке показана общая схема формирования выходного (триггерного) сигнала таймера TMx_TRGO. Не все указанные события могут быть доступны в конкретном типе таймера.

Все настройки блока также осуществляются через регистр TMx_TRG. Событие для формирования сигнала TMx_TRGO определяется значением поля TMx_TRGO_MDS. Сигнал TMx_TRGO может быть использован как входной сигнал (управляющий или счетный) для других периферийных модулей МК и может быть выведен на внешний вывод МК (см. таблицу AFS на конкретный тип МК). Сигнал TMx_TRGO может быть проинвертирован, если будет установлен бит TMx_TRGO_INV.
Сигналом TMx_TRGO можно управлять программно путем установки и сброса бита TMx_TRGO_SW, если в качестве источника выбран SW (9). Если в качестве источника выбирается событие UEV, то в поле TMx_UEV_SEL можно задать один из трех вариантов формирования выходного сигнала: по переполнению счетчика CT1, по достижению нуля счетчиком CT1, либо оба события (по-умолчанию). Остальные события будут рассмотрены далее.
Таймеры TM00/01 и TM10/16
Данные таймеры представляют собой базовый вариант с минимальным функционалом, поэтому не включают часть дополнительных функций. Их общая часть соответствует приведенной выше функциональной схеме за исключением того, что сигналы TMx_IN0 и TMx_IN1 не поддерживаются. Таймеры TM00/01 отличаются от TM10/16 только разрядностью счетчиков (8 и 16 соответственно). Таймер TM16 отличается возможностью счета вниз для счетчика CT1.
Таймеры TM20/26
Функциональная схема
Функциональная схема таймеров TM20/26 приведена на следующем рисунке.

Часть дополнительных функций включает двухканальную схему захвата/сравнения, состоящую из следующих блоков:
блок формирования входных управляющих сигналов для каждого канала таймера (Input Stage),
блок захвата/сравнения (Capture/Compare),
блок формирования выходных сигналов для каждого канала таймера (Output Stage).
В составе каждого блока захвата/сравнения имеются два 16-разрядных регистра CCnA и CCnB, программно доступные по чтению и записи как TMx_CCnA и TMx_CCnB, где n — номер канала 0 или 1. Схема может работать в одном из следующих режимов, задаваемом в поле TMx_CCMDS.TMx_CCn_MDS:
NOP(0) — схема отключена;16bit_IC(1) — захват по входному сигналу,16bit_OC(2) — выход по сравнению в режиме 16 бит,8bitx2_OC(3) — два выхода по сравнению в режиме 8 бит,16bit_PWM(4) — 16-битный формирователь ШИМ-сигнала,8bitx2_PWM(5) — два 8-битных формирователя ШИМ-сигнала.
Рассмотрим каждый из режимов работы подробнее.
Захват по входному сигналу
В этом режиме (16bit_IC) в регистрах CCnA и CCnB сохраняется состояние счетчиков в момент срабатывания входного триггера. Схема захвата для одного канала приведена на следующем рисунке.

Каждый канал имеет один вход, на который подается сигнал TMx_ISn, где n — номер канала 0 или 1. Этот сигнал поступает с выхода блока Edge Select, в котором определяется активный фронт входного триггерного сигнала TMx_INn согласно значению поля TMx_ICCR.TMx_ICn_TRGS: 0 — отключен, 1 — нарастающий (передний), 2 — спадающий (задний), 3 — оба фронта. Источник сигнала TMx_INn выбирается в поле TMx_ICCR.TMx_ICn_MUX из следующих:
внешний вывод МК TMx_ICn,
внутренний сигнал таймера TMx_ITR (см. схему блоков Counter Stage и Trigger Control выше),
выход компаратора CMPn_OUT.
Если в поле TMx_ICCR.TMx_ICn_TRGS выбрано срабатывание по одному из фронтов (1 или 2), то в зависимости от режима работы счетчиков схема работает следующим образом:
в раздельном и каскадном режимах в регистре CCnA сохраняется значение счетчика CT1 при первом срабатывании триггера, а в регистре CCnB — значение счетчика CT1 при втором срабатывании триггера;
в совмещенном режиме 32-битное значение единого счетчика сохраняется при каждом срабатывании триггера: старшие 16 бит — в регистре CCnA, младшие 16 бит — в регистре CCnB.
После первого срабатывания триггера и сохранения значения счетчика активируется флаг CFnA, а после второго срабатывания — флаг CFnB, показывая тем самым готовность данных для считывания. Если после этого данные из регистров CCnA и CCnB не были востребованы программой, к началу следующего события захвата возникает состояние "Overrun".
Если в поле TMx_ICCR.TMx_ICn_TRGS выбрано срабатывание по обоим фронтам (3), то схема работает следующим образом:
в раздельном и каскадном режимах в регистре CCnA сохраняется значение счетчика CT1 при нарастающем фронте импульса сигнала TMx_INn, а в регистре CCnB — значение счетчика CT1 при спадающем фронте импульса;
в совмещенном режиме 32-битное значение единого счетчика сохраняется в регистрах CCnA и CCnB при каждом срабатывании триггера.
Флаг CFnA активируется после сохранения значения единого счетчика при нарастающем фронте импульса, а флаг CFnB — при спадающем. Если после этого данные из регистров CCnA и CCnB не были востребованы программой, к началу следующего события захвата также возникает состояние "Overrun".
При возникновении состояния "Overrun" в зависимости от значения поля TMx_CR1.TMx_OVRn_MDS (отдельно для каждого канала) происходит следующее:
Overwritten (0) — регистры CCnA и CCnB перезаписываются новыми данными (по-умолчанию),
Keep (1) — регистры CCnA и CCnB не перезаписываются, сохраняются старые данные.
Генерация сигналов сравнения и ШИМ в 16-битном режиме
В данных режимах каждый регистр CCnA используется в качестве "теневого" 16-разрядного регистра (Shadow), с которым фактически сравнивается значение счетчика CT1. Регистр CCnB (TMx_CCnB) используется для предварительной загрузки значения сравнения (Preload) из программы. Специальный бит TMx_CCMDS.TMx_OC_LCK управляет синхронным обновлением регистров CCnA для всех каналов таймера. Когда бит установлен (locked), новые данные из регистров CCnB не загружаются в регистры CCnA, пока бит не будет сброшен. После сброса бита (unlocked, по-умолчанию) регистры CCnA будут синхронно обновлены после завершения очередного цикла счета (по сигналу TMx_UEV).
На следующем рисунке показана схема сравнения и формирования выходных сигналов в 16-битном режиме.

Основным выходным сигналом блока сравнения является TMx_OSn. В режимах 16bit_OC и 8bitx2_OC его начальный уровень задается битом TMx_OSCR.TMx_OSn_STA (по-умолчанию 0). Изменение значения этого бита возможно при одновременной записи логической "1" в разряд TMx_OSn_LCK этого же регистра. Алгоритм управления сигналом зависит от режима работы.
В режиме генерации сигнала сравнения (16bit_OC) при счете вверх уровень сигнала TMx_OSn изменяется на противоположный в момент достижения счетчиком CT1 значения CCnB, при этом активируется флаг CFnA. При достижении этого же значения в следующем цикле счета уровень сигнала TMx_OSn возвращается к начальному, при этом также активируется флаг CFnA. Временная диаграмма работы таймера показана на следующем рисунке.

Здесь коэффициент счета CT1 ARR (значение регистра TMx_ARR) выбран равным 8, показаны сигналы TMx_OSn для двух разных начальных уровней при OCnB=2 и для варианта высокого начального уровня при OCnB=8. Если значение OCnB больше ARR, состояние сигнала TMx_OSn не изменяется.
В режиме формирования ШИМ-сигнала (16bit_PWM) в начале цикла счетчика CT1 сигнал TMx_OSn переходит в состояние высокого уровня. При счете вверх в момент достижения счетчиком значения CCnB сигнал TMx_OSn переходит в состояние низкого уровня. Флаг CFnA активируется только в момент достижения значения CCnB. Длительность одного цикла счета составляет (ARR+1) тактов, а коэффициент заполнения — CCnB/(ARR+1) тактов. Пример временной диаграммы работы таймера показан на рисунке.

Здесь показаны случаи при значениях OCnB — 2, 6 и 8. Если значение OCnB больше ARR, сигнал TMx_OSn всегда остается в состоянии высокого уровня. Если значение OCnB равно нулю, сигнал TMx_OSn всегда остается в состоянии низкого уровня. Настройка начального уровня в поле TMx_OSn_STA в режиме ШИМ не используется.
В режиме формирования ШИМ-сигнала (16bit_PWM) при счете вниз сигнал TMx_OSn переходит в состояние низкого уровня в момент переключения счетчика CT1 со значения CCnB на (CCnB-1), при этом также активируется флаг CFnA. Если значение OCnB больше значения ARR, сигнал TMx_OSn всегда остается в состоянии низкого уровня. Если значение OCnB равно нулю, сигнал TMx_OSn всегда остается в состоянии высокого уровня. Пример временной диаграммы работы таймера в таком режиме показан на следующем рисунке.

Генерация сигналов сравнения и ШИМ в 8-битном режиме
На следующем рисунке показана схема сравнения и формирования выходных сигналов в 8-битном режиме.

В 8-битных режимах регистр CCnA разделяется на два 8-битных теневых регистра — старший CCnAH и младший CCnAL. Аналогично разделяется регистр загрузки CCnB на соответствующие старший CCnBH и младший CCnBL регистры. Сравнение выполняется отдельно для младшего (L) и для старшего (H) регистров, причем в сравнении участвуют только младшие 8 разрядов счетчика CT1. Соответственно, в каждом канале таймера формируется второй выходной сигнал TMx_OSnH сравнения старшего регистра, а сигналом сравнения младшего регистра остается TMx_OSn.
Начальный (неактивный) уровень сигнала TMx_OSnH задается битом TMx_OSCR.TMx_OSnH_STA. Изменение значения этого бита возможно при одновременной записи логической "1" в разряд TMx_OSnH_LCK этого же регистра.
Флаг CFnA активируется при совпадении в младшей части (L), а флаг CFnB — при совпадении в старшей (H) в обоих режимах 8bitx2_OC и 8bitx2_PWM.
Блок формирования выходных сигналов каналов сравнения
Рассмотрим блок формирования выходных сигналов одного канала таймеров TM20/26.

В общем случае имеется три типа выходных сигналов схемы сравнения (n — номер канала):
TMx_OCn — основной сигнал сравнения или ШИМ-сигнал,
TMx_OCnN — комплементарный к TMx_OCn сигнал,
TMx_OCnH — сигнал сравнения в старшей части для 8-битных режимов.
Для каждого из сигналов можно выбрать инвертирование установкой соответствующих битов TMx_OCn_INV, TMx_OCnN_INV и TMx_OCnH_INV в регистре TMx_OCCR1.
Сигнал TMx_OCn может быть выведен на три разных вывода, каждый из которых включается независимо. Таким образом, на внешние выводы ("пины") МК от каждого канала можно вывести всего 5 сигналов: TMx_OCn0, TMx_OCn1, TMx_OCn2, TMx_OCnN и TMx_OCnH. Вывод сигналов TMx_OCn{0,1,2} и TMx_OCnN разрешается установкой соответствующих разрядов TMx_OCn_OE{0,1,2} и TMx_OCnN_OE в регистре TMx_OCCR0.
Возможно включение небольшой задержки сигналов канала 1 по отношению к сигналам канала 0 путем установки бита TMx_OCCR1.TMx_ODLY_SEL. Согласно User Guide, величина задержки составляет 3-5 нс, ее зависимость от тактовой частоты не указывается.
Таймер TM36
Функциональная схема
Функциональная схема таймера TM36 приведена на следующем рисунке.

Таймер TM36 отличается от TM20/26 следующими функциональными возможностями:
4 канала в схеме захвата/совпадения,
схема формирования "мертвого" времени для режима ШИМ (DTG),
возможность генерации "центрированных" ШИМ-сигналов,
отключение выходов по входному сигналу (блок Break Input Source),
работа в режиме DMA.
Далее рассмотрим те функции и блоки, которые отличаются от таймеров TM20/26.
Захват по входному сигналу
В данном блоке добавлена возможность использования на каналах 0 и 3 внутреннего сигнала TMx_XOR, который формируется на выходе схемы "Исключающее ИЛИ" из внешних сигналов IC0, IC1 и IC2. Сигналы от компараторов CMP0_OUT и CMP1_OUT как входные доступны только для каналов 0 и 1.
Генерация "центрированных" ШИМ-сигналов в 16-битном режиме
В таймере TM36 в поле TMx_PWM.TMx_PWM_MDS возможно включение режима ШИМ с выравниванием выходных импульсов всех каналов по центру. Общий цикл формирования ШИМ-сигнала увеличивается до 2·ARR тактов по сравнению с обычным выравниванием с циклом длительностью (ARR+1) тактов.
В начале цикла сигнал TMx_OSn находится в состоянии высокого уровня, счетчик CT1 начинает считать вверх от 0 до значения ARR. При достижении счетчиком значения CCnB сигнал TMx_OSn переходит в состояние низкого уровня и активируется флаг CFnA. В момент, когда значение счетчика изменяется с (ARR-1) на ARR, генерируется событие Timer Overflow и активируется флаг TOF. Этот момент является центром отрицательного импульса длительностью 2·(ARR-CCnB) тактов.
Далее счетчик продолжает считать вниз. При достижении счетчиком значения CCnB сигнал TMx_OSn возвращается в состояние высокого уровня и активируется флаг CFnB. В момент, когда значение счетчика изменяется с 1 на 0, генерируется событие Timer Underflow и активируется флаг TUF. Этот момент является центром положительного импульса длительностью 2·CCnB тактов. Далее счетчик продолжает считать от 0 вверх и цикл повторяется. Временная диаграмма работы таймера показана на следующем рисунке.

В режиме формирования ШИМ-сигнала 8bitx2_PWM флаг CFnA активируется при совпадении в младшей части (L) при счете вверх, а флаг CFnB активируется при совпадении в младшей части (L) при счете вниз.
Формирование "мертвого" времени
В блок формирования выходных сигналов каналов 0-2 добавлена схема формирования "мертвого" времени DTG (Dead Time Generator). На следующем рисунке показаны временные диаграммы работы схемы.

Формирование ШИМ-сигнала в каждом канале осуществляется с помощью дополнительных внутренних комплементарных сигналов TMx_DTn и TMx_DTnN, которые далее используются как выходные сигналы TMx_OCn и TMx_OCnN. Нарастающий фронт сигнала TMx_DTn задерживается относительно нарастающего фронта сигнала TMx_OSn, а нарастающий фронт сигнала TMx_DTnN задерживается относительно спадающего фронта сигнала TMx_OSn. В итоге между положительными импульсами сигналов TMx_DTn и TMx_DTnN возникает постоянная задержка, величина которой устанавливается в поле TM36_PWM.TM36_DTG_DY в периодах сигнала TMx_CK_DTG. Задержка одинаковая для всех каналов и по-умолчанию равна 0, т.е. формирования "мертвого" времени не происходит. Сигнал TMx_CK_DTG формируется на выходе делителя частоты из тактового сигнала CK_TMx, коэффициент деления 1, 2, 4 или 8 задается в поле TM36_CLK.TM36_DTG_DIV. Формирование "мертвого" времени может быть полезно при управлении "верхним" и "нижним" силовыми ключами в мостовой и полумостовой схемах для исключения сквозного тока в моменты переключения.
Блок формирования выходных сигналов каналов сравнения
В таймере TM36 схемы формирования выходных сигналов каналов сравнения 2 и 3 отличаются от каналов 0,1 (см. рисунок).

В каналах 0,1 для формирования сигналов TMx_OCn{0,1,2} и TMx_OCnN вместо сигналов TMx_OSn и TMx_OSnN используются сигналы TMx_DTn и TMx_DTnN. Канал 2 имеет только три внешних вывода TMx_OC2, TMx_OC2N и TMx_OC2H, а канал 3 — два вывода TMx_OC3 и TMx_OC3H. Во всех каналах для управления выходными сигналами TMx_OCn добавлена возможность использования внешнего сигнала TMx_BK_INT.
Флаги событий и прерывания
Флаги событий всех типов таймеров собраны в регистре TMx_STA, а биты разрешения прерываний — в регистре TMx_INT. Перечень событий и соответствующих флагов прерываний приведен в следующей таблице.
Разряд | Флаг события | Бит прерывания | Название события | Описание | Наличие |
|---|---|---|---|---|---|
0 | DIRF | - | Main Timer up/down counting | Направление счета счетчика CT1 | TM16, TM26, TM36 |
2 | BKF | BKIE | Break input | Сигнал отключения выходов | TM36 |
3 | EXF | EXIE | External trigger | Срабатывание внешнего триггерного сигнала | все |
4 | TOF | TIE | Main Timer overflow | Переполнение счетчика CT1 | все |
5 | TOF2 | TIE2 | 2nd Timer overfloww | Переполнение счетчика CT2 | все |
6 | TUF | TIE | Main Timer underflow | Переход через 0 при счете вниз счетчика CT1 | TM16, TM26, TM36 |
7 | TUF2 | TIE2 | 2nd Timer underflow | Переход через 0 при счете вниз счетчика CT2 | все |
8 | CF0A | CC0_IE | Input capture/output compare A, channel 0 | Событие A захвата/совпадения канала 0 | TM2x, TM36 |
9 | CF1A | CC1_IE | Input capture/output compare A, channel 1 | Событие A захвата/совпадения канала 1 | TM2x, TM36 |
10 | CF2A | CC2_IE | Input capture/output compare A, channel 2 | Событие A захвата/совпадения канала 2 | TM36 |
11 | CF3A | CC3_IE | Input capture/output compare A, channel 3 | Событие A захвата/совпадения канала 3 | TM36 |
12 | CF0B | CC0_IE | Input capture/output compare B, channel 0 | Событие B захвата/совпадения канала 0 | TM2x, TM36 |
13 | CF1B | CC1_IE | Input capture/output compare B, channel 1 | Событие B захвата/совпадения канала 1 | TM2x, TM36 |
14 | CF2B | CC2_IE | Input capture/output compare B, channel 2 | Событие B захвата/совпадения канала 2 | TM36 |
15 | CF3B | CC3_IE | Input capture/output compare B, channel 3 | Событие B захвата/совпадения канала 3 | TM36 |
16 | DIRCF | DIRC_IE | Main Timer up/down counting direction change flag | Смена направления счета счетчика CT1 | TM26, TM36 |
18 | IDXF | IDX_IE | QEI external index signal input active detect and internal timer reset flag | Активность внешнего индексного сигнала | TM26, TM36 |
19 | QPEF | QPE_IE | QEI phase state transition errors detect | Ошибка детектирования фазы энкодера | TM26, TM36 |
20 | RTUF | RTU_IE | Repetition timer underflow | Переполнение счетчика повторений | TM2x, TM36 (*1) |
Примечание: (*1) В МК MG32F02A032 флаг RTUF не поддерживается.
Для включения генерации прерывания необходимо:
Выбрать событие (или события) в регистре
TMx_INT.Разрешить прерывание самого модуля установкой бита
TMx_INT.TMx_IEA.Разрешить прерывание IRQ от модуля в контроллере прерываний NVIC в регистре
CPU_ISER.
Тестирование таймеров
Подготовка
В базовую часть кода ("прошиваемую" во flash-память) в файл svr.c добавлены функции-обработчики прерываний таймеров IRQ с номерами 12-17. Для работы с портом PA в функцию init_clock() в файле init.c добавлено включение его тактирования. Для экономии места в статье этот код не приводится.
Для удобства работы с таймерами создано несколько общих функций. Файлы timer.h и timer.c включают объявление перечисления enum TimerID с идентификаторами таймеров TM00_id - TM36_id, а также функции:
tm_init(uint8_t tm_id)— инициализация таймера (включение тактирования),tm_setup_int(uint8_t tm_id, uint32_t flags)— включение прерывания INT_TMx по флагам, указанным вflagsсогласно формату регистраTMxx_INT.
Файл timer_test.с включает все далее рассматриваемые функции тестирования, а также общие функции настройки режима работы счетчиков таймеров:
tm_setup_separate(uint8_t tm_id, uint32_t mode, uint16_t khi, uint16_t klo)— раздельный режим,tm_setup_cascade(uint8_t tm_id, uint32_t mode, uint16_t khi, uint16_t klo)— каскадный режим,tm_setup_fullcnt(uint8_t tm_id, uint32_t mode, uint32_t k)— совмещенный режим.
В аргументе mode можно задать дополнительные биты настройки по формату регистра TMx_CR0, кроме полей TMx_MDS, TMx_EN, TMx_EN2, которые задаются в самих функциях. Для 16-битных режимов в аргументах khi и klo задаются периоды счета счетчиков CT1 и CT2 (с вычетом единицы), а для 32-битного режима период задается в k.
Напомню, что весь исходный код и сопутствующие файлы доступны в репозитории GitHub. Также отмечу, что в репозитории обновлена библиотека mg32f02_mem_ap.tcl и конфигурационные файлы для МК mg32f02a032.cfg, mg32f02a064.cfg. Изменения следующие:
добавлена поддержка страниц flash-памяти размером 512 байт, задание размера происходит в файлах
*.cfg;оптимизирован алгоритм прошивки и добавлена функция верификации данных;
добавлен файл
jlink.cfgдля работы с J-Link, в том числе, с "перешитым" из ST-Link.
В аппаратной части изменений нет, во всех тестах МК тактируется от кварцевого генератора частотой 12 МГц. Необходимые для тестирования входы и выходы МК будут указаны в каждом тесте.
Частотомер
Начнем тестирование таймеров с задачи построения измерителя частоты. Нам потребуются два таймера: один — для формирования временного интервала 1 с, другой — для подсчета количества входящих импульсов в течение этого интервала. Выберем для этого первые два 32-битных таймера TM10 и TM16 соответственно. Функциональная схема частотомера показана на следующем рисунке.

Оба таймера будут работать в совмещенном режиме. Таймер TM10 тактируется от сигнала CK_APB частотой 12 МГц, поделенной на 4 входным делителем таймера. Период счета установлен равным 3 000 000 тактам, что будет обеспечивать измерительный интервал в 1 с. Сигнал переполнения счетчика (флаг TOF, активный уровень — высокий) выведен из модуля в качестве выходного триггерного сигнала TM10_TRGO. Его можно будет контролировать на внешнем выводе PC12.
На внешний вход ETR таймера TM16 (PB0) подается входной сигнал с измеряемой частотой Fx. Он непосредственно поступает на счетный вход единого счетчика. Для управления счетом используется входной триггерный сигнал TM16_TRGI, который подается на вход Gate счетчика: при низком уровне сигнала прохождение счетных импульсов разрешено, при высоком уровне счет останавливается. Значение единого 32-битного счетчика доступно в регистре TM16_PSCNT. Для коммутации сигнала TM10_TRGO на триггерный вход таймера TM16 необходимо использовать общесистемный сигнал событий ITR6, поскольку прямой возможности выбора такого входного сигнала для TM16 не предусмотрено.
Рассмотрим основную функцию timer_test_freq(), реализующую частотомер:
/// Частотомер на базе TM10 и TM16
void timer_test_freq() {
// Настройка TM10 как формирователя секундных импульсов
tm_init(TM10_id);
RH(TM10_CLK_h0) = TM_CLK_CKI_DIV_div4_h0 | TM_CLK_CKI_SEL_proc_h0 | TM_CLK_CKS2_SEL_ck_int_h0;
// Включаем режим 32 бита с функцией автостопа:
tm_setup_fullcnt(TM10_id, TM_CR0_ASTOP_EN_enable_h0, 3000000-1); // F(CKO1)=1 Гц
// TRGO <- TOF
RW(TM10_TRG_w) = TM_TRG_TRGO_MDS_tof_w;
// Контроль сигнала на выводе PC12 (30)
RH(PC_CR12_h0) = (5 << 12) | 2; // PC12: TM10_TRGO, push pull output
// Настройка прерывания TM10 по событию TOF (TIE)
SVC2(SVC_HANDLER_SET, 13, timer_hdl_freq); // устанавливаем обработчик прерывания
tm_setup_int(TM10_id, TM_INT_TIE_enable_w);
// Настройка TM16 как основного счетчика входных импульсов
tm_init(TM16_id);
// Настройка тактирования: TM16_CK_TC2 <- TM16_ETR:
RW(TM16_CLK_w) = TM_CLK_CKS2_SEL_ck_ext_w | TM_CLK_CKE_SEL_etr_w;
// Настройка входного сигнала TM16_ETR на пин PB0:
RH(PB_CR0_h0) = (5 << 12) | (1 << 5) | 3; // TM16_ETR, digital input + pull-up
// Включаем режим 32 бит:
tm_setup_fullcnt(TM16_id,TM_CR0_DIR_up_w,0xffffffff);
// Включаем входной триггер ITR6=TM10_TRGO как Gate:
RW(TM16_TRG_w)=
TM_TRG_ITR_MUX_itr6_w | // ITR <- ITR6
TM_TRG_TRG_MUX_itr_w | // TRGI <- ITR
TM_TRG_TRGI_MDS_gate_h_w; // TRGI_MDS: GATE HI
// Включаем сигнал TM10_TRGO как ITR6 (TRG1=TM10_TRGO):
RB(APB_CR2_b0)= APB_CR2_ITR6_MUX_trg1_b0;
}
В начале функции инициализируется и настраивается таймер TM10. Для выполнения точного измерения частоты необходимо не только выдержать интервал 1 с, но и перезапустить таймер одновременно с деактивацией сигнала TM10_TRGO, чтобы начался счет входных импульсов в таймере TM16. Для этого в таймере TM10 задействуем функцию автостопа: поскольку счетчики CT1 и CT2 работают в совмещенном режиме, активация флага TOF и останов счета будут происходить при переполнении счетчика, т.е. в нулевом состоянии. Сброс флага TOF автоматически запустит таймер TM10 с нуля и одновременно разрешит счет в таймере TM16. Для снятия показаний счетчика TM16 и его последующего сброса по окончанию интервала 1 с необходимо задействовать обработчик прерываний по переполнению таймера TM10.
Далее в функции инициализируется и настраивается таймер TM16. Входной сигнал TM16_ETR будет поступать с вывода МК PB0. Счетчики включаются в совмещенный режим с максимальным коэффициентом счета. На вход триггера подается сигнал ITR6 c мультиплексора сигналов событий шины APB, а источником этого сигнала назначается выходной сигнал таймера TM10_TRGO (источник TRG1, см. п. "Блок формирования входного триггерного сигнала").
Теперь рассмотрим обработчик прерывания timer_hdl_freq(), который будет вызываться каждый раз по окончанию измерительного интервала 1 с:
/// Обработчик прерывания с таймера TM10
void timer_hdl_freq() {
// Считываем значение частоты с TM16:
debug32('F',RW(TM16_PSCNT_w));
// Сбрасываем счетчик в TM16:
RB(TM16_TRG_b3) |= TM_TRG_RST_SW_enable_b3;
RB(TM16_TRG_b3) &= ~TM_TRG_RST_SW_enable_b3;
// Сбрасываем флаг TOF и одновременно запускаем счетчик в TM10:
RB(TM10_STA_b0)=0xff; //TM_STA_TOF_mask_b0;
}
В начале функции считываются показания счетчика таймера TM16 и выводятся в терминал в десятичном виде (для этого функция debug32() была переписана). Далее счетчик сбрасывается с помощью программной генерации сигнала RST. Наконец, сбрасывается флаг TOF таймера TM10, после чего запускается новый цикл измерения частоты.
Перейдем к эксперименту. Подключим ко входу PB0 внешний лабораторный генератор Rigol DG4102. Подадим с генератора меандр частотой 10 кГц и посмотрим, что приходит в терминал:
F 0000010000
F 0000010001
F 0000010001
F 0000010001
F 0000010001
Результат вполне хороший. Изменим частоту на 100 кГц:
F 0000100007
F 0000100006
F 0000100007
F 0000100006
F 0000100007
И наконец, проверим частотомер на 1 МГц:
F 0001000065
F 0001000064
F 0001000065
F 0001000064
F 0001000064
При тактовой частоте 12 МГц при дальнейшем увеличении частоты входного сигнала частотомер адекватно работал примерно до 3.5-4 МГц. Видно, что с учетом немного заниженной тактовой частоты МК измерительный интервал получился больше, поэтому показания частотомера имеют погрешность "в плюс". Однако, при стабильной частоте кварцевого генератора можно легко добиться более точного значения интервала в 1 c путем подбора периода счета таймера TM10, задаваемого в функции tm_setup_fullcnt() (в моем случае потребовалось установить значение 2999806). В целом частотомер показал очень хорошую работу с полностью аппаратным обеспечением процесса измерения.
Режим захвата и измерение длительности импульсов
Тестирование схемы захвата/сравнения начнем с функции захвата на основе таймера TM26. Задача будет заключаться в фиксировании моментов времени переключения входного сигнала на канале 0. В качестве источника тактирования выберем вспомогательный таймер TM00, который обеспечит тактовые импульсы с частотой 1 МГц, чтобы время можно было измерять в удобных единицах — микросекундах. Функциональная схема показана на следующем рисунке.

Рассмотрим функцию тестирования timer_test_capture():
/// Тестирование функции захвата на TM26
void timer_test_capture() {
// Настройка TM00_TRGO в качестве источника 1 МГц
tm_init(TM00_id);
// Настройка тактирования: TM00_CK_TC2 - 12 МГц
RH(TM00_CLK_h0) = TM_CLK_CKI_DIV_div1_h0 | TM_CLK_CKI_SEL_proc_h0 | TM_CLK_CKS2_SEL_ck_int_h0;
tm00_setup_fullcnt(12-1); // F1 = 1 МГц
// TRGO <- UEV
RW(TM00_TRG_w) = TM_TRG_TRGO_MDS_uev_w;
// Контроль сигнала на выводе PD9 (39)
RH(PD_CR9_h0) = (0x2 << 12) | 2; // PD9: TM00_TRGO, push pull output
// Настройка TM26
tm_init(TM26_id);
// Настройка тактирования: TM26_CK_TC2 <- TM00_TRGO
RW(TM26_CLK_w) = TM_CLK_CKS2_SEL_ck_ext_w | TM_CLK_CKE_SEL_itr_w;
RB(TM26_TRG_b1) = TM_TRG_ITR_MUX_itr6_b1; // TM26: ITR6 = TRG0 = TM00_TRGO
tm_setup_fullcnt(TM26_id,TM_CR0_DIR_up_w,0xffffffff);
// Настройка режима захвата на канале 0 по обоим фронтам от сигнала IC0
RB(TM26_CCMDS_b0) = TM_CCMDS_CC0_MDS_16bit_ic_b0;
RW(TM26_ICCR_w) = TM_ICCR_IC0_TRGS_dual_edge_w | TM_ICCR_IC0_MUX_ic00_w; // IC0
// Настройка входного сигнала TM26_IC0 на пин PB0
RH(PB_CR0_h0) = (6 << 12) | (1 << 5) | 3; // TM26_IC0, digital input + pull-up
// Настройка прерывания по событиям CC0A, CC0B
SVC2(SVC_HANDLER_SET, 16, timer_hdl_capture); // устанавливаем обработчик прерывания
tm_setup_int(TM26_id, TM_INT_CC0_IE_enable_w);
}
В начале функции инициализируется и настраивается таймер TM00. Поскольку таймер работает в режиме делителя частоты, для контроля частоты на выход TM00_TRGO (PD9) выводится сигнал UEV. Далее настраивается таймер TM26. В качестве тактового выбирается внешний триггерный сигнал ITR от источника ITR6, поскольку для данного таймера непосредственно выбрать сигнал TM00_TRGO нельзя. Однако сам общесистемный сигнал событий ITR6 уже связан по-умолчанию с сигналом TM00_TRGO (источник TRG0), поэтому в мультиплексоре APB ничего настраивать не требуется. Счетчики настраиваются на совмещенный 32-битный режим с возрастающим счетом на максимальный период.
В схеме захвата будем использовать только канал 0. Выбираем срабатывание по обоим фронтам (Dual-edge), поскольку необходимо измерять длительность импульсов. Входной сигнал захвата будем подавать на вывод IC0 (PB0). Для обработки событий захвата будем использовать прерывание таймера TM26 (IRQ#16) по событиям CC0A и CC0B, которые объединяются в общее прерывание CC0.
Рассмотрим обработчик прерывания timer_hdl_capture():
/// Обработчик прерывания в режиме захвата по каналу 0
void timer_hdl_capture() {
static uint32_t a;
uint32_t b;
uint32_t f=RW(TM26_STA_w);
if (f & TM_STA_CF0A_happened_w) {
b=a;
a=(RH(TM26_CC0A_h0) << 16) | RH(TM26_CC0B_h0);
debug32('A',a);
debug32('T',a-b); // Период A1-A0
}
if (f & TM_STA_CF0B_happened_w) {
b=(RH(TM26_CC0A_h0) << 16) | RH(TM26_CC0B_h0);
debug32('B',b);
debug32('P',b-a); // Длительность импульса B-A
uart_puts(PORT,"--",UART_NEWLINE_CRLF);
}
RW(TM26_STA_w)=0xffffffff; // сброс всех флагов
}
В начале функции считываются флаги и определяется, какое из событий произошло. Событие CC0A возникает при нарастающем фронте входного сигнала, а CC0B — при спадающем. В обоих случаях 32-битный результат захвата сохраняется в регистрах TM26_CC0A и TM26_CC0B частями по 16 бит. В первом случае значение счетчика выводится в терминал с пометкой A и сохраняется в статической переменной a. Во втором случае значение счетчика также выводится в терминал с пометкой B и вычисляется его разница с ранее сохраненным в переменной a. Разница выводится в терминал с пометкой P — длительность положительного импульса. Дополнительно при наступлении события CC0A выводится период импульсов с пометкой T. В конце функции сбрасываются все флаги. Отметим, что программа будет работать корректно только в том случае, если интервал между импульсами будет достаточно большим для того, чтобы успел выполниться код обработчика прерывания, в котором самой медленной операцией будет вывод в UART.
Перейдем к эксперименту. Вначале измерим частоту тактового сигнала на выводе TM00_TRGO с помощью частотомера Ч3-85:

Частота несколько ниже 1 МГц, значит период импульсов будет длиннее, а показания схемы захвата будут занижены. На вход IC0 подаем меандр с частотой 1 Гц от генератора DG4102 и получаем вывод в терминал (фрагмент с момента 3.6 с):
A 0003608801
T 0000999935
B 0004108769
P 0000499968
--
A 0004608737
T 0000999936
B 0005108704
P 0000499967
--
A 0005608672
T 0000999935
B 0006108640
P 0000499968
--
A 0006608607
T 0000999935
B 0007108575
P 0000499968
--
A 0007608543
T 0000999936
B 0008108510
P 0000499967
--
Поскольку период сигнала внешнего генератора DG4102 выполнил функцию эталонного интервала 1 с, мы получили фактически частотомер для собственных тактовых импульсов и очевидный результат: период (T) около 999935 мкс, а длительность импульсов (P) — около 499967 мкс. Схема работает корректно.
Формирование ШИМ-сигналов
Для формирования ШИМ-сигналов возьмем самый "продвинутый" таймер TM36. Во-перв��х, только в нем имеется режим "центрирования" импульсов с разных каналов. Во-вторых, в подопытном МК MG32F02A064AD48 вывести на "пины" нужные сигналы от других таймеров оказалось проблематично для выбранного корпуса и уже подготовленной платы.
Для данного эксперимента нам потребуется только таймер TM36. Поскольку формирование ШИМ-сигнала возможно только на основном счетчике CT1, разумно использовать каскадный режим, а счетчик CT2 использовать как предделитель. Будем формировать следующие сигналы:
TM36_TRGO (PB1) — тактовый сигнал счетчика CT1, полученный из сигнала UEV2 с выхода предделителя;
TM36_OC00 (PA0) — ШИМ-сигнал с канала 0;
TM36_OC10 (PA1) — ШИМ-сигнал с канала 1;
сигнал окончания цикла счетчика CT1 (флаг TOF) для удобства анализа осциллограмм (PA2).
Создадим в файле timer_test.c тестовую функцию timer_test_pwm():
/// Генератор ШИМ-сигнала на базе TM36
void timer_test_pwm() {
// Настройка выводов МК:
RH(PA_CR0_h0) = (0xA << 12) | 2; // PA0 (45): TM36_OC00, канал 0
RH(PA_CR1_h0) = (0xA << 12) | 2; // PA1 (46): TM36_OC10, канал 1
RH(PA_CR2_h0) = (0x0 << 12) | 2; // PA2 (47): GPA2, software TOF
RH(PB_CR1_h0) = (0x7 << 12) | 2; // PB1 (10): TM36_TRGO, тактовый сигнал
// Инициализация TM36:
tm_init(TM36_id);
// Настройка тактирования: CK_TC2 <- 6 МГц
RW(TM36_CLK_w) = TM_CLK_CKI_DIV_div2_w | TM_CLK_CKI_SEL_proc_w | TM_CLK_CKS2_SEL_ck_int_w;
// TRGO <- UEV2
RW(TM36_TRG_w) = TM_TRG_TRGO_MDS_uev2_w;
// Настройка периодов: CT2 - 6000 (1 кГц), CT1 - 20 (50 Гц)
tm_setup_cascade(TM36_id,TM_CR0_DIR_up_w,20-1,6000-1);
//tm_setup_cascade(TM36_id,TM_CR0_DIR_down_w,20-1,6000-1);
// Пороги (полный цикл - 20):
RH(TM36_CC0B_h0)=5;
RH(TM36_CC1B_h0)=10;
// Настройка режима OC:
RB(TM36_CCMDS_b0) =
TM_CCMDS_CC0_MDS_16bit_oc_b0 | // канал 0
TM_CCMDS_CC1_MDS_16bit_oc_b0; // канал 1
// Включение выходов:
RW(TM36_OCCR0_w) =
TM_OCCR0_OC0_OE0_enable_w | // OC00 enable
TM_OCCR0_OC1_OE0_enable_w; // OC10 enable
// Настройка прерывания
SVC2(SVC_HANDLER_SET, 17, timer_hdl_pwm); // устанавливаем обработчик прерывания
tm_setup_int(TM36_id, TM_INT_TIE_enable_w); // прерывание по TOF/TUF
}
В начале функции выполняется настройка используемых выводов МК. Далее происходит инициализация и настройка таймера TM36. В качестве исходного выбирается тактовый сигнал шины APB CK_TM36_PR (12 МГц), частота которого предварительно делится на 2. Итоговый сигнал CK_TC2 частотой 6 МГц поступает на вход счетчика CT2. Его коэффициент счета выбирается равным 6000, чтобы тактовый сигнал основного счетчика имел частоту 1 кГц. Коэффициент счета CT1 выбирается небольшим — 20 тактов (20 мс, частота полного цикла 50 Гц), чтобы было удобно определять моменты времени в выходных сигналах на осциллограммах. Выбирается возрастающий счет для обоих счетчиков.
Далее задаются параметры схемы сравнения: пороги CC0B=5 для канала 0 и CC1B=10 для канала 1. В первом эксперименте включим режим сравнения 16bit_OC (это пока не ШИМ) и разрешим прохождение сигналов на выходы МК. Для программного формирования сигнала окончания цикла счета будем использовать прерывание TIE по флагам TOF/TUF и создадим его обработчик:
/// Обработчик прерывания
void timer_hdl_pwm() {
RH(PA_SC_h0) = 4; // set PA2
__NOP(); __NOP();
RH(PA_SC_h1) = 4; // clear PA2
RB(TM36_STA_b0) = 0xFF; // clear flags
}
При срабатывании прерывания формируется положительный импульс на выводе PA2 (добавляем пару NOP, чтобы импульс был не такой короткий) и сбрасываются флаги. Этот импульс будем использовать далее как триггерный при снятии осциллограмм.
С помощью цифрового анализатора Saleae Logic получаем такой результат:

Видно, что в данном режиме выходные сигналы изменяют свой уровень при каждом срабатывании схемы сравнения (на отметках 5 и 10 мс), тем самым формируя последовательность импульсов со скважностью 2. Период (40 мс) и длительность импульсов (20 мс) на обоих каналах одинаковые, схема лишь создает относительный сдвиг фаз.
Теперь включим режим формирования ШИМ-сигналов на обоих каналах:
// RB(TM36_CCMDS_b0) =
// TM_CCMDS_CC0_MDS_16bit_oc_b0 | // канал 0
// TM_CCMDS_CC1_MDS_16bit_oc_b0; // канал 1
// // Настройка режима ШИМ:
RB(TM36_CCMDS_b0) =
TM_CCMDS_CC0_MDS_16bit_pwm_b0 | // канал 0
TM_CCMDS_CC1_MDS_16bit_pwm_b0; // канал 1
Получаем следующий результат:

Видно, что формируются нормальные ШИМ-сигналы с заданными длительностями импульсов и одинаковыми нулевыми начальными фазами, а их период соответствует одному циклу счета CT1 (20 мс).
Переключим направление счета CT1 вниз и посмотрим результат:
//tm_setup_cascade(TM36_id,TM_CR0_DIR_up_w,20-1,6000-1);
tm_setup_cascade(TM36_id,TM_CR0_DIR_down_w,20-1,6000-1);

Теперь в выходном сигнале канала 0 длительность импульса изменилась на 20-5=15 мс, а на канале 1 в силу симметрии сигнала длительность не изменилась.
В заключении проверим работу таймера в режиме выравнивания импульсов всех каналов по центру. Для этого вернем возрастающее направление счета CT1, а после настройки регистра TM36_CCMDS_b0 добавим следующую строку:
RH(TM36_PWM_h0) = TM_PWM_PWM_MDS_center_aligned_h0; // выравнивание по центру
Получаем следующий результат:

Видно, что действительно импульсы выровнялись во времени по центру, но их параметры изменились. Период счета CT1 сократился с 20 до 19 мс, период импульсов увеличился и стал равен 2·(20-1)=38 мс, а длительности импульсов увеличились в 2 раза. Таймер работает в полном соответствии с документацией.
Заключение
Мы рассмотрели большинство функциональных возможностей таймеров МК серии MG32F02 и успешно протестировали их на практике. За рамками статьи остались следующие вопросы, которые читатель может изучить по указанным пунктам User Guide:
задание начальных (preload) значений выходных сигналов, которые могут быть активированы по внешнему событию (20.14.3),
отключение выходов по входному сигналу (Input Break, ��олько TM36) (20.15),
интерфейс квадратурного энкодера QEI (Quadrature Encoder Interface, TM26, TM36) (20.16),
применение DMA (только TM36) (20.17).
В следующий раз мы рассмотрим модуль двухпроводного интерфейса I2C.
