TIM4 просто циклично задает начало отсчета (зеленая линия) с постоянной частотой. Далее мне надо получить картину как на рисунке, где все параметры (T1, T2, T3, P1, P2, P3) динамически могу меняться путем задания их длительности с ПК.
Основная проблема в том, что я не могу добиться нужной мне точности срабатывания таймеров и установки логических уровней на пинах мк. Для этого попробовал разные подходы:
1. Изначально была идея сделать на прерываниях. Довольно банально, от TIM4 стартуем все таймеры и в их прерываниях выставляем логические уровни и делаем их перезапуск.
Запускаем все таймеры
Спойлер
Код: Выделить всё
void TIM4_Callback(void)
{
if(LL_TIM_IsActiveFlag_UPDATE(TIM4))
{
// START
GPIOC->BSRR = GPIO_BSRR_BS0;
// START TIMER 7
TIM7->ARR = SetTime7 - 1;
TIM7->SR &= ~ TIM_SR_UIF;
TIM7->CNT = 0;
TIM7->DIER = TIM_DIER_UIE;
LL_TIM_EnableCounter(TIM7);
// START TIMER 3
TIM3->ARR = SeеTime3 - 1;
TIM3->EGR = TIM_EGR_UG;
TIM3 ->SR &= ~ TIM_SR_UIF;
TIM3->CNT = 0;
TIM3->DIER = TIM_DIER_UIE;
LL_TIM_EnableCounter(TIM3);
// START TIMER 5
TIM5->ARR = SetTime5 - 1;
TIM5->EGR = TIM_EGR_UG;
LL_TIM_ClearFlag_UPDATE(TIM5);
TIM5->CNT = 0;
TIM5->DIER = TIM_DIER_UIE;
LL_TIM_EnableCounter(TIM5);
}
else
{
__NOP();
}
LL_TIM_ClearFlag_UPDATE(TIM4);
}
Спойлер
Код: Выделить всё
void TIM7_Callback(void)
{
if(LL_TIM_IsActiveFlag_UPDATE(TIM7))
{
switch (StateTim7)
{
case 0:
StateTim7 = 1;
// SET PIN LEVEL HIGH
GPIOC->BSRR = GPIO_BSRR_BS3;
TIM7->ARR = SetPeriod7 - 1;
break;
case 1:
StateTim7 = 0;
// SET PIN LEVEL LOW
GPIOC->BSRR = GPIO_BSRR_BR3;
LL_TIM_DisableCounter(TIM7);
break;
}
}
else
{
__NOP();
}
LL_TIM_ClearFlag_UPDATE(TIM7);
}
Но когда я уменьшаю время срабатывания таймера допустим T7 до 0.1 мк сек от старта, то тут во-первых этот тайминг не выставится меньше 2.5 мк сек (Рисунок 2), во вторых почему-то начинает сильно ошибаться величина P7, может уменьшиться в 1.5 раза и тд, происходит какое-то влияние одной величины на другую.
Такая не предсказуемость меня не сильно устроила, поэтому попробовал второй вариант.
2. Решил я переделать все на one pulse mode. В целом идея та же в коллбеке TIM4 стартуем 3 таймера, но уже настроенные в этом режиме. Для эксперимента взял TIM11 и TIM12
Спойлер
Код: Выделить всё
void TIM4_Callback(void)
{
if(LL_TIM_IsActiveFlag_UPDATE(TIM4))
{
TIM11->ARR = 4000;
TIM11->CCR1 = 1000;
TIM11->EGR = TIM_EGR_UG;
TIM11->CNT = 0;
TIM11->SR &= ~ TIM_SR_UIF;
TIM11->DIER = TIM_DIER_UIE;
HAL_TIM_Base_Start(&htim11);
HAL_TIM_PWM_Start(&htim11, TIM_CHANNEL_1);
TIM12->ARR = 4000;
TIM12->CCR2 = 1000;
TIM12->EGR = TIM_EGR_UG;
TIM12->CNT = 0;
TIM12->SR &= ~ TIM_SR_UIF;
TIM12->DIER = TIM_DIER_UIE;
HAL_TIM_Base_Start(&htim12);
HAL_TIM_PWM_Start(&htim12, TIM_CHANNEL_2);
}
else
{
__NOP();
}
LL_TIM_ClearFlag_UPDATE(TIM4);
}
Код: Выделить всё
TIM11->ARR = 4000;
TIM11->CCR1 = 1000;
TIM11->EGR = TIM_EGR_UG;
TIM11->CNT = 0;
TIM11->SR &= ~ TIM_SR_UIF;
TIM11->DIER = TIM_DIER_UIE;
HAL_TIM_Base_Start(&htim11);
HAL_TIM_PWM_Start(&htim11, TIM_CHANNEL_1);
3. Третьей моей идеей является взять один таймер с 4мя каналами, запустить его в коллбеке TIM4 и в прерывании от каждого канала запускать еще по одному таймеру, чтобы выдержать необходимые длительности импульсов (P1, P2, P3). Берем пока TIM12 на 2 канала.
Ставлю такие параметры:
Для канала 1 - TIM_OC_InitStruct.CompareValue = 1;
Для канала 2 - TIM_OC_InitStruct.CompareValue = 2500;
Т.е. при запуске в том же самом коллбеке TIM4
Код: Выделить всё
TIM12->EGR = TIM_EGR_UG;
LL_TIM_EnableIT_CC1(TIM12);
LL_TIM_EnableIT_CC2(TIM12);
LL_TIM_EnableCounter(TIM12);
Спойлер
Код: Выделить всё
void TIM12_Callback(void)
{
if(LL_TIM_IsActiveFlag_UPDATE(TIM12))
{
if(LL_TIM_IsActiveFlag_CC1(TIM12))
{
LL_TIM_ClearFlag_CC1(TIM12);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_2); // Test
LL_TIM_DisableIT_CC1(TIM12);
}
else if(LL_TIM_IsActiveFlag_CC2(TIM12))
{
LL_TIM_ClearFlag_CC2(TIM12);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_2); // Test
LL_TIM_DisableIT_CC2(TIM12);
LL_TIM_DisableCounter(TIM12);
}
else
{
__NOP();
}
}
else
{
__NOP();
}
}
По факту первый стартует спустя 1.5 мк сек, а второй 25 + 1.5 мк сек. Т.е. опять задержка от времени старта единицы мк секунд.
Исходя из этого:
1) Почему такие большие задержки запуска таймеров?
2) Какой подход для решения данной задачи будет самым правильным?
3) Может просто я что-то делаю не так?
Буду благодарен за любые подсказки, ибо не понимаю причину такой работы мк.
Лирическое отступление: мк - stm32f746. Настройка в CubeMX (для таймеров LL), так как используется FreeRTOS, но приоритет таймеров выше чем у любой задачи ОС. Таймеры функции ОС не используют


