Почему существует разница во времени периодического прерывания?

Я пишу драйвер низкого уровня для протокола связи с одной линией. Эта линия подключена как к выводу Tx, так и к выводу Rx на микроконтроллере STM32F0, работающем с внутренними часами на частоте 8 МГц. Состояние вывода Tx устанавливается в прерывании таймера, а вывод Rx считывается во внешнем прерывании GPIO.

Для тестирования я переключаю вывод Tx на 416 мкс (значение автоматической перезагрузки составляет 3333 без предварительного делителя), а в прерывании GPIO я считываю разницу во времени между двумя последовательными прерываниями. Измеренное время составляет примерно 500 мкс от прерывания перехода с высокого уровня на низкий до прерывания перехода с низкого на высокий и 300 мкс от прерывания перехода с низкого уровня на высокий до прерывания перехода с высокого уровня на низкий. Почему такая разница? И как от этого избавиться?

Я проверил сигнал на осциллографе, и это идеальная прямоугольная волна с длительностью импульса 416 мкс. Я также использую htim->Instance->CNT = 0; и time = htim->Instance->CNT;, чтобы обернуть разные части кода, чтобы найти, откуда взялась разница, но безрезультатно.

Вот обработчики прерываний, измеренное время сохраняется в переменной tim3_value:

void TIM2_IRQHandler(void)
{
  if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(&htim2, TIM_IT_UPDATE) != RESET)
    {
        __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);
        HAL_GPIO_TogglePin(TX_GPIO_Port, TX_Pin);
        htim2.Instance->ARR = 3333;
    }
  }
return;
}

void EXTI4_15_IRQHandler(void)
{
  if(__HAL_GPIO_EXTI_GET_IT(RX_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(RX_Pin);
    tim3_value = htim3.Instance->CNT;
    htim3.Instance->CNT = 0;
  }
return;
}

person cuckoo    schedule 30.09.2020    source источник
comment
Вероятно, из-за физических свойств контактов ввода / вывода. Их времена перехода и пороговые напряжения высокого / низкого уровня   -  person Eugene Sh.    schedule 30.09.2020
comment
Я измерил время между концом прерывания таймера и началом прерывания GPIO, но не обнаружил значительной разницы.   -  person cuckoo    schedule 30.09.2020
comment
@EugeneSh. незначительный.   -  person 0___________    schedule 30.09.2020
comment
Хорошо, как вы измеряете время?   -  person Eugene Sh.    schedule 30.09.2020
comment
Гарантировано ли получение этих прерываний в определенное время? Могут ли они быть задержаны, если выполняется другая обработка прерывания?   -  person tadman    schedule 30.09.2020
comment
@tadman, что зависит от их приоритета.   -  person 0___________    schedule 30.09.2020
comment
@P__J__ Мне интересно, не мешают ли периодически другие прерывания.   -  person tadman    schedule 30.09.2020
comment
@ Евгений Ш. Как я уже сказал в посте, я использовал микротаймер для измерения времени (сбросил счетчик в конце прерывания таймера и прочитал значение счетчика в начале прерывания GPIO). Это действительный способ измерить время?   -  person cuckoo    schedule 30.09.2020
comment
Ваши два неустойчивых времени перехода, кажется, в сумме примерно в 2 раза превышают время цикла, равное 832 мкс.   -  person tadman    schedule 30.09.2020
comment
Я считаю, что это не проблема.   -  person 0___________    schedule 30.09.2020
comment
@tadman да, я заметил это, но я не знаю, откуда это взялось   -  person cuckoo    schedule 30.09.2020
comment
htim2.Instance->ARR = 3333; не изменит ARR. Он изменит его при следующем переполнении   -  person 0___________    schedule 30.09.2020
comment
Это интересная проблема. Не могли бы вы добавить код, который используется для инициализации RX / TX GPIO (режим, скорость и т. Д.), Периферийных устройств EXTI и приоритетов IRQ для обработчика IRQ TX и RX. Можно ли предположить, что в вашем примере проекта нет других прерываний?   -  person Blue    schedule 04.10.2020


Ответы (1)


Таймеры STM32 имеют предварительно загруженный ARR. Это означает, что он изменит фактическое значение внутреннего регистра ARR при событии обновления. Если вы хотите изменить его в определенный момент, вам необходимо сгенерировать это событие самостоятельно, записав 1 в бит UG в регистре EGR.

Я настоятельно рекомендую внимательно прочитать Справочное руководство STM32, поскольку волшебных функций HAL недостаточно

Я бы все равно не стал делать это в прерывании. Времена STM32 имеют механизм, называемый режимом прямой передачи. Он использует DMA для загрузки значения (значений) регистра таймера для выбранного события. Вам просто нужно подготовить данные для него, и при событии обновления ARR будет загружаться из памяти автоматически.

person 0___________    schedule 30.09.2020
comment
но в моем случае я установил то же значение, поэтому это не должно вызывать разницы - person cuckoo; 30.09.2020