Как Вы знаете в STM32 много 16 битных таймеров. При этом их разрядности порой не достаточно для получения тайм штампов. При этом 32х битных таймеров всего два: TIM2 и TIM5.
|
Таймер |
Разрядность |
Шина |
Каналов |
|
TIM1 |
16 |
APB2 |
4 |
|
TIM2 |
32 |
APB1 |
4 |
|
TIM3 |
16 |
APB1 |
4 |
|
TIM4 |
16 |
APB1 |
4 |
|
TIM5 |
32 |
APB1 |
4 |
|
TIM6 |
16 |
APB1 |
0 |
|
TIM7 |
16 |
APB1 |
0 |
|
TIM8 |
16 |
APB2 |
4 |
|
TIM9 |
16 |
APB2 |
2 |
|
TIM10 |
16 |
APB2 |
2 |
|
TIM11 |
16 |
APB2 |
2 |
|
TIM12 |
16 |
APB1 |
2 |
|
TIM13 |
16 |
APB1 |
2 |
|
TIM14 |
16 |
APB1 |
2 |
Определения
up-time - время с момента включения питания на плату
тайм штамп - временная отметка. По сути это и есть up_time
В чем проблема?
Проблема в том, что в STM32 большинство таймеров обладают очень низкой разрядностью. Двенадцать таймеров 16 битные. Есть только два 32 битных таймера и они обычно чем-то заняты: моторы, счетчики импульсов и пр..
При этом большинство настоящих прошивок требуют возможности получать микросекундные тайм штампы. Это нужно для выдерживания пауз менее 1 ms, для импровизированных планировщиков на основе limiter-ов, для подписывания логов в UARTе и прочего. То есть нужен таймер, который увеличивается на +1 каждую одну микросекунду и не переполняется в обозримой перспективе.
Проблема с том что в случае 16 битного таймера такой таймер будет переполняться каждые 65 ms. Это ни о чем. Человек моргает и то продолжительнее. Переполнение за 65ms - это плохо.
|
разрядность |
Тактирование, MHz |
Макс число |
Переполнение,s |
Переполнение,min |
|
16 |
1 |
65536 |
0.065536 |
0.00109 |
|
32 |
1 |
4294967296 |
4294.96 |
71 |
|
64 |
1 |
18446744073709551616 |
18446744073709 |
307445734561 |
Постановка задачи.
Из двух 16 бит таймеров собрать один 32 битный таймер.
|
Таймер |
Биты |
Режим работы |
PSC |
Разрядность |
|
TIM3 |
0...15 |
master |
47 |
16 |
|
TIM9 |
16....31 |
slave |
0 |
16 |
Реализация
Хорошая новость заключается в том, что микроконтроллеры STM32 позволяют собирать каскадом составные аппаратные таймеры. Схемотехнически это выглядит так.

Надо отметить, что в STM32 не всяким таймером можно тактировать конкретный аппаратный таймер (TIM9). Например Timer 9 может тактировать одним из 4х таймеров на выбор. Выбор осуществляется трёхбитовым битовым полем Trigger selection (TS) в регистре TIMx_SMCR
|
Ведомый таймер (TIM9) |
Trigger selection |
Trigger selection |
|
Ведущий таймер / |
dec |
bin |
|
TIM2 |
0 |
0b00 |
|
TIM3 |
1 |
0b01 |
|
TIM10 |
2 |
0b10 |
|
TIM11 |
3 |
0b11 |
Для каждого аппаратного таймера есть отдельная таблица с реестром возможных ведущих таймеров.

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

Настройка ведущего таймера TIM3
--Подать тактирование на Timer3. В регистре RCC_APB1ENR установить бит 1.

--Активировать тактирование от внутренней шины
--В регистре TIMx_CR1 поле Clock division установить в ноль CKD=0. Пред делитель для тактовых импульсов.
--Переключить таймер3 в режим мастера. В регистре TIMx_CR2 в поле MMS ( Master mode selection ) прописать значение 2=0b10. Это для генерирования события Update. При переполнении таймера произойдет тактирование ведомого таймера. При переполнении ведущего таймера ведомый таймер увеличится на единицу.
--Прописать пред делитель, чтобы получилось инкрементирование каждый 1us. Значение пред делителя зависит от частоты тактирования таймера.
--Активировать таймер 3. Прописать в поле CEN=1 (Counter enable). После этого таймер начнет считать.
Сырые значения регистров выглядят так
-->tdrr 3
Base:0x40000400,Cnt:20
+-----+--------------------+-------+------+------------+------------+
| N | Name |offset | size | Addr | ValHex |
+-----+--------------------+-------+------+------------+------------+
| 1 | TIMx_CR1 | 0x000 | 0 | 0x40000400 | 0x00000001 |
| 2 | TIMx_CR2 | 0x004 | 4 | 0x40000404 | 0x00000020 |
| 3 | TIMx_SMCR | 0x008 | 4 | 0x40000408 | 0x00000000 |
| 4 | TIMx_DIER | 0x00c | 4 | 0x4000040c | 0x00000000 |
| 5 | TIMx_SR | 0x010 | 4 | 0x40000410 | 0x0000001f |
| 6 | TIMx_EGR | 0x014 | 4 | 0x40000414 | 0x00000000 |
| 7 | TIMx_CCMR1 | 0x018 | 4 | 0x40000418 | 0x00000000 |
| 8 | TIMx_CCMR2 | 0x01c | 4 | 0x4000041c | 0x00000000 |
| 9 | TIMx_CCER | 0x020 | 4 | 0x40000420 | 0x00000000 |
| 10 | TIMx_CNT | 0x024 | 4 | 0x40000424 | 0x00009731 |
| 11 | TIMx_PSC | 0x028 | 4 | 0x40000428 | 0x0000002f |
| 12 | TIMx_ARR | 0x02c | 4 | 0x4000042c | 0x0000ffff |
| 13 | TIMx_RCR | 0x030 | 4 | 0x40000430 | 0x00000000 |
| 14 | TIMx_CCR1 | 0x034 | 4 | 0x40000434 | 0x00000000 |
| 15 | TIMx_CCR2 | 0x038 | 4 | 0x40000438 | 0x00000000 |
| 16 | TIMx_CCR3 | 0x03c | 4 | 0x4000043c | 0x00000000 |
| 17 | TIMx_CCR4 | 0x040 | 4 | 0x40000440 | 0x00000000 |
| 18 | TIMx_BDTR | 0x044 | 4 | 0x40000444 | 0x00000000 |
| 19 | TIMx_DCR | 0x048 | 4 | 0x40000448 | 0x00000000 |
| 20 | TIMx_DMAR | 0x04c | 4 | 0x4000044c | 0x00000001 |
+-----+--------------------+-------+------+------------+------------+
Настройка ведомого таймера TIM9
--Подать тактирование на Timer9. В регистре RCC_APB2ENR установить в 1 бит 16 (RCC_APB2ENR_TIM9EN). Это нужно чтобы появилась возможность прописывать регистры аппаратного таймера. Без активации тактирования настройки не применятся.

-- В регистре TIMx_CR1 поле Clock division установить в ноль CKD=0. Пред делитель для тактовых импульсов.
--В регистре TIMx_SMCR (slave mode control register) поле Slave mode selection установить в SMS=7 ( External Clock mode 1 - Rising edges of the selected trigger (TRGI) clock the counter. )
--В регистре TIMx_SMCR поле Trigger selection установить в значение TS=1-(Internal Trigger 1 (ITR1)) . После инициализации в регистре TIMx_SMCR должно оказаться значение 0x17 = 0b1_0111.
--Активировать таймер 9. Прописать в поле CEN=1 (Counter enable). Пос��е этого таймер начнет считать.
-->tdrr 9
Base:0x40014000,Cnt:20
+-----+--------------------+-------+------+------------+------------+
| N | Name |offset | size | Addr | ValHex |
+-----+--------------------+-------+------+------------+------------+
| 1 | TIMx_CR1 | 0x000 | 0 | 0x40014000 | 0x00000001 |
| 2 | TIMx_CR2 | 0x004 | 4 | 0x40014004 | 0x00000000 |
| 3 | TIMx_SMCR | 0x008 | 4 | 0x40014008 | 0x00000017 |
| 4 | TIMx_DIER | 0x00c | 4 | 0x4001400c | 0x00000000 |
| 5 | TIMx_SR | 0x010 | 4 | 0x40014010 | 0x00000040 |
| 6 | TIMx_EGR | 0x014 | 4 | 0x40014014 | 0x00000000 |
| 7 | TIMx_CCMR1 | 0x018 | 4 | 0x40014018 | 0x00000000 |
| 8 | TIMx_CCMR2 | 0x01c | 4 | 0x4001401c | 0x00000000 |
| 9 | TIMx_CCER | 0x020 | 4 | 0x40014020 | 0x00000000 |
| 10 | TIMx_CNT | 0x024 | 4 | 0x40014024 | 0x00003eab |
| 11 | TIMx_PSC | 0x028 | 4 | 0x40014028 | 0x00000000 |
| 12 | TIMx_ARR | 0x02c | 4 | 0x4001402c | 0x0000ffff |
| 13 | TIMx_RCR | 0x030 | 4 | 0x40014030 | 0x00000000 |
| 14 | TIMx_CCR1 | 0x034 | 4 | 0x40014034 | 0x00000000 |
| 15 | TIMx_CCR2 | 0x038 | 4 | 0x40014038 | 0x00000000 |
| 16 | TIMx_CCR3 | 0x03c | 4 | 0x4001403c | 0x00000000 |
| 17 | TIMx_CCR4 | 0x040 | 4 | 0x40014040 | 0x00000000 |
| 18 | TIMx_BDTR | 0x044 | 4 | 0x40014044 | 0x00000000 |
| 19 | TIMx_DCR | 0x048 | 4 | 0x40014048 | 0x00000000 |
| 20 | TIMx_DMAR | 0x04c | 4 | 0x4001404c | 0x00000000 |
+-----+--------------------+-------+------+------------+------------+
Теперь каждый раз, когда надо получить тайм штамп можно просто прочитать два 16 бит регистра и скомпоновать одно 32битное значение.
uint32_t timer32_timestamp_get_us( void ) {
uint32_t tim_word_lo, tim_word_hi, time_stamp;
tim_word_hi = TIM9->CNT;
tim_word_lo = TIM3->CNT;
time_stamp = (tim_word_hi << 16U) | tim_word_lo;
return time_stamp;
}
Достоинства
1) Не происходят частые прерывания по таймеру и, как следствие, не тормозится основная прошивка.
2) Бесхозные 16ти битные таймеры внезапно начинают приносить реальную пользу.
3) Появляется еще один 32 битный таймер буквально из неоткуда.
Итог
Удалось собрать 32 битный таймер буквально из подручных материалов. Каскадирование таймеров может быть хорошим подспорьем в решении прикладных задач прошивки. Это открывает дорогу для генерирования полноценных тайм штампов в прошивках на STM32.
Вопросы
--Можно ли на STM32 собрать из четырех 16 битных таймеров собрать один 64 битный таймер? Может ли таймер работать одновременно в режиме master и slave?
Автор: danil_12345
