Estoy trabajando en el firmware de un STM32F103 que se comunica a través de 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 vinculados. 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 con un retorno de carro ("v 12345", donde el número de dígitos es variable). Tengo un código para analizar la respuesta y extraer un valor numérico de ella. Una vez que se analiza la respuesta, el comando de sondeo de registro debe transmitirse nuevamente al controlador del motor. El STM32 también lee un canal ADC sobre DMA en modo circular en segundo plano.
Me gustaría implementar esto usando el controlador DMA para hacer que todo no bloquee tanto como sea posible, pero estoy un poco confundido en cuanto a qué interrupciones debo usar y cuándo se activan. Sin usar el controlador DMA, el código de análisis actualmente reside 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 completa de la transferencia DMA? ¿Hay alguna diferencia funcional en este caso entre usar la interrupción DMA TC y la interrupción USART RXNE?
Puede configurar DMA para que funcione en modo cíclico, y con un búfer razonablemente grande puede extraer caracteres con la frecuencia que desee con una poll
función simple. Simplemente almacene el índice del último carácter recuperado y use el registro DMA para verificar cuántos caracteres tiene que recibir hasta que se renueve (el registro AFAIR tiene NDTR
en su nombre), y procese los caracteres recibidos desde la última llamada, luego actualice el índice del último carácter recuperado.
El uso de DMA descrito lo hace poll
independiente del contexto desde el que lo llama, siempre que evite la preferencia. Luego puede usar la interrupción RX para activar llamadas de sondeo, o puede hacerlo en otro contexto (por ejemplo, con algunos eventos periódicos).
Esto es generalmente eficiente si los marcos son lo suficientemente largos, la tasa de baudios es grande y la latencia de 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 procesándolos char por char de la manera actual, y el uso de DMA puede ser excesivo.
Como señaló @Chris Stratton, también puede configurar DMA para una transmisión única y esperar el tiempo suficiente, cambiar el protocolo o usar otra señal como "fin de transmisión", y luego procesar el cuadro en el búfer DMA.
Deberías usar interrupciones DMA. Estoy usando STM32F02 con bibliotecas periféricas STM32 STL, pero la idea es más o menos la misma para F01:
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 une UART con DMA, y creo que esa es su respuesta. De esta forma, el DMA copiará un byte al puntero que proporcionaste en la configuración cada vez que se dispare un evento RXNE, pero interrumpiendo SÓLO cuando se dispare un evento Transfer Complete (DMA_IT_TC), llamando a la función DMA correspondiente según el canal configurado. / arroyo.
jimmyb
m.alin
the parsing code currently resides in the USART RXNE interrupt
Una mejor manera sería usar solo la interrupción RX para colocar el byte actual en un búfer circular. En el bucle principal, compruebe si el búfer contiene un mensaje completo y analice ese mensaje.jimmyb
gbulmer
chris stratton
joe panadero
connor lobo
A better way would be to only use the RX interrupt to put the current byte in a circular buffer.
: esto solo es cierto si 1. necesita responder a ciertos eventos dentro de un marco de tiempo finito y 2. no tiene las instalaciones para interrupciones anidadas . Dado que está en un STM32, tiene un NVIC con múltiples prioridades de interrupción, por lo que es completamente aceptable tener una lógica significativa en los controladores de interrupciones.