понеділок, 29 лютого 2016 р.

Таймери STM32 -- огляд

Працюючи із далекоміром, ми використовували те, що називають GPIO -- General Purpose Input-Output. В принципі, сяк-так воно задачу вирішує. Однак, повністю займає процесор, і взагалі -- неестетичне. Мікроконтролери, зазвичай, обладнані значно більш зручними засобами для вирішення таких задач -- таймерами та перериваннями. 

Переривання дозволяють програмі не очікувати на якусь подію, постійно перевіряючи щось типу "а що там на піні зараз? а тепер? а тепер?", а отримати нотифікацію про неї -- виклик певного коду у відповідь на появу події. Вони, безперечно, заслуговують окремої розмови (можливо, найближчим часом), але Cortex-M все організовує так, що обробники переривання  -- звичні С-ні функції, що викликаються у відповідь на подію. А ось таймери -- пристрої складні та різноманітні. Тому поговоримо поки про них. 

Що таке таймер? Спеціальний пристрій в мікроконтролері, який вміє відраховувати такти, та, за виконання певних умов, здійснювати вказані дії. Звучить, звичайно, надміру загально, зараз подивимося конкретніше.

Всі ARM Cortex M обладнані SysTick, який є частиною ядра. Ми вже користувалися ним. (Див. опис в глибині цього посту). Якщо коротко: 24-бітний, тобто, лічильник, в якому зберігається "нараховане", має 24 біти -- після \(2^{24}-1\) відбувається переповнення, і відповідний регістр набуває значення 0. Рахує від вказаного значення (в регістрі LOAD) до нуля, в цей момент генерує переривання. Працює або на частоті ядра, SYSCLK, або 1/8 від неї, SYSCLK/8. Є частиною ядра ARM Cortex M, тому присутній у всіх мікроконтролерах сімейства.

Решта таймерів залежать від конкретних мікроконтролерів. У контролерів серій STM32F0, STM32F1, STM32F2, STM32F4, STM32L1  та лінійок (серії F3): STM32F301, STM32F302, STM32F303, STM32F3x8, STM32F373, таймери організовані єдиним чином.

Їх поділяють на наступні групи:
  • Базові таймери -- власне, лічильники, схожі на SysTick, хоч і гнучкіші. Не вміють керувати виводами (пінами).
  • Таймери загального використання. Крім відліку, вміють порівнювати-і-виводити, наприклад, для створення затримок чи генерації ШІМ (англійською воно звучить як output compare, але зводиться до порівняння лічильника із певним значенням, і якщо його досягнуто -- реакції, тому дослівно не перекладаю), подавати один імпульс, захоплювати ввід (наприклад, для визначення тривалості імпульсу чи визначення частоти вхідного сигналу), генерувати ШІМ (PWM), взаємодіяти із периферією -- енкодерами, датчиками Холла, тощо. Кожен має багато каналів, якими може керувати одночасно, (але лічильник в таймера один). Різні такі таймери мають різний набір можливостей із цієї множини.
  • Просунуті таймери. По перше, кожен із них має всю множину можливостей таймерів загального використання. По друге, вони мають додаткові можливості, засоби керування двигунами та джерелами живлення і "аварійної зупинки" (break).
  • Додатково виділяють "channel timers" та "channel timers with complementary output", які мають той же набір властивостей, що і таймери загального використання, але керують меншою кількістю каналів.
Важливо, що архітектура таймерів спільна -- більш потужні є розширеними варіантами примітивніших.

Наступна таблиця показує комплекти таймерів різних моделей:

Розподіл таймерів по різним моделям мікроконтролерів. В нотатках до таблиці сказано, що STM32F30x and STM32F3x8 мають ряд додаткових режимів роботи таймерів.
(c) "AN4013 Application note", STMicroelectronics.
Також може бути корисною звідна таблиця можливостей таймерів різних груп:
Можливості різних груп таймерів.
(c) "AN4013 Application note", STMicroelectronics.
Для конкретики, в подальшому розгляді зосереджуся на контролерах двох демо-плат, що лежать поруч, поки я пишу цей текст -- STM32F100RBT6B на STM32VLDiscovery та STM32F303VCT6 на STM32F3Discovery. Тобто, коли писатиму STM32F303, мається на увазі "і всі схожі" -- у них навіть даташіт спільний: "STM32F303xB/C/D/E, STM32F303x6/8, STM32F328x8, STM32F358xC, STM32F398xE advanced ARM®-based MCUs", тому що наводити кожен раз весь список чи уточнювати дрібні відмінності між моделями -- неефективно, засмічуватиме текст і забере забагато сил, майже нічого не додавши до цінності тексту.

Джерела тактування

Як сказано вище, таймери відраховують такти. Питання -- звідки ті такти беруться?

Із SysTick все просто -- він тактується або від ядра, з його тактовою частотою, або із 1/8 цієї частоти. Таймери STM32 мають більше можливих джерел.

По перше, це може бути внутрішня тактова частота (Internal clock), отримана від підсистеми RCC. Однак, на відміну від SysTick, у них є 16-бітний подільник (prescaler),  який дозволяє поділити цю частоту на вказане значення.
Наприклад, якщо тактова частота MPU -- 24МГц, і нам потрібно, щоб таймер рахував кожну мілісекунду, то prescaler = 24000 - 1. Відняти одиничку потрібно, так як до подільника спершу додається 1 (очевидно, щоб prescaler==0 відповідало тактуванню на частоті процесора).
По друге, присутні ряд режимів зовнішнього тактування: External clock mode1, External clock mode2, Internal trigger clock. В цих режимах тактовим сигналом служать зовнішні джерела (хоча сам таймер має бути затактованим від своєї шини, APB, і реакція на такти вирівнюватиметься по тактах шини -- пристрій, все ж, синхронний).

External clock mode1 -- зовнішнє тактування в режимі 1.

В цьому режимі тактовий сигнал береться із входів таймера TI1 або TI2. Є можливість налаштовувати полярність (вважати активним високий чи низький рівень), спрацьовувати по фронту, по спаду, або по обох фронтах імпульсу. Однак, ділити отриману частоту не можна. Тобто, основне призначення цього режиму -- захоплення сигналів, фіксуючи значення лічильника таймера в момент отримання сигналу.

External clock mode2 -- зовнішнє тактування в режимі 2.

Тактовий сигнал береться із піна ETR (External trigger). Можна застосовувати подільник частоти, можна вибирати полярність спрацювання. Спрацювання по фронту або по спаду.

Internal trigger clock -- внутрішній тригер (ITRx)

Дозволяє події від одного таймера (оновлення чи порівняння, див. далі) використовувати в ролі тактування для іншого. Для ілюстрації можливого використання -- з двох 16-бітних таймерів, із використанням цього режиму можна зробити один 32-бітний.

Зауваження про піни таймера

Кожен таймер, крім базових, може працювати із пінами -- слідкувати за сигналом на них, генерувати ШІМ, тощо. В документації взаємодія таймерів із цими пінами та іншими частинами мікроконтролера розбита на декілька блоків-етапів. Наприклад, TI1 -- Trigger Input 1, вхід таймера, котрий може служити тригером, TI1FP -- TI1 після фільтру (див. відповідний пост, якщо фільтр вимкнено -- те ж, що і TI1) -- це є те, звідки береться сигнал тригера.

При тому, звідки приходить сигнал на TI1, можна керувати. Наприклад, вказати, що джерелом IT1 служитиме канал CH1, або CH2.

Так само, можна  вибрати джерело тригера -- сам TI1, вже згаданий TI1 після фільтрації -- TI1FP, чи результат зміни рівня сигналу на TI1 --- TI1F_ED, TI1 Edge Detector, нарешті це може бути ETRF, External Trigger input -- безпосередньо сигнал із піна чи один із ITR0, ITR1 і т.д. -- внутрішнє джерело.

Тобто, цілком реальна конфігурація -- запуск таймера відбувається по тригеру TI1, джерелом якого служить ETRF -- зміна рівня сигналу, на CH1 -- першому каналі. В подальших постах ми вибудовуватимемо такі ланцюжки для вирішення конкретних задач.

На найбільш зовнішньому кінці цієї схеми -- конкретні піни. Їх набір для кожного таймера описані в документації. Наприклад, CH2 для TIM2 це PA1 на STM32F100. Ця відповідність, на жаль, задана жорстко, але є можливість трохи керувати нею. Контролер підтримує перепризначення, remapping-гу, пінів -- в залежності від потреб, існує кілька фіксованих комбінацій відповідності пінів "функціям" таймерів. Тобто, можна зробити, щоб TIM2_CH1 був під'єднаний до PB3, але при цьому, TIM2_CH1_ETR перейде з PA0 до PA15. Комбінацій небагато і вони фіксовані, але навіть такий обмежений ремапінг сильно спрощує розробку схем.

Щодо документації, то знайти відповідну інформацію -- задача нетривіальна. Зокрема, описана вона не там, де мова про таймери, а:

Базові таймери

Традиційно, на цих таймерах виклад не починають, а закінчують. Однак, вони прості, містять ті ж блоки та користуються тими ж поняттями, що й більш просунуті таймери, тому є сенс почати із них.

Розглядаючи таймери, не копіюватиму з документації опис регістрів і їх бітів. Це, економлячи час, дасть мені шанс закінчити цю серію до того, як ці контролери застаріють, майже без втрат для якості розповіді. Однак, консультуватися із табличками регістрів у даташітах доведеться самостійно -- хороша практика, в будь якому випадку.

Для обраних мікроконтролерів це TIM6 та TIM7. В деяких мікроконтролерах їх більше, окремо на цьому не наголошуватиму, детальніше див. табличку розподілу таймерів по контролерах, вище.

Їх основне призначення -- керувати DAC, вивід TRGO кожного із них може запускати перетворення. Однак, їх можна використовувати і для відліку часу, економлячи більш просунуті таймери.

Принцип дії простий.
  • Таймер має регістр-лічильник, TIMx_CNT (де x -- номер таймера), який за кожного такту зростає на 1. 
  • Тактування -- лише внутрішнє. Регістр TIMx_PSC задає подільник тактової частоти, від 1 до 65536, який отримується із TIMx_PSC+1 (тобто, коли TIMx_PSC==0, подільник рівний один, а коли потрібен подільник 24 000, в TIMx_PSC слід покласти 23999 = 24 000 - 1).
  • Коли лічильник досягає значення, збереженого в регістрі TIMx_ARR (Auto-Reload Register), відбувається зразу дві речі -- в TIMx_CNT кладеться 0, генерується подія переповнення лічильника (counter overflow) та подія оновлення (update event). Це дві різні події, в більш просунутих таймерах даний факт буде проявлятися значно більш виразно, але навіть для базових таймерів подію оновлення можна згенерувати незалежно (наприклад, встановивши біт UG регістра TIMx_EGR ("event generation register").
  • У відповідь на ту чи іншу подію може генеруватися переривання або запит до DMA.
В регістри можна писати і під час роботи, однак, по замовчуванню, використовуються їх "тіньові" копії (shadow registers), оновлення відбувається під час подій. Тобто, діяти нові значення починають, наприклад, після події оновлення. Подробиці -- див. даташіти та appnotes (їх просто забагато, хоча в кожному конкретному випадку особливих труднощів не виникає).
CMSIS надає зручні імена для регістрів та бітів. Наприклад, щоб звернутися до CNT таймера TIM7, робимо так: TIM7->CNT, а бітова маска для біту UG -- TIM_EGR_UG, і встановити його можна якось так: TIM7->EGR |=  TIM_EGR_UG. Думаю, схема співставлення написаного в документації та в коді на С, зрозуміла.

Інші регістри керування базовими таймерами (подробиці див. даташіт, собакою @ відмічаю місця, де, на мою думку, є важливі не висвітлені тут нюанси):
  • TIMx_CR1  -- головний регістр керування. Важливі біти: CEN, Counter enable, коли встановлений, запускає відлік; UDIS, Update disable -- забороняє подію оновлення, (@); URS, Update request source, дозволяє заборонити оновлення по зміні біту UG; OPM, One-pulse mode -- якщо 1, після події оновлення таймер зупиняється, очищаючи біт CEN; ARPE, Auto-reload preload enable, керує буферизацією ARR -- чи він ступає в дію зразу (0) чи після події оновлення (1).
  • TIMx_CR2 -- другий регістр керування. Дозволяє обирати (бітами MMS, Master mode selection), як саме цей таймер керує підлеглим. Важливим значенням є 010b, Update --- "смикати" підлеглий таймер по приходу події оновлення, цікавим --- 000b, Reset, по встановленні UG -- підлеглий таймер оновлюється.
  • TIMx_DIER, DMA/Interrupt enable register -- керування генерацією переривань та запитів DMA. Біти UDE, Update DMA request enable та UIE, Update interrupt enable, встановлені у 1 дозволяють відповідну реакцію.
  • TIMx_SR, регістр статусу. Біт UIF вказує, чи була подія оновлення.
Приклади будуть в наступних постах.

Просунуті таймери

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

Це таймери TIM1/TIM8/TIM20 (нагадую, що із них  STM32F100 має лише TIM1).
  • Лічильник 16-бітний, але рахувати вони можуть вверх, вниз, і туди-потім-назад. 
  • Як і в базових таймерів, присутній подільник частоти.
  • Мають до 6 (STM32F303 -- 6, STM32F100 -- 4) канали. На кожному каналі можна незалежно захоплювати ввід (Input Capture), здійснювати порівняння-і-вивід (Output Compare), генерувати PWM (Широтно-імпульсна модуляція, ШІМ), працювати в одно-імпульсному режимі.
  • Комплементарні виводи із затримкою між ними (Complementary outputs with programmable dead-time) -- виводи, сигнал на яких має протилежне значення, але для комплементарних можна встановити затримку переключення у новий стан -- dead time.
  • Як і в базових -- можливість тактувати один таймер іншим, об'єднуючи їх у ланцюжки.
  • Лічильник повторів, який дозволяє реагувати після вказаної кількості повторів події (переповнення, наприклад).
  • Один-два так званих break inputs -- аварійні піни, по сигналу на яких виводи таймерів набувають вказаних безпечних значень.
  • Засоби підтримки енкодерів та датчиків Холла. 
  • Також, вони можуть активувати АЦП чи ЦАП  (ADC/DAC) у відповідь на події.
Генерація переривань чи запитів DMA можлива у відповідь на наступні події:
  • Оновлення: лічильник досягнув максимального значення або нуля, лічильнику програмно присвоєно значення.
  • Подія-тригер: початок відліку, зупинка відліку, ініціалізація чи відлік по зовнішньому чи внутрішньому тригеру.
  • Захоплення вводу (сигналу).
  • Порівняння (Output compare, хоча, воно швидше поводиться як "порівняти лічильник, і якщо умова виконується -- встановити пін у потрібне значення).

Для розуміння подальшого дуже корисною буде наступна схема таймерів у мікроконтролера STM32F100 (для STM32F303 вона схожа, але більш громіздка, тому не наводжу -- див. даташіт).

Будова просунутого таймера STM32F100.
(c) STMicroelectronics
Умовні позначення на цій діаграмі:

Як видно, різноманітних режимів багато, детально їх всіх розглядати не будемо, але в наступних постах будуть приклади деяких із них -- тих, з якими мені доводилося стикатися на практиці. Бо, як показує згадана практика, не спробувавши використовувати щось в реальній роботі, розповісти про нього важко ("Hello world"-а для цього замало) -- завжди щось важливе буде впущено.

Відлік

Як і для базових, у просунутих таймерів присутні регістри TIMx_CNT, TIMx_PSC, TIMx_ARR, із тими ж функціями.

На відміну від базового, відлік може йти не тільки вверх, але і вниз -- від значення, завантаженого в лічильник TIMx_CNT із TIMx_ARR до нуля, а також вверх, до TIMx_ARR, а потім вниз (Center-aligned mode -- центрований режим).

Крім того, є регістр TIMx_RCR, який задає, скільки раз слід повторно дорахувати (до переповнення чи до нуля),  перш ніж генерувати подію. (Поточне значення знаходиться в REP_CNT, подія генерується, коли він досягає нуля, потім у нього автоматично завантажується значення із TIMx_RCR).

Крім події оновлення, яка генерується після вказаної кількості повторів, якщо таймер досягає нуля, генерується повідомлення спорожнення (underflow event), якщо максимального значення --- подія переповнення (overflow event). Тобто, коли працюється у центрованому режимі, на кожен цикл може двічі генеруватися оновлення (вважаючи, що повторами не користуємося) та генеруються дві події -- спорожнення і переповнення.

Відлік для таймера єдиний, однак кожен канал (так звані канали захоплення/порівняння  --- Capture/compare channels), в загальному випадку, можна налаштовувати незалежно (звичайно, в деяких режимах різні канали мусять налаштовуватися скорельовано). Розглянемо, що вони можуть.

Захоплення сигналу

Кожен канал має регістр TIMx_CCRx, де x -- номер каналу, в який, у режимі захоплення, зберігається значення лічильника в момент приходу сигналу. При тому встановлюється відповідний біт CCxIF у регістрі TIMx_SR та може бути згенеровано переривання чи запит DMA. Якщо під час захоплення біт CCxIF, який автоматично очищається при читанні з TIMx_CCRx чи може бути очищений програмно, все ще рівний 1 -- значить попереднє значення не було прочитано, встановлюється прапорець CCxOF в тому ж регістрі статусу, та може генеруватися відповідне переривання чи запит -- over-capture.
Зауважте, що регістр TIMx_SR має для цих таймерів значно більше осмислених бітів, ніж для базових.
Захоплення може відбуватися по зростанню, (фронту), спаданню сигналу чи і по тому і по тому. Можна встановити фільтр -- кількість вибірок, після якої можна вважати, що сигнал встановився (такий собі захист від дрижання контактів). Можна ділити вхідну частоту на 2, 4 або 8 --- реєструвати кожну другу-четверту-восьму подію.

Типове використання -- заміряння тривалості якоїсь події. Наприклад, довжини імпульсу на echo ультразвукового далекоміру. Можливості цього режиму використовуються для реалізації інших режимів. Наприклад:

Захоплення ШІМ

Хитра конфігурація режиму захоплення сигналу -- коли два канали "слухають" той самий вхід, один ловить фронт, другий спад. При тому, початок відліку каналу по фронту очищає лічильник таймера. Тоді подія по спаданню збереже у TIMx_CCR2 відповідного каналу тривалість імпульсу, а наступний фронт дасть у TIMx_CCR1 каналу, що їх ловить, період. Значно краще все це зрозуміти можна на рисунку із даташіту:


Режим захоплення ШІМ.
(c) STMicroelectronics

Інтерфейс енкодера

Інкрементальні енкодери генерують два або три сигнали -- фаза A, фаза B, іноді ще -- індекс. Індекс генерується кожен оберт. Якщо фаза A наступає швидше за фазу B, обертання йде в одну сторону, інакше -- в другу. 
Сигнали енкодера. Обертання за годинниковою стрілкою.
(c) wiki
В режимі інтерфейсу енкодера сигнали фаз можна під'єднати до входів TI1 i TI2, тоді електроніка таймера визначатиме, коли прийшов сигнал, і в залежності від напрямку повороту, збільшуватиме чи зменшуватиме лічильник. Індекс можна під'єднати до зовнішньої лінії переривань, підраховуючи зразу і оберти -- щоб отримати абсолютне положення. Швидкість обертання можна визначити, якщо залучити ще один таймер для відліку часу.

Приклад роботи енкодера. Біт DIR -- напрямку відліку, в цьому режимі керується апаратно. (Роздільна здатність X4 -- рахується кожна зміна сигналу, можливою є також X2, коли рахуватиметься пара фронт-спад).
(c) STMicroelectronics
TIMx_ARR все ще бере участь в роботі таймера, по досягненню цього значення або нуля, відбудеться перезавантаження лічильника.

Інтерфейс датчиків Холла

Є можливість під'єднати перших три канали до першого, із виконанням між їх значеннями операції XOR. Цю можливість можна використовувати для читання даних із набору (трьох) датчиків Холла, котрі "стежать" за обертанням.

Порівняння (Output compare)

Режим дозволяє дорахувати до певного значення -- поки вміст лічильника не зрівняється із значенням спеціального регістра TIMx_CCRx, після чого виконує вказані дії, поміж яких може бути:
  • Встановлення виводу (піна мікроконтролера)  у задане наперед значення.
  • Встановити прапорець, що подія відбулася (біт CCxIF в регістрі статусу TIMx_SR) та генерує відповідні переривання чи запит DMA, якщо вони дозволені. 
Можна запрограмувати, щоб у результаті події:
  • пін встановлювався в активний чи пасивний стан, 
  • змінював стан на протилежний,
  • чи залишався у тому стані, що є (ну мало, може знадобиться і такий режим). 
  • Пара дуже важливих режимів -- ШІМ1 та ШІМ2 (PWM mode 1 i PWM mode 2). В  режимі ШІМ1 вивід активний, поки лічильник менший за те, що є в регістрі порівняння каналу, TIMx_CCRy, (в назві регістра, x -- номер таймера, y -- номер каналу), потім -- неактивний, аж до переповнення, (описано  при рахунку вверх, при рахунку вниз, фактично, буде так само, тільки значення лічильника в іншу сторону рухається). В режимі ШІМ2 все навпаки -- вивід неактивний, поки лічильник менший за TIMx_CCRx та активний, поки він знаходиться між TIMx_CCRx і TIMx_ARR -- максимальним значенням до якого/від якого рахується.
  • Також є можливість примусового встановлення в активний чи пасивний стан, не залежно від значення лічильника. 
Що значить активний чи пасивний -- визначається полярністю. Якщо відповідний біт (CCxP де x -- номер каналу) регістра TIMx_CCER рівний 0, активним вважається високий рівень (3.3В, наприклад), інакше -- низький (0В).
STM32F303 має багато більше варіантів тих режимів керування виводами, аж до того що бітів вибору режиму, OCxM, (регістра TIMx_CCMR1) у нього чотири замість трьох у STM32F100, хоча, при всій корисності, нічого аж такого видатного, тому описувати лінь. Детальніше див. даташіти.

ШІМ (PWM)

Генерація ШІМ, фактично є просто способом використання Output compare. Вміст TIMx_ARR задає період, TIMx_CCRx задає заповнення (при полярності із активним високим, інакше заповнення буде TIMx_ARR - TIMx_CCRx). Якщо відлік відбувається вверх чи вниз, ШІМ вирівняний по краю, якщо туди-потім-назад -- по центру.

Генерація ШІМ, вирівняного по краю, при відліку вверх. Вивід, керований таймером -- OCXREF. CCxIF -- біт, який вказує, що відбулася подія порівняння (якщо дозволено, при його встановленні в 1, генерується переривання чи запит DMA). TIMx_ARR == 8.
(c) STMicroelectronics


Генерація ШІМ, центральний режим. Решта як на попередній діаграмі. CMS -- біти вибору центрального режиму із TIMx_CR1. (Подробиці див. даташіт).
(c) STMicroelectronics

Режим одного імпульсу

На додачу до всього описаного вище, таймер має спеціальний біт, який вирішує, продовжувати відлік чи зупинятися (встановлюючи CEN=0) після події оновлення. З допомогою цієї можливості реалізовано спеціальний, одноімпульсний, режим. По зовнішньому чи внутрішньому сигналу (запустити таймер може зовнішня подія або інший таймер) відбувається затримка (визначається вже згаданим TIMx_CCRx), після чого -- імпульс, тривалістю TIMx_ARRx-TIMx_CCRx. Вигляд імпульсу визначається тими режимами, якими володіє кожен із каналів -- встановити у активний, пасивний, змінити на протилежний, ШІМ1, ШІМ2, не змінювати нічого, примусовий активний чи примусовий пасивний. Що значить активний/пасивний -- визначається полярністю.

Режим одного імпульсу.
(c) STMicroelectronics

Режим одного імпульсу з продовженням -- Retriggerable one pulse mode

STM32F303 має ще один варіант одно-імпульсного режиму. Його особливістю є те, що імпульс продовжується ("починається з початку"), якщо тригер спрацював ще раз поки імпульс тривав.
Режим одного імпульсу з продовженням. (STM32F30x i STM32F3x8)
(c) STMicroelectronics


Комплементарні (взаємодоповнювальні) виводи із можливістю затримки -- Complementary outputs and dead-time insertion

Просунуті таймери мають можливість виводити зразу два сигнали, із протилежним значенням (виводи  OCx і OCxN), які беруться із значення OCxREF, але із можливість затримки перш ніж переходити у стан OCxREF чи !OCxREF. Що цікаво, полярністю OCx та OCxN можна керувати незалежно.

Комплементарні виводи із затримкою.
(c) STMicroelectronics
Є можливість також перенаправляти  OCxREF безпосередньо на OCx чи OCxN, залишаючи інший неактивним.



"Аварійна зупинка" -- break

Режим, який дозволяє по сигналу на певному піні чи повідомленню від RCC про проблеми із тактуванням, перевести виводи у наперед визначений стан. Щоб не зламати чого, якщо щось не так. За його допомогою можна, наприклад, зробити кнопку аварійної зупинки приладу.

Очищення OCxREF у відповідь на зовнішній сигнал -- Clearing the OCxREF signal on an external event

Є можливість сконфігурувати канал так, щоб коли на вході ETRF з'являється високий рівень, OCxREF переходив у низький, і залишався таким до наступної події оновлення. (Ця функція не працює в примусових режимах -- лише в режимі порівняння та ШІМ-режимах).

6-step PWM

Як вже обговорювалося вище, перших три канали просунутих таймерів мають комплементарні виводи, для яких можна встановлювати затримку (dead time). Насправді, так задумувалося відразу, щоб можна було керувати трифазними двигунами.

Асиметричний та комбінований ШІМ

STM32F303 підтримує також ще два додаткових режими.
Асиметричний режим (Asymmetric PWM mode) дозволяє генерувати на двох каналах центральний ШІМ із тією ж частотою, але зсувом по фазі.
Комбінований режим (Combined PWM mode) дозволяє генерувати центральний чи вирівняний по краю ШІМ із заданими затримками та зсувом по фазі, а потім комбінувати їх.  Сигнал на виході є їх комбінацією OR чи AND між вхідними.


Регістри просунутих таймерів

Всі вони мають ті ж регістри, що і базові таймери. По перше, це TIMx_CNT, TIMx_PSC, TIMx_ARR. На додачу до них з'явився лічильник повторів, TIMx_RCR.

Регістри керування, TIMx_CR1 та TIMx_CR2 теж присутні, але у них з'явилися нові біти. В першу чергу, це CMS -- вибір центрального режиму та DIR -- вибір напрямку лічби в CR1 (@). TIMx_CR2 має більше новинок:
  • CCPC --  Capture/compare preloaded control, керує, чи біти  CCxE, CCxNE, OCxM змінюються зразу при записі у них чи при появі події (@).
  • CCDS -- Capture/compare DMA selection. Якщо 0, запит DMA відбувається у відповідь на подію CCx, інакше -- у відповідь на подію оновлення.
  • TI1S -- TI1 selection. Вибирає, чи вхід таймера TIMx_CH1 під'єднаний до піна TI1, чи TIMx_CH1/2/3 до нього під'єднані із використанням XOR (див. інтерфейс датчиків Холла)
  • OIS1 (також для 2, 3, 4, та 5-6 у таймерів із шістьома каналами) -- значення, що виводитиметься на OC1 за появи аварійного сигналу. Аналогічно -- біт OIS1N для комплементарного каналу. (Dead-time враховується). Див. також регістр BDTR.
Регістр  TIMx_SMCR -- TIMx slave mode control register керує зовнішнім тактуванням.
  • Біти SMS вибирають режим "підлеглості" (@); 
  • біти TS вибирають тригери (із ITRx -- внутрішніх джерел, TI1F_ED -- границі імпульсу на TI1, входів TI1FP1 та TI2FP1, ETRF); 
  • біти ETF задають, скільки раз заміряти сигнал, перш ніж вважати, що він наступив, в рамках боротьби із дрижанням контактів і т.д. (@);  
  • ETPS -- подільник зовнішнього сигналу (@); 
  • ECE -- дозвіл зовнішнього тактування; 
  • ETP -- полярність зовнішнього тактування  (список не повний).

Як і для базових таймерів, TIMx_DIER керує перериваннями та запитами DMA. Однак, варіантів подій для просунутих таймерів багато більше! Події, для яких можна дозволити переривання чи/і запит DMA:
  • TDE: Trigger DMA request enable/TIE: Trigger interrupt enable -- переривання/запит DMA за появою тригера
  • COMDE: COM DMA request enable/COMIE: COM interrupt enable (стосується 6-step PWM)
  • CCxDE: Capture/Compare x DMA request enable/CCxIE: Capture/Compare x interrupt enable -- подія порівняння чи захоплення (в залежності від режиму), для кожного каналу
  • UDE: Update DMA request enable/UIE: Update interrupt enable, -- переривання/запит DMA у відповідь на переповнення, як і для базових
  • BIE: Break interrupt enable -- переривання за "аварійною зупинкою"
Регістр статусу TIMx_SR теж завів собі багато нових статусів, на додачу до UIF (Update interrupt flag) базових таймерів:
  •  CCxIF: Capture/Compare x interrupt flag, для кожного каналу. При роботі із виводом, стає рівним 1 коли дораховується до  TIMx_CCRx (@), очищається програмно. При роботі із вводом -- стає 1, коли відбулося захоплення в TIMx_CCRx (@), очищається програмно, або читанням TIMx_CCRx.
  • COMIF: COM interrupt flag -- встановлюється за події COM. 
  • TIF: Trigger interrupt flag -- встановлюється за активації тригера.
  • BIF: Break interrupt flag -- аналогічно, за події break. (Також B2IF для STM32F303, у якого два break канали)
  • CCxOF: Capture/Compare x overcapture flag. Встановлюється, коли канал налаштовано на ввід і було пропущено значення, захоплене в TIMx_CCRx -- на момент захоплення біт CCxIF було ще встановлено.
Аналогічно, зросла і кількість можливих подій, якими керує TIMx_EGR -- event generation register. Крім події оновлення, присутньої і в базових таймерів, є можливість активувати Capture/Compare події на кожному із каналів,  COMG: Capture/Compare control update generation, TG: Trigger generation, BG: Break generation.

Крім купи бітів у вже знайомих регістрах, є багато нових регістрів.

TIMx_CCMR1 та  TIMx_CCMR2 -- сapture/compare mode register 1/2  керують захопленням вводу чи виводу для 1 і 2 та 3 і 4 каналів, відповідно (TIMx_CCMR3 для 5 і 6 каналів, якщо вони є).
  • Біти CCxS вибирають, чи канал х працюватиме на ввід, чи на вивід (і якщо на ввід, то з якого входу братиме).
Решта бітів у різних режимах мають різне значення. В режимі порівняння виводу (Output Compare) використовуються:
  • OCхFE -- ввімкнути швидкий режим (@)
  • OCxPE -- Output Compare x preload enable, керує моментом, коли нове значення  TIMx_CCRx береться до уваги -- за події оновлення чи в момент завантаження. 
  • Біти OCxM -- Output Compare x mode визначають, що робити із виводом при події співпадіння (можливі варіанти обговорювалися вище).
  • OCxCE -- Output Compare x clear enable, дозвіл чи заборона встановлення виводу в нуль по зовнішньому сигналу.
В режимі захоплення вводу:
  • Біти ICxPSC -- Input capture x prescaler, задають подільник (можливі значення -- реєструвати кожну 1, 2, 4, 8 подію)
  • Біти ICxF -- Input capture x filter, керують фільтром (див. згадки про дрижання вище)
Регістр TIMx_CCER  -- capture/compare enable register:
  • CCxE -- дозволяє відповідні канали, 
  • CCxP -- визначає полярність виводу чи вибірку по фронту чи спаданню для вводу, 
  • CCxNE, CCxNP -- аналогічні біти для комплементарних каналів.

Кожен канал має свій регістр TIMx_CCRx -- capture/compare register. При вводі у нього зберігається значення лічильника, при виводі -- порівнюється із ним. Подробиці детально обговорювалися вище. Регістр TIMx_CCR5 для STM32F303 має додаткові біти керування хитрими новими режимами таймерів (регістри 64-бітні, тому сам лічильник того ж розміру).

TIMx_BDTR --  break and dead-time register, керує "аварійною зупинкою", блокуванням зміни налаштувань таймерів (щоб захистити від завад під час роботи, наприклад) та тривалістю затримки dead-time (подробиці див. вище і в даташітах).
  • MOE -- main output enable, очищається за події break, переводячи всі виводи в заданий режим.
  • AOE --  Automatic output enable, задає чи MOE можна встановлювати в 1, дозволяючи вивід, лише програмно, чи й  автоматично, на наступній події оновлення, якщо сигналу на піні break вже немає.
  • BKE -- Break enable, дозволяє слідкувати за піном break.
  • BKP -- Break polarity, визначає його полярність.
  • LOCK -- забороняють модифікувати конфігурацію. Записувати в ці біти можна лише раз після перевантаження (reset) мікроконтролера. Захист від збою програмного забезпечення.
  • DTG, 8-бітний, Dead-time generator setup -- задає затримку між комплементарними каналами.

Регістр TIMx_DCR -- DMA control register, керує запитами DMA а TIMx_DMAR задає адресу для пакетного (burst) режиму, в якому є можливість читання-запису групи регістрів таймера з допомогою DMA.

STM32F303 ще обладнаний TIMx_OR -- option registers, який керує відображенням між ETR і ADC.

Майте на увазі, що деякі бітові поля в  STM32F303 довші, ніж в STM32F100, а частина (іменованих) регістрів займають не 16 а 32 біти.


Таймери загального використання

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

TIM2/TIM3/TIM4/TIM5

(Звертайте увагу на конкретний набір таймерів контролера. Скажімо, STM32F303 не має TIM5).

Вони:
  • Навіть в 303-х, мають лише 4 канали. 
  • Не мають комплементарних виводів.
  • Не вміють працювати із повторами (repetitions), відповідно, не мають регістра TIMx_RCR.
  • Не мають режиму чи входів переривання (того, що break, із interrupt у них все добре :-).
Зате, для STM32F303, TIM2 i TIM5 -- 32-бітні.

TIM12/TIM13/TIM14 -- STM32F100

Ще більш обмежені за можливостями.
  • TIM12 має 2 канали, TIM13 та TIM14 -- один. 
  • TIM12 може працювати лише із внутрішніми тригерами, решта з тригерами взагалі не вміють працювати.
  • ШІМ можуть генерувати лише вирівняний по краю.
  • Режим одного імпульсу є лише в TIM12 -- очевидно, через те, що інші не мають тригерів
  • Не вміють працювати із енкодерами чи датчиками Холла
  • TIM12 може тактуватися від зовнішнього сигналу, пінами TIx. Тільки він вміє захоплювати ШІМ
 Відсутні в STM32F100 серії low та medium density та в STM32F303.

TIM15/TIM16/TIM17

 Характеризуються тим, що мають комплементарні канали.
  • TIM15 -- два канали, решта -- один, всі -- з одним комплементарним виводом.
  • ШІМ -- тільки вирівняний по краю.
  • Зате у них є лічильник повторів, TIMx_RCR та break input.

Регістри, на загал, є урізаними варіантами аналогічних для просунутих таймерів.

Спеціалізовані таймери

Окрім розглянутих, мікроконтролери обладнані додатковими таймерами, які не потрапляють у список розглянутих вище, так як є пристроями зовсім іншої природи.

Із суміжного, STM32F303, явно підтримує інтерфейс інфрачервоного порту (IRTIM -- Infrared interface), залучаючи до цього два таймери, TIM16 i TIM17.


Real-time clock (RTC) -- годинник реального часу

Ну, в STM32F100 повноцінним RTC він не є, але має все необхідне для самостійного створення такого. Цей таймер має 32-бітний лічильник та 20-бітний подільник. Може тактуватися від зовнішнього "годинникового", низькочастотного кварц (32.768кГц) -- LSE, внутрішнього RC-ланцюжка (~40кГц, але, кажуть, реально -- десь між 30 і 60 кГц, доволі неточний для таких задач!) -- LSI, та від HSE,із подільником 128.

По замовчуванню налаштований, щоб генерувати відлік кожної секунди. Завдяки 32-бітному лічильнику, може вимірювати тривалі інтервали, може генерувати переривання тривоги (alarm) у вказаний час, переривання що секунди та переривання по переповненню лічильника.

Має окремі кола живлення, (Backup domain), тому та частина, що відраховує час, зберігає свої налаштування і продовжує функціонувати, навіть коли решта мікроконтролеру знеструмлена, живлячись від батареї. Також має 10 16-бітних регістрів (20 байт) загального використання, у яких можна зберігати інформацію, потрібну між знеструмленнями.

STM32F303, навпаки, обладнаний повноцінним RTC, що працює в BCD кодуванні, знає про високосні роки та про те, що місяці мають різну тривалість, дозволяє користуватися декретним часом, надає доступ до часток секунди (див. регістр RTC_SSR). Звичайно, вміє генерувати переривання у вказаний час (можна задати два різних часи) та із заданим інтервалом і т.д. Резервує 16  32-бітних регістрів. Вміє керувати виводами (подробиці -- див. даташіти).

Independent watchdog (IWDG) -- незалежний сторожовий таймер

Призначення сторожових таймерів -- виявляти проблеми із програмним забезпеченням та перевантажувати контролер, в надії відновити працездатність. IWDG -- класичний приклад такої "сторожової собаки". Він, хоч і знаходиться на тому ж чіпі, повністю незалежний від решти мікроконтролера, тактується від свого джерела, LSI, з частотою близько 40кГц. Через це він, з одного боку, надійний, з іншого -- відносно повільно реагує.

Працює він наступним чином:
  • Після запису  0xCCCC в регістр ключа IWDG_KR, лічильник починає рахувати вниз, від 0xFFF.
  • Коли досягає нуля, перевантажує контролер.
  • Якщо контролер встиг за цей час завантажити  0xAAAA в IWDG_KR, лічильник встановлюється в значення IWDG_RLR, перевантаження відтерміновується.
Можна також зробити так, щоб він почав працювати автоматично, зразу після перевантаження.

Має подільник, (регістр IWDG_PR), який може бути степенем двійки від 4 до 256, даючи можливий таймаут від 0.1 мс (подільник 4, IWDG_RLR=0) до 26 214 мс,  ~26 секунд (подільник 256, IWDG_RLR=0xFFF). 

Хитрі числа, які слід записати, обрано щоб, коли програма на контролері "піде в рознос", зменшити шанс випадкового де-активування чи  відтермінування спрацювання цього таймера. Аналогічно, захищено запис в  регістри IWDG_PR і IWDG_RLR -- перш ніж писати у них, слід в  IWDG_KR записати  0x5555.

Має свій регістр статусу, IWDG_SR, у якому біти вказують, що відбувається перевантаження лічильника (RVU) чи подільника (PVU). Змінювати відповідні параметри можна лише коли ці біти рівні нулю,  а процес запису доволі повільний -- до 5 циклів на частоті 40кГц.

STM32F303 дозволяє також налаштувати вікно спрацювання -- як для Window watchdog (і додає відповідний регістр, IWDG_WINR).  Спеціальні значення використовуються ті ж, що і для STM32F100, однак регістри тепер 32-бітні, тому потрібно записувати нулі спереду -- 0x0000AAAA і т.д.


Window watchdog (WWDG) -- віконний сторожовий таймер

Цей таймер менш незалежний -- він тактується від  APB1, якщо тактування MPU "зіпсується", він теж не зможе працювати правильно. Зате багато швидший і більш передбачуваний, ніж IWDG.

Він теж містить лічильник, щоправда -- 7-бітний (максимальна значення -- 0x80 або 128), який зменшується, і при досягненні значення 0x40 -- перевантажує мікроконтролер. (Іншими словами -- перевантаження відбувається, коли 6-й біт стає рівним нулю). Крім того, він називається віконним, тому що зразу після оновлення лічильника є інтервал часу, в якому оновлювати заборонено -- така спроба теж приведе до перевантаження. Ну і, на додачу, замість перевантаження таймер вміє генерувати переривання, коли лічильник досягає 0x40, тому його можна використовувати і для відліку часу.

Лічильник "клацає" неперервно, навіть коли таймер заборонено, тому слід потурбуватися, щоб на момент дозволу в ньому було число, більше за 0x40.

Вікно віконного сторожа.
(c) STMicroelectronics
На частоті мікроконтролера 24МГц, мінімальна затримка -- 170 мкс, максимальна -- 87 380 мкс, ~87 мс.

Регістри:
  • WWDG_CR -- регістр керування, біт WDGA -- активація, може бути вимкненим лише при перевантаженні; 7 бітів T -- лічильник; 
  • WWDG_CFR -- конфігурація, EWI -- дозвіл генерувати переривання замість/перед перевантаженням; 2 біти WDGTB -- подільник частоти; 7 біт W -- вікно, в якому заборонено оновлення лічильника, має бути між 0x80 i 0x41.
  • WWDG_SR -- регістр статусу, лише один біт, EWIF -- відбулося переривання.
Регістри для STM32F303 32-бітні.

Зауважте, що ці сторожові таймери можуть конфліктувати із відладкою --- вони можуть продовжувати відлік, навіть коли мікроконтролер зупинився на контрольній точці, перевантажуючи його без потреби. Правда, блок відладки мікроконтролерів вміє зупиняти і їх.


Підсумок

Таймери -- надзвичайно складні, різноманітні та потужні пристрої. Поміж то все -- ще й корисні. :-) Текст вище -- лише короткий огляд! Я свідомо включав імена регістрів там, де це релевантно, дещо змішуючи рівні абстракції викладу -- щоб були ключові слова для пошуку у документації та інших джерелах. Однак, такого короткого огляду явно недостатньо для використання таймерів. Особливо -- для правильного використання. Десятки регістрів, сотні біт, всі треба правильно налаштувати...

Систематичний огляд виходить за межі моїх можливостей, а тексти в даташітах та appnotes -- важкі для сприйняття і вимагають (малодоступного для мене рівня) уважності. Тому, як компроміс, в наступних постах буде розглянуто кілька типових прикладів використання.

Посилання

Як виявилося, назви документів (типу DM00042534.pdf) змінюються значно рідше, ніж посилання на них. Тому, для спрощення пошуку, наводжу і їх.

8 коментарів:

  1. Дякую за Вашу працю. На інших сайтах хоч і є приклади, але на рівні "заліза" детальніше буде лише оригінал на англіцкій.

    ВідповістиВидалити
    Відповіді
    1. І Вам дякую за відгук!

      Власне, ця серія так і з'явилася -- ніби кожну конкретну задачу міг вирішити, але крок в сторону і все розвалювалося, доводилося підпирати все більшою кількістю костилів, тому було зрозуміло, що я таки чогось не розумію.

      Видалити
  2. Чудова стаття, приємно читати рідною мовою.) Дуже вдячний!

    ВідповістиВидалити
  3. Очень хорошая статья. Многое стало более понятным. Спасибо огромное за Ваш труд.

    ВідповістиВидалити
  4. Я вообще казах, у нас не то что программирование микроконтроллеров даже естественные науки не развиты. Благо в результате глобализации есть возможность переводить и учиться.

    ВідповістиВидалити
  5. Товариство, дякую за всі відгуки! На жаль, щось зламалося і мені не повідомляло про ваші коментарі, щойно побачив.

    ВідповістиВидалити