¿Problema de indicador IDLE con uart?

void USART2_IRQHandler(void)
 
{
 
 /* USER CODE BEGIN USART2_IRQn 0 */
 
  /* UART IDLE Interrupt */
 
    if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) == SET)  
 
    {
 
     __HAL_UART_CLEAR_IDLEFLAG(&huart2);
 print("time %d",timeCounter");
receivedDataFlag = 1;

 
}
 
}

Cuando uso esta función, verifico los estados de inactividad de la línea y decido los datos recibidos o no recibidos. Pero esta interrupción se activa durante la transmisión. ¿Cómo puedo separar la línea de datos de recepción inactiva y la de recepción inactiva?

Quiero activar solo recibir la línea de datos inactiva, ¿cómo puedo hacer eso? ¿Qué otro registro debo mirar?

Obtengo un resultado muy interesante,

El remitente envía datos cada 100 ms a mi dispositivo;

Si uso las funciones DMA de recepción única; tiempo de retorno 10, 110, 220,330 (Estados inactivos trabajando)

Pero si recibí que después de transmitir datos con uart, estos valores de tiempo devuelven 10,13,15, ... una función de transmisión media cambia el estado inactivo de la línea, ¿cómo es posible? ¿El UART_FLAG_IDLE está relacionado solo con rx?

EDITAR: Por cierto, estoy usando rs485, así que cuando empiezo a transmitir, configuro el modo de transmisor del transceptor, de modo que el modo del receptor del lado del remitente, ¿así que mi MCU decide INACTIVO en este estado? ¿es eso posible? ¿Cómo puedo proteger esta situación?

Cuando inicio el modo de transmisión después de recibir los datos, luego completé la devolución de llamada, cuando llamo a HAL_UART_Receive_DMA(&huart2,(uint8_t*)dma_rx_buf,DMA_BUF_SIZE); función IDLE disparo de interrupción cada 5 ms pero tiempo de espera de envío de datos 100 ms

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
 

  HAL_UART_DMAStop(&huart2);
  dmaTransmitCompletedFlag = 1;
  RS485_Set_Receive_Mode();
  HAL_UART_Receive_DMA(&huart2,(uint8_t*)dma_rx_buf,DMA_BUF_SIZE);
  waitForTransmittingData = 0;

}
¡Nunca haga llamadas de función desde ISR! Acaba de presionar todos los registros utilizados en ISR y ahora lo vuelve a hacer. El printf aumenta los registros utilizados y la latencia de la función en ISR es un desperdicio. Establece tu bandera. En su software, verifique la bandera, procésela e imprima el mensaje.
@StainlessSteelRat ¿Hablas en serio sobre lo que dijiste? Llamar funciones desde ISR está bien. El STM32 HAL ya lo hace. Es un STM32, por lo que en ISR los registros se apilan por hardware para el contexto ISR de todos modos, no hay más penalización que para una llamada de función normal. Además, el STM32 podría tener como 1 megabyte de RAM, por lo que no es un problema, ni siquiera en un STM32 de 8 kilobytes. Lo que no es correcto es llamar a una función pesada como printf en ISR, y lo más probable es que no vuelva a entrar, por lo que esos son los problemas más importantes.
Depende de la función. Cualquier printf es un cerdo y es parte del problema de OP.
@StainlessSteelRat tiene razón en que usar impresiones en una interrupción es un problema, ya que el controlador de flujo stdio debe ser seguro para subprocesos. Que no es por defecto para stm32.

Respuestas (3)

Esa interrupción se usa tanto para transmitir como para recibir.

El IDLE es relevante solo para la recepción, significa que hay al menos un cuadro completo de inactividad detectado.

Usar print en una interrupción no es aconsejable, especialmente si la impresión usa el mismo UART para el que es la interrupción.

imprimir usando usart1 pero esta interrupción usando usart2, ¿es IDLE relevante solo recepción, cómo es esto posible? ¿Cómo está mi temporizador muy cerca?
Por cierto, estoy usando rs485, así que cuando empiezo a transmitir, configuro el modo de transmisor del transceptor, de modo que el modo del receptor del lado del remitente, ¿así que mi MCU decide INACTIVO en este estado? ¿es eso posible?
en segundo lugar, la precaución contra la impresión en una interrupción. Además de la naturaleza de bloqueo de esa función, hay mucha sobrecarga y uso de RAM que aumenta aún más el tiempo de ejecución. La mejor práctica es mantener sus controladores muy rápidos y simples, y hacer pasar una funcionalidad más intensiva al establecer banderas en el controlador y borrarlas en el ciclo principal. Si los controladores se ejecutan demasiado tiempo, obtendrá 'tormentas de interrupción' que básicamente bloquean su código.
@mathco No entiendo por qué preguntas cómo es posible esto, porque así está diseñado. IDLE es relevante solo para la recepción, se establece cuando después de la recepción de un cuadro no se detecta la recepción de un nuevo cuadro dentro de un período de tiempo de espera de un cuadro. Si desea que le cite el manual, debe indicar qué modelo exacto de microcontrolador STM32 está utilizando.
Agregué algunos detalles en mi pregunta.
Todavía no entiendo el problema. Si configura RS485 en modo de transmisión, no sabemos si el STM32 puede recibir datos transmitidos o no. Aún así, siempre que el receptor vea un marco inactivo, creará una interrupción inactiva. Si no desea interrupciones inactivas, deje de usarlas. Pero como dije, no hay problema en cómo funcionan las interrupciones IDLE, el problema es que puede esperar que funcionen de manera diferente a cómo funcionan realmente y cómo usa el transceptor RS485 puede afectarlo. Y nunca menciona qué microcontrolador STM32 exacto usa para que nadie pueda cotizarle el manual. Edite el tipo STM32.

Esa IRQ está dedicada a USART2, pero se llama para cada interrupción habilitada asociada con USART2. Eso significa que el controlador debe verificar y manejar cada señal de interrupción habilitada. Para STM32 USART, eso incluye señales fundamentales para interrumpir el UART como TXNE y RXNE, así como señales de error, IDLE, etc.

La señal IDLE es para enmarcar recepciones de varios bytes (un problema común para USART, especialmente en entornos ruidosos). Se afirma cuando la línea de recepción se ha declarado alta (o 'inactiva') durante algún tiempo de rebote (determinado por la configuración de sobremuestreo/velocidad en baudios), después de que esa línea haya estado activa (durante la recepción de un grupo de uno o más bytes) . Esto es útil porque puede usarlo para restablecer su búfer de recepción al índice '0', de modo que el siguiente cuadro se alinee correctamente (incluso si se recibieron muy pocos o demasiados bytes en el cuadro actual). Normalmente, debe implementar este tipo de lógica con un periférico de temporizador dedicado, pero STM32 lo empaqueta convenientemente en sus periféricos USART (aunque no es compatible con el controlador HAL nativo).

Si realmente desea que solo la señal inactiva active una interrupción, deberá desactivar manualmente todas las demás señales de interrupción. Si desea un receptor UART útil controlado por interrupciones, no le sugiero que lo haga.

De una de sus preguntas anteriores, le di algunos enlaces, donde esto se implementa.

Código fuente

USART3_IRQHandler(void) {
    /* Check for IDLE line interrupt */
    if (LL_USART_IsEnabledIT_IDLE(USART3) && LL_USART_IsActiveFlag_IDLE(USART3)) {
        LL_USART_ClearFlag_IDLE(USART3);        /* Clear IDLE line flag */
        usart_rx_check();                       /* Check for data to process */
    }

    /* Implement other events when needed */
}
Miré todo el código fuente en este enlace antes de escribir mi código, pero la interrupción de IDLE se activa cuando el transceptor RS485 inicia el modo de transmisión, no sé por qué.
Después de esta función, disparador de interrupción IDLE; void HAL_UART_TxCpltCallback(UART_HandleTypeDef huart) { HAL_UART_DMAStop(&huart2); dmaTransmitCompletedFlag = 1; RS485_Establecer_Modo_Recibir(); HAL_UART_Receive_DMA(&huart2,(uint8_t )dma_rx_buf,DMA_BUF_SIZE); esperar para transmitir datos = 0; }