4 votos

STM32 USART con DMA -- ¿qué interrupciones utilizar?

Estoy trabajando en un firmware para un STM32F103 que se comunica por RS232 a 115200 baudios con un controlador de motor. El controlador del motor (un Copley Xenus XTL ) funciona con un protocolo de "hablar cuando se le habla". Estoy usando la interfaz de programación ASCII en los documentos enlazados. El STM32 siempre envía el mismo comando ("g r0x18") para sondear un registro, y el controlador del motor responde con un número variable (~4-10 bytes) de caracteres terminados por un retorno de carro ("v 12345", donde el número de dígitos es variable). Tengo un código para analizar la respuesta y sacar un valor numérico de ella. Una vez que la respuesta es analizada, el comando de sondeo de registro debe ser transmitido al controlador del motor de nuevo. El STM32 también está leyendo un canal ADC sobre DMA en modo circular en el fondo.

Me gustaría implementar esto usando el controlador DMA para que todo sea lo menos bloqueante posible, pero estoy un poco confundido en cuanto a qué interrupciones debería usar y cuándo se disparan. Sin usar el controlador DMA, el código de análisis reside actualmente en la interrupción USART RXNE. Supongamos que transmito un comando y el controlador del motor comienza a responder. Creo que la interrupción RXNE se dispara por cada byte recibido, pero ¿qué pasa con la interrupción de transferencia DMA completa? ¿Hay alguna diferencia funcional en este caso entre usar la interrupción DMA TC y la interrupción USART RXNE?

3voto

kwesoly Puntos 121

Puedes configurar el DMA para que funcione en modo cíclico, y con un búfer razonablemente grande puedes sacar caracteres tan a menudo como quieras con simples poll función. Sólo hay que almacenar el índice del último carácter recuperado y utilizar el registro DMA para comprobar cuántos caracteres tiene que recibir hasta el roll over (el registro AFAIR tiene NDTR en su nombre), y procesa los caracteres recibidos desde la última llamada, luego actualiza el índice del último carácter recuperado.

El uso de DMA descrito hace que su poll independientemente del contexto desde el que se llame, siempre y cuando se evite la previsión. A continuación, puede utilizar la interrupción RX para desencadenar la llamada de sondeo (s), o puede hacerlo en otro contexto (por ejemplo, con algunos eventos periódicos).

Esto es generalmente eficiente si las tramas son lo suficientemente largas, la tasa de baudios es grande y la latencia de la interrupción es mayor que el tiempo de recepción de un solo carácter.

Pero si los datos se reciben con la suficiente lentitud, puede salirse con la suya el procesamiento de char por la vía actual, y el uso de DMA puede ser excesivo.

Como señaló @Chris Stratton, también se puede configurar DMA para una sola transmisión, y esperar el tiempo suficiente, cambiar el protocolo o utilizar otra señal como "fin de la transmisión" - y luego procesar la trama en el buffer DMA.

1voto

fenix Puntos 1

Deberías utilizar las interrupciones DMA. Estoy usando el STM32F02 con las bibliotecas de periféricos STL de STM32, pero la idea es más o menos la misma para el F01:

  • Inicialice su UART
  • Inicializar DMA (¡no olvides proporcionar la señal CLK para el periférico ANTES de llamar a DMA_Init!)
  • Configure las interrupciones NVIC y DMA, y habilite DMA como sigue:

 NVIC_InitTypeDef NVIC_InitStructure;
 //Enable DMA1 channel IRQ Channel
 //Note: maybe in your implementation you don't have DMAx_Streamy, look for channel/ stream configurations in your microcontroller manual

 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream1_IRQn; // This could be different in your implementation

 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);

 // Enable DMA1 Channel Transfer Complete interrupt
 DMA_ITConfig(DMA1_Stream1, DMA_IT_TC, ENABLE);

 USART_DMACmd(ACCESSORY_UART, USART_DMAReq_Rx, ENABLE);
 DMA_Cmd(DMA1_Stream1, ENABLE);

La función USART_DMACmd vincula la UART con la DMA, y creo que esa es tu respuesta. De esta manera, el DMA copiará un byte al puntero que proporcionaste en la configuración cada vez que se dispare un evento RXNE, pero interrumpiendo SOLO cuando se dispare un evento de Transferencia Completa (DMA_IT_TC), llamando a la función DMA correspondiente según el canal/ stream configurado.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X