STM32. TIMx OUTPUT COMPARE MODE.

В своей прошлой статье я как-то не полностью раскрыл вопросы по использованию таймера. Теперь восполняю этот пробел. Дело в том, что при обилии информации по STM32, конкретных примеров использования таймера в указанном режиме я не встретил в сети. Были подобные статьи, однако описано всё как-то слишком общими фразами.
В своём макете генератора меандра я использовал таймер 2, но это не суть важно, просто пояснять материал я буду именно на нём, и это ни с чем не сязано, просто так легли карты. ?так, управление таймером (да и всем контроллером) заключается в записи в управляющие регистры определённых значений, и контроль определённых разрядов (флагов) в тех же регистрах, если это необходимо.  Так вот для правильного управления просто необходимо знать назначение каждого разряда каждого регистра и иметь перед глазами структурную схему таймера.
Сводная таблица регистров таймеров 2-5 микроконтроллера STM32F100xx представлена в документе под названием «RM0041 Reference manual», в Table 73. «TIMx register map and reset values», а структурная схема — Figure 88 на стр.276 того же документа.  Я для себя распечатал описание всех регистров контроллера, структурные схемы узлов и сшил листы в виде этакой книжицы. Рассмотрим, что же делает код, представленный в прошлой статье:

void timer_2_init (void)//функция инициализации таймера
{
   AFIO->MAPR  = 0x02000300;//отключаем выводы JTAG и ремапим выводы таймера 2
   GPIOA->CRH |= 0xB0000000;//РА15 - альтернативный цифровой выход до 50 МГц
   RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;//разрешаем тактирование таймера 2
   TIM2->CR1   = 0x00000000;//останавливаем его на всякий случай
   TIM2->ARR   = 1;//сброс таймера (его максимальное значение
   TIM2->CCMR1 = 0x00000038;//
   TIM2->CCR1  = 1;//считаем до 1
   TIM2->CCER  = 0x00000001;//
}

AFIO->MAPR = 0x02000300;
AFIO_MAPR

Группе бит 26-24, которые управляют JTAG/SWD — интерфейсами, установили значение = 010: (JTAG-DP Disabled and SW-DP Enabled), т.е отключили JTAG при включенном SWD. Группе бит 9-8, которые ремапят таймер 2 установили значение =  11: Full remap (CH1/ETR/PA15, CH2/PB3, CH3/PB10, CH4/PB11), т.е выход его канала CH1 подключили на PA15. Я долго не мог понять, почему же при правильных настройках таймера на его выходе CH1 (PA15) я тупо наблюдаю лог. «1». Переключался на CH2 (PB3), а там вообще какая-то постоянная байтовая посылка! ? именно эта байтовая посылка толкнула меня посмотреть ещё раз на распиновку контроллера. Естественно, я увидел там, что по умолчанию PA15 — это вход JTDI (вот почему там лог. «1»), а PB3 — это выход JTDO (вот откуда байтовая посылка). Надеюсь действия с битами 26-24 (SWJ_CFG) теперь не требуют пояснения

GPIOA->CRH = 0xB0000000;
GPIOx_CRH
Ну, этот регистр разжёван во многих статьях. Вывод PA15 настраиваем как выход MODE15[1:0] = 11: Output mode, max speed 50 MHz. с максимальной частотой 50 МГц. При этом CNF15[1:0] = 10: Alternate function output Push-pull, он управляется таймером в режиме «тяни-толкай».

RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
RCC_APB1ENRДля работы таймера на него нужно подать тактирование, что мы и делаем устанавливая бит 0 (TIM2EN), не изменяя остальных, возможно уже установленных битов.

TIM2->CR1   = 0x00000000;
TIM2_CR1
Многие настройки таймера необходимо делать при выключенном таймере, поэтому мы его останавливаем, так, на всякий случай, а то вдруг он где-то в программе запущен был. Для этого сбрасываем бит 0 CEN. Заодно сбрасываем и все остальные биты, хотя для нас здесь значение имеет, пожалуй, бит 4 DIR — он задаёт направление счёта. При нуле — счётчик инкрементирует значение. Хотя, в принципе это не важно — можно и декрементировать, импульсы всё равно будут.

TIM2->ARR   = 1;
Это шестнадцатиразрядный регистр переполнения, до значения которого (0xFFFF — max) счётчик будет считать, а потом обнуляться и считать заново. По нашим условиям он будет считать до 1, т.е. 0,1…0,1…0,1 и т.д.

TIM2->CCMR1 = 0x00000038;
TIM2_CCMR1
Для бит 6-4 OC1M: Output compare 1 mode устанавливаем значение = 011. Оно определяет поведение вывода CH1 (PA15) при равенстве счётного и TIMx_CCR1 — регистра. В нашем случае значение вывода будет меняться на противоположное, ведь мы хотим формировать меандр! Бит 3 OC1PE определяет порядок изменения значения регистра сравнения TIMx_CCR1. Если он сброшен — изменение будет проведено немедленно, даже во время счёта, если установлен — изменение значения произойдет после обновления события. Я решил его установить, хоть это и не важно.

TIM2->CCR1  = 1;
Шестнадцатиразрядный регистр сравнения. Значение должно быть не нулевое и не больше значения регистра переполнения TIM2->ARR, а то сравнение никогда не произойдет. При совпадении значения счётного регистра со значением регистра сравнения произойдёт событие — переключение значения вывода CH1 (PA15). ?менно такое событие мы установили в регистре TIM2->CCMR1.

TIM2->CCER  = 0x00000001;
TIM2_CCERБит 0 CC1E, если канал блока сравнения 1 сконфигурирован как выход, подключает его на соответствующий выходной контакт CH1 (PA15).

Вот таким образом инициализируется таймер для работы в режиме сравнения 1 канала. Вообще-то сюда ещё необходимо добавить оператор, устанавливающий значение делителя счётных импульсов (регистр TIMx prescaler (TIMx_PSC)), однако по умолчанию он нулевой, и я зашарился одной строчкой ))) После инициализации таймера логику его работы можно визуально отследить по структурной схеме ниже:
TIM2_block_diagram

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

Дальше по программе вообще ничего сложного. Выбирается желаемая частота генерации, а по сути выбирается именно значения делителя TIMx prescaler (TIMx_PSC) и включается счётчик командой TIM2->CR1   = 0x00000001; Каждой кнопке «0» ….. «9» соответствует такое же значение делителя 0 …. 9.
Формула значения выходной частоты имеет вид
Fвыходная(CH1) = CK_PSC/((PSC+1)*(ARR+1))
Значение регистра сравнения CCR1 на частоту не влияет, оно определяет сдвиг меандра относительно точки обнуления счётчика.
Подставим значения, которые задали в программе и получили на осциллографе в формулу:
— Кнопка «0» —  9 МГц = CK_PSC/(0+1)*(1+1) = CK_PSC/2 — получается, что на прескалер приходят 18 МГц ?!
Ну-ка, проверим ещё одно значение
— Кнопка «5» —  1,5  МГц = CK_PSC/(5+1)*(1+1) = CK_PSC/12 — те же 18 МГц ?!
Значит ядро работает на частоте 36 МГц? Но как такое может быть?
Этот вопрос, а также  другие, касающиеся настроек тактирования микроконтроллера STM32F100C4 я распишу в следующей статье!

Запись опубликована в рубрике ARM с метками , . Добавьте в закладки постоянную ссылку.

6 комментариев на «STM32. TIMx OUTPUT COMPARE MODE.»

  1. алексей говорит:

    довольно хорошо все написано.

  2. s_black говорит:

    Я старался.

  3. алексей говорит:

    послушайте, раз вы знаете больше чем я про таймеры, буду признателен если подскажите пытаюсь собрать спидометр но ничего не выходит. Завел 2 таймера, TIM2,TIM3. TIM3 работает в режиме захвата таймера, и считывает период между импульсами код взял отсюда» http://chipspace.ru/stm32-general-purpose-timers-input-capture/ » а TIM2 выводит значения на экран вот формула V=F*(L/1000 * 3600) /6 . Я даже не знаю как это можно сделать, ткните откуда можно почерпнуть информации.

  4. s_black говорит:

    Пришлите мне схему. Будет время — постараюсь помочью

  5. Аноним говорит:

    Спасибо! Единственный нормальный источник нужного мне решения во всем интернете.

  6. Андрей говорит:

    «я распишу в следующей статье!»
    А где следующая статья?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.