UC/OS-III Systick & Периферийный таймер0 для ШИМ вмешиваться
У меня проблемы с получением сигнала PWM для светодиодов, работающих без сбоев на NXP LPC1857 с ОС uC/OS-III. Только когда я отключаю ОС, работающую на 1 мс, мерцание, которое происходит регулярно, прекращается.
Я настроил свой таймер с 4 регистрами совпадений: по одному для каждого цвета (красный, зеленый, синий) и по одному на полный период. Первые три соответствующих выхода очищают физические выходные выводы для каждого цвета. При совпадении последнего периода генерируется прерывание для установки всех трех цветовых выходов для следующего периода.
я попытался отключить прерывания от ОС во время прерывания timer0, добавив следующий код вокруг прерываний:
void TIMER0_IRQHandler(void)
{
CPU_SR_ALLOC();
OS_CRITICAL_ENTER();
OSIntEnter();
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_RED))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_RED);
PWM_TIMER->EMR &= ~(((uint32_t) 0x01) << PWM_RED);
}
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_GREEN))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_GREEN);
PWM_TIMER->EMR &= ~(((uint32_t) 0x01) << PWM_GREEN);
}
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_BLUE))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_BLUE);
PWM_TIMER->EMR &= ~(((uint32_t) 0x01) << PWM_BLUE);
}
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_MATCH))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_MATCH);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_RED);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_GREEN);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_BLUE);
}
OS_CRITICAL_EXIT();
OSIntExit();
}
У кого-нибудь есть идея, почему помада может вызвать мерцание в сигнале ШИМ?
2 ответа
Наконец нашел решение, хотя я не совсем понимаю, почему:P.
После полного удаления ОС из моих собственных задач, за исключением задачи ШИМ, проблемы все еще оставались. Поэтому я вернулся к коду таймера.
Единственное, что мне нужно было добавить, чтобы избавиться от мерцания, это сброс таймера после прерывания периода:
Старый:
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_MATCH))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_MATCH);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_RED);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_GREEN);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_BLUE);
}
Новое:
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_MATCH))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_MATCH);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_RED);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_GREEN);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_BLUE);
Chip_TIMER_Reset(PWM_TIMER);
}
Может кто-нибудь объяснить, зачем нужен этот сброс?
Я ожидал, что следующая строка позаботится об этом (что входит в мою процедуру инициализации):
Chip_TIMER_ResetOnMatchEnable(PWM_TIMER, PWM_MATCH);
Вы не должны использовать OS_CRITICAL_ENTER() и OS_CRITICAL_EXIT(). Вместо этого вы должны использовать CPU_CRITICAL() и CPU_CRITICAL_EXIT(), чтобы отключить прерывания во время критической секции.
Кроме того, этот ISR не сигнализирует о какой-либо задаче, поэтому вам не нужно вызывать OSIntEnter () и OSIntExit (). Я считаю, что ваш код должен быть просто:
void TIMER0_IRQHandler(void)
{
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_RED))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_RED);
PWM_TIMER->EMR &= ~(((uint32_t) 0x01) << PWM_RED);
}
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_GREEN))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_GREEN);
PWM_TIMER->EMR &= ~(((uint32_t) 0x01) << PWM_GREEN);
}
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_BLUE))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_BLUE);
PWM_TIMER->EMR &= ~(((uint32_t) 0x01) << PWM_BLUE);
}
if (Chip_TIMER_MatchPending(PWM_TIMER, PWM_MATCH))
{
Chip_TIMER_ClearMatch(PWM_TIMER, PWM_MATCH);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_RED);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_GREEN);
PWM_TIMER->EMR |= (((uint32_t) 0x01) << PWM_BLUE);
}
}
джинсовый