четвер, 31 березня 2016 р.

Таймери STM32 -- одноімпульсний режим/HAL

Черговий пост в серії -- одноімпульсний режим, OPM, із використанням STM32CubeMX/HAL. Вирішимо тих же дві задачі -- реакція на кнопку, із затримкою та реакція на внутрішній тригер, яким служить подія переповнення іншого таймера. 

Запуск OPM кнопкою 

Почнемо із візуальної конфігурації:
Клікабельно! Знадобиться, щоб роздивитися конфігурацію таймера.

понеділок, 28 березня 2016 р.

Таймери STM32 -- одноімпульсний режим/CMSIS

Останні теми, перш ніж повернемося до далекоміра -- вже із новими засобами. Взагалі, якщо чесно, вся ця серія з'явилася через те, що я дуже розсердився, витративши, щоб розібратися із One Pulse Mode (одноімпульсний режим, OPM) кілька повних днів. Тому текст нижче -- спроба розказати про нього максимально детально.

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

Режим одного імпульсу.
(c) STMicroelectronics
Розглянемо два види подій, що запускатимуть OPM -- внутрішня, від іншого таймера та зовнішня -- від кнопки.

Почнемо із простішого і більш корисного -- реакція на зовнішню подію із заданою затримкою.

неділю, 27 березня 2016 р.

Таймери STM32 -- захоплення ШІМ/HAL

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

Черговий такий приклад -- вирішена раніше, засобами CMSIS, задача визначення тривалості натискання кнопки із використанням режиму захоплення ШІМ. Задача, насправді, зовсім трішки відрізняється від "канонічної", із документації -- один таймер генерує ШІМ, інший його ловить, але дає можливість "помацати" таймер руками -- натискаючи кнопку.

суботу, 26 березня 2016 р.

Таймери STM32 -- захоплення ШІМ/CMSIS

За допомогою захоплення вводу, розглянутого недавно, можна організувати потрібні для роботи із далекоміром вимірювання тривалості імпульсів. Реалізувати це можна як програмно (налаштувавши захоплення по спаду і по зростанню сигналу та програмно відстежувати поточний стан) так і апаратно (з'єднавши фізично два канали таймера і на одному захоплювати фронт, на іншому -- спад). Думка, що такі задачі постають, прийшла й розробникам STM32, тому у таймерів є спеціальний режим -- захоплення ШІМ. Зацитую описане в огляді таймерів:
Хитра конфігурація режиму захоплення сигналу -- коли два канали "слухають" той самий вхід, один ловить фронт, другий спад. При тому, початок відліку каналу по фронту очищає лічильник таймера. Тоді подія по спаданню збереже у TIMx_CCRx відповідного каналу тривалість імпульсу, а наступний фронт дасть у TIMx_CCRx каналу, що їх ловить, період. Значно краще все це зрозуміти можна на рисунку із даташіту:


Режим захоплення ШІМ.
(c) STMicroelectronics
Насправді, це всього лиш комбінація вже розглянутого режиму захоплення, різних видів тригерів і реакції на них та під'єднання двох каналів до одного піну.

вівторок, 22 березня 2016 р.

Таймери STM32 -- захоплення вводу/HAL

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

Традиційно, створюємо проект STM32CubeMX, вибираємо мікроконтролер і т.д. Далі, налаштовуємо таймер та пін кнопки:

понеділок, 21 березня 2016 р.

Таймери STM32 -- захоплення вводу/CMSIS

Для роботи із далекоміром нам треба не тільки подавати імпульс заданої довжини, але і заміряти тривалість імпульсу на Echo, яка визначає час польоту звуку. Хоча це можна зробити і вручну, опитуванням, як раніше, або скориставшись зовнішнім перериванням EXTI, як буде розглянуто в подальшому, цікавіше зробити все автоматично -- за допомогою таймерів, які мають спеціальний режим -- Input capture mode.

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

середу, 16 березня 2016 р.

Таймери STM32 -- автоматична зупинка/HAL

Аналогічно до відповідного CMSIS-поста, беремо проект, котрий генерує ШІМ, збільшуємо період до видимого оком значення -- нам потрібен один імпульс заданої тривалості, а не власне ШІМ та кажемо зупинятися після переповнення.

Для цього на вкладці pinout слід поставити одну "пташку" -- One Pulse Mode:


Потім, в Configure, налаштовуємо період і тривалість імпульсу:

вівторок, 15 березня 2016 р.

Таймери STM32 -- автоматична зупинка/CMSIS

Цього разу -- зовсім коротка нотатка. Таймери володіють цікавою особливістю -- якщо встановити біт OPM в CR1, таймер автоматично зупинятиметься після події оновлення.

Важливе зауваження -- цей біт, OPM -- One-Pulse Mode, використовується для реалізації однойменного режиму One-pulse mode, який призначений керувати формою імпульсу -- генерувати його у відповідь на подію, із заданою затримкою після події та заданою довжиною. Про цей режим говоритимемо окремо. Цей пост -- своєрідна прелюдія до відповідної розмови -- ми просто навчимо таймер зупинятися. Така можливість теж корисна -- наприклад, для нашого далекоміра немає потреби робити якісь затримки, генерувати хитрі хвилі, абощо, але хотілося б, щоб таймер генерував один імпульс заданої довжини, і хотілося б, щоб він робив це повністю автоматично -- не використовуючи переривання та ручне вмикання-вимикання логічної одинички на піні.

понеділок, 14 березня 2016 р.

Таймери STM32 -- внутрішні тригери/HAL

(c) Wiki
Повторимо "подвиг" CMSIS, розглянутий раніше, зробивши із двох 16-бітних таймерів один 32-бітний, засобами HAL.

Почнемо із візуального конфігурування:


Для головного (master) таймера просто вмикаємо тактування. Підлеглому, slave, вказуємо працювати в режимі External Clock Mode 1 та отримувати тактування від внутрішнього джерела ITR3, котре, як ми знаємо з попереднього поста, під'єднане до TRGO TIM4.

пʼятницю, 11 березня 2016 р.

Таймери STM32 -- внутрішні тригери/CMSIS

Взято тут.
Як вже не раз згадувалося, таймери можуть постачати тактування один одному. Наприклад, один таймер може служити подільником для іншого -- переповнення головного (master) таймера приводить до одного відліку підлеглого (slave). Це дозволяє зробити із двох 16-бітних таймерів один 32-бітний. Хоча, комбінацій master-slave є багато більше -- як підлеглий таймер може реагувати на сигнал, описувалося тут (мова про біти SMS), а за яких умов головний (master) сигнал посилає -- описано нижче.

Подивимося, як користуватися цією можливістю на дещо надуманому прикладі -- мигатимемо світлодіодом у перериванні від TIM1, який буде підлеглим для TIM4.

На відміну від зовнішнього тактування,  розглянутого раніше, тут використано тактування від внутрішніх тригерів -- ITRx.

четвер, 10 березня 2016 р.

Таймери STM32 -- зовнішнє тактування/HAL

Ще один зовнішній годинник.
(c) Wiki
Повторимо зроблене в пості про зовнішнє тактування таймерів з використанням CMSIS за допомогою HAL та STM32CubeMX. Як завжди із графічними утилітами конфігурації і на відміну CMSIS-постів, тут буде багато картинок і мало власного коду. 

Проект, використаний тут, спільний для трьох постів -- цього і двох наступних, (про внутрішні тригери та біт OPM, засобами HAL) тому на елементи конфігурації, яка стосується інших таймерів, просто не звертайте уваги. 

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

середу, 9 березня 2016 р.

Таймери STM32 -- зовнішнє тактування/CMSIS

Зовнішній годинник, а що? :-)
(c) Wiki
Як вже говорилося раніше, таймери можуть тактуватися не тільки від RCC, але і від інших зовнішніх чи внутрішніх джерел:
  • External clock mode1 -- тактування від входів TI1 або TI2,
  • External clock mode2 -- від піна ETR,
  • Internal trigger clock (ITRx) -- від внутрішніх джерел.
Про внутрішні джерела тактування таймерів поговоримо окремо, а зараз познайомимося із зовнішнім тактуванням на простому прикладі -- підрахунку кількості натискання кнопки. 

вівторок, 8 березня 2016 р.

Таймери STM32 -- ШІМ/HAL

Беремо STM32CubeMX проект із попереднього прикладу (із відліком) та додаємо до нього TIM3, який генеруватиме на своєму каналі CH2, під'єднаному до PA7, PWM (ШІМ), змінюючи яскравість світлодіода, як і в попередньому пості, але засобами HAL.

"Малюємо" проект


Конфігуруємо TIM3

неділю, 6 березня 2016 р.

Таймери STM32 -- ШІМ/CMSIS

Здатність відраховувати час ([1], [2], [3]), звичайно, критична для таймерів, однак, всі, крім базових (та спеціалізованих, типу SysTick та watchdog-ів), вміють більше -- безпосередньо керувати виводами, пінами, мікроконтролера. Один із найпростіших, але дуже потужних, способів такого керування --- генерація ШІМ, широтно-імпульсна модуляції, (англійською -- PWM).

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

суботу, 5 березня 2016 р.

Таймери STM32 -- відлік часу/HAL

Раніше ми розглянули як здійснювати найпростіші операції із таймерами, безпосередньо маніпулюючи їх регістрами. Звичайно, користуючись константами та функціями із CMSIS, але нічим більш високорівневим. Тепер подивимося, як це ж зробити за допомогою HAL. Важливо, що HAL -- лише бібліотека, якою користуватися можна по різному, сама по собі вона особливих переваг не надає. (IMHO, звичайно). Однак, STM32CubeMX вміє генерувати ініціалізацію периферії з візуальних налаштувань, користуючись цією бібліотекою. Це дуже спрощує розробку -- все ж, принаймні для мене, найбільша проблема роботи із такими контролерами -- сотні бітів конфігурації периферії, які слід вмикати і вимикати в правильній послідовності. Cube дозволяє, як мінімум, побачити правильну таку послідовність -- спрощуючи й "ручну" роботу з ними в майбутньому. Як максимум -- просто про це не турбуватися. Додаткова абстракція вносить свої труднощі, але серйозною проблемою це не є -- весь код доступний, навіть без додаткової документації можна розібратися, що-куди-як, а, як буде показано в подальшому, за ввімкненої оптимізації, при всій громіздкості (в порівнянні із ручною маніпуляцією регістрами) коду HAL/STM32CubeMX, зростання розмірів пам'яті обох видів -- цілком скромне. 

Отож, повторимо зроблене в попередньому прикладі, користуючись HAL. 

четвер, 3 березня 2016 р.

Таймери STM32 -- відлік часу/CMSIS

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

Нагадаю, працюватимемо на прикладі STM32F100RB, яким обладнана STM32VLDiscovery. Для інших мікроконтролерів сімейства, скажімо, STM32F303, зміни будуть мінімальними, якщо взагалі будуть, навіть якщо користуватися виключно CMSIS.

Переривання таймерів


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

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

Список таких "комунальних" квартир переривань таймерів для STM32F100RB:
  • TIM1_BRK_TIM15_IRQn, TIM1_UP_TIM16_IRQn, TIM1_TRG_COM_TIM17_IRQn,  TIM1_CC_IRQn -- як бачимо, три із чотирьох переривань єдиного просунутого таймера цього контролера, TIM1, використовуються спільно із іншими таймерами (TIM15/16/17).
  • TIM2_IRQn
  • TIM3_IRQn
  • TIM4_IRQn
  • TIM6_DAC_IRQn -- разом із перериванням від ЦАП (DAC)
  • TIM7_IRQn
Зауважте, що таймери TIM12/13/14 у варіанта мікроконтролера STM32F100RB (у всіх Low i Medium density, якщо точніше) -- відсутні, є лише в High-density STM32F100.

середу, 2 березня 2016 р.

Таймер SysTick

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

SysTick timer 

SysTick timer -- простий 24-бітний таймер, частина ядра Cortex M, тому присутній у відповідних мікроконтролерах всіх виробників. Належить до підсистеми контролера переривань, NVIC.

вівторок, 1 березня 2016 р.

Відлік часу без таймерів

Альтернативний спосіб відліку часу
Кам'яна сокира. (c) Wiki

Відмірювати час за допомогою таймерів -- найбільш зручний і коректний спосіб. Однак, іноді він може не підходити, з тих чи інших мотивів. Одна з альтернатив -- чисто програмна затримка. Іншими словами, контролер змушують якийсь час виконувати задані інструкції. Якщо потік виконання один і переривань не виникає, такий спосіб доволі точний (а з перерахунку вимог, щоб він був точним, видно основні його недоліки). Важливо, що на відміну від x86, час виконання інструкцій мікроконтролера значно більш передбачуваний.

Наведений нижче приклад реалізації базується на коді з Leaflab Maple IDE, аналогу оболонки Ардуїно для STM32. Увага: Приклад може бути неточним -- особливо ретельно я не тестував.

Update: Див. також розвиток теми в "Мікросекундні затримки та відлік мікросекунд для STM32".