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 с метками , . Добавьте в закладки постоянную ссылку.

5 комментариев на «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. Аноним говорит:

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

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

Ваш адрес email не будет опубликован.

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