STM32: Невозможно выйти из обработчика прерывания для прерывания UART

Я реализую простой протокол приема-передачи UART на STM32F103, код библиотеки / шаблон, который я здесь использую, это LL, а не HAL (так как HAL включает в себя безумные объемы служебных данных)

Моя проблема в том, что после успешного ввода обработчика прерываний "USART1_IRQHandler" он продолжает работать бесконечно. Мой код здесь:

    void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
    int ii = 0;
    for(ii=0; ii<4;  ii++){
        LL_mDelay(40);
        LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
        LL_mDelay(40);
        LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);

    }
    uint8_t cc = LL_USART_ReceiveData8(USART1);
    LL_USART_TransmitData8(USART1, cc);
    LL_mDelay(130);

    //LL_USART_ClearFlag_RXNE(USART1);
    //NVIC_ClearPendingIRQ( USART1_IRQn );

  /* USER CODE END USART1_IRQn 0 */
  /* USER CODE BEGIN USART1_IRQn 1 */
  /* USER CODE END USART1_IRQn 1 */
}

и в main.c у меня есть:

LL_USART_EnableIT_RXNE(USART1);
  while (1)
  {

        LL_mDelay(300);
        LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
        LL_mDelay(300);
        LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);

        //LL_USART_EnableIT_TC(USART1);

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }

Команды GPIO_Toggle предназначены только для мигания светодиода, поэтому я знаю, что происходит. Вот что происходит: когда я включаю MC, он входит в основной цикл и медленно мигает. Когда я посылаю что-то (~10 байт) через UART, светодиод начинает быстро мигать, указывая, что он вошел в обработчик прерываний. Проблема в том, что она никогда не останавливается и продолжает вращаться в обработчике прерываний.

Я пытался использовать теперь прокомментированные функции

LL_USART_ClearFlag_RXNE(USART1);
NVIC_ClearPendingIRQ( USART1_IRQn );

в одиночку или в комбинации, но они абсолютно ни на что не влияют. Что я делаю неправильно? Как я могу выйти из обработчика?

1 ответ

На самом деле все в вашем обработчике прерываний USART неверно.

  1. Вы не проверяете, что вызвало прерывание. Если это флаг RXNE, вы должны просто загрузить значение из регистра DR. Вам не нужно снимать какие-либо флаги. Если это флаг TXE, вы можете сохранить данные в регистр DR. Вы не можете очистить этот флаг любым другим способом. Если у вас нет данных для отправки, вам необходимо отключить прерывание TXE. В противном случае он будет срабатывать непрерывно.

Вы не можете просто читать и записывать регистр данных, когда хотите. Вы должны знать, разрешено ли вам

Вы также должны контролировать статусы ошибок.

  1. Вы не должны использовать какие-либо задержки в процедурах прерывания. Держите это как можно быстрее.
  2. Не прикасайтесь к NVIC, за исключением включения и отключения прерываний, так как сейчас вы не знаете, для чего они нужны.

Системное время, используемое для управления задержками, обновляется периодическим прерыванием sysTick. Если прерывание RXNE имеет более высокий приоритет, чем прерывание sysTick, оно не будет обрабатываться, пока вы находитесь внутри обработчика RXNE IRQ, поэтому время никогда не будет увеличиваться и время окончания задержки никогда не будет достигнуто. В зависимости от того, как реализована ваша задержка, он может просто поставить ЦП в спин-блокировку, которая никогда не сможет выйти.

Другие вопросы по тегам