11 votos

¿Por qué no utilizar siempre DMA en favor de las interrupciones con UART en STM32?

El mes pasado pasé mucho tiempo consiguiendo que la UART (para MIDI) funcionara con un STM (STM32F103C8T6) usando interrupciones, sin mucho éxito.

Sin embargo, esta tarde usando DMA ha funcionado bastante rápido.

Ya que por lo que leo DMA es más rápido y alivia a la CPU, ¿por qué no usar siempre DMA en favor de las interrupciones? Sobre todo porque en el STM32 parece que hay bastantes problemas.

Estoy usando STM32CubeMx/HAL.

0 votos

No todos los µC tienen DMA. Si usted puede usarlo, entonces genial, úsalo si necesito la velocidad.

0 votos

@HarrySvensson No sé si realmente necesito la velocidad, pero el DMA lo conseguí en pocas horas, mientras que las interrupciones las probé durante varias semanas (tiempo de pasatiempo libre). Pensé que lo mejor sería probar primero directamente (que funcionaba), que las interrupciones (no funcionaba bien), que el DMA (usando las interrupciones).

2 votos

¿Por qué no? Eso es una cuestión de opinión, que busca una conjetura en cuanto a la posible razón técnica, o de la misma manera demasiado amplia, y por lo tanto no es una pregunta que pertenece aquí. Por nombrar un ejemplo al azar, el DMA significará más latencia en la reclamación de los datos, sobre todo porque no se obtiene ningún beneficio real a menos que se permita recoger varios caracteres. A menudo eso puede estar bien, a veces no.

28voto

luapyad Puntos 2680

Aunque el DMA alivia a la CPU y, por tanto, puede reducir la latencia de otras aplicaciones basadas en interrupciones que se ejecutan en el mismo núcleo, hay costes asociados a él:

  • Sólo hay un cantidad limitada de canales DMA y hay limitaciones en la forma en que esos canales pueden interactuar con los diferentes periféricos. Otro periférico en el mismo canal puede ser más adecuado para el uso de DMA.

    Por ejemplo, si tienes una transferencia I2C masiva cada 5ms, esto parece un mejor candidato para DMA que un comando de depuración ocasional que llega a UART2.

  • Configuración y mantener la AMD es un coste por sí mismo. (Normalmente, la configuración de DMA se considera más compleja que la configuración de una transferencia normal por carácter impulsada por interrupción, debido a la gestión de la memoria, a que hay más periféricos implicados, a que DMA utiliza interrupciones por sí mismo y a la posibilidad de que necesites analizar los primeros caracteres fuera de DMA de todos modos, ver más abajo).

  • La DMA puede utilizar energía adicional ya que se trata de otro dominio del núcleo que hay que cronometrar. Por otro lado, puedes suspender la CPU mientras la transferencia DMA está en progreso, si el núcleo lo soporta.

  • La DMA requiere búferes de memoria para trabajar (a menos que estés haciendo DMA de periférico a periférico), por lo que hay algún coste de memoria asociado.

    (El coste de la memoria puede también estar ahí cuando se usan interrupciones por carácter, pero también puede yo mucho más pequeño o desaparecer del todo si los mensajes se interpretan enseguida dentro de la interrupción).

  • La DMA produce un latencia porque la CPU sólo recibe una notificación cuando la transferencia está completa/medio completa (ver las otras respuestas).

  • Excepto cuando se transmiten datos a/desde un búfer en anillo, se necesita saber de antemano cuántos datos que va a recibir/enviar.

    • Esto puede significar que es necesario procesar los primeros caracteres de un mensaje utilizando interrupciones por carácter: por ejemplo, cuando se interconecta con un XBee, primero se lee el tipo y el tamaño del paquete y luego se activa una transferencia DMA a un búfer asignado.

    • Para otros protocolos, esto puede no ser posible en absoluto, si sólo utilizan delimitadores de fin de mensaje: por ejemplo, los protocolos basados en texto que utilizan '\n' como delimitador. (A menos que el periférico DMA admita la coincidencia con un carácter).

Como puedes ver, hay que tener en cuenta muchas compensaciones. Algunas están relacionadas con las limitaciones del hardware (número de canales, conflictos con otros periféricos, coincidencia de caracteres), otras se basan en el protocolo utilizado (delimitadores, longitud conocida, búferes de memoria).

Para añadir algunas pruebas anecdóticas, me he enfrentado a todas estas compensaciones en un proyecto de hobby que utilizaba muchos periféricos diferentes con protocolos muy distintos. Había que hacer algunas concesiones, sobre todo basadas en la pregunta "¿cuántos datos voy a transferir y con qué frecuencia voy a hacerlo?". Esto te da esencialmente una estimación aproximada del impacto de una simple transferencia basada en interrupciones en la CPU. Así, di prioridad a la mencionada transferencia I2C cada 5ms sobre la transferencia UART cada pocos segundos que utilizaba el mismo canal DMA. Otra transferencia UART que ocurre más a menudo y con más datos, por otro lado, tiene prioridad sobre otra transferencia I2C que ocurre más raramente. Todo son compensaciones.

Por supuesto, el uso de DMA también tiene ventajas, pero eso no es lo que has pedido.

0 votos

Gracias por su detallada respuesta. MIDI será la parte más crítica así que supongo que DMA es adecuado para ello (aunque la velocidad es baja: 31250 baudios). Tengo suficientes canales DMA, más adelante voy a usar otro STM32 cuando use 4 USARTs. No necesito suspender la CPU, ya que tendrá alimentación USB de 5V, y necesito hacer procesamiento entre los mensajes (para procesar los mensajes en el bucle principal). Tengo un buffer de lectura de 256 bytes y de transmisión de 256 bytes. Puedo aumentarlo más tarde si es necesario. El STM32f103c8t6 tiene 20 KB de RAM, el eventual STM que usaré tiene 192 KB.

0 votos

Y me das una muy buena idea de cómo mejorar. Hasta ahora siempre leo 1 byte y compruebo continuamente cuando se recibe un mensaje completo (MIDI). Pero puedo leer el primer byte, y dependiendo de eso mayormente se sabe el tamaño y se puede pedir el resto. Esto me cuesta otro pequeño buffer pero esta bien.

0 votos

La lectura de bytes individuales con DMA es muy ineficiente. Para una menor latencia y una mayor eficiencia, sería favorable utilizar interrupciones por carácter hasta conocer el tamaño y luego cambiar a DMA.

11voto

GSerg Puntos 33571

El uso de DMA suele significar que ya no se produce una interrupción en cada carácter, sino sólo después de que se haya recibido (o transmitido) un "búfer lleno" de caracteres. Esto aumenta la latencia del procesamiento de esos caracteres: el primer carácter no se procesa hasta que se ha recibido el último carácter del búfer.

Esta latencia puede ser algo malo, especialmente en una aplicación sensible a la latencia como la MIDI, donde unos pocos ms aquí y allá pueden suponer graves problemas de reproducción en las actuaciones en directo.

0 votos

Lo que hago es recibir 1 byte a la vez (así que un buffer 'DMA' de 1 byte) y después de cada callback DMA de ese byte, almacenarlo en un buffer de anillo que manejo manualmente. En mi bucle principal pretendo comprobar si hay mensajes MIDI completos y procesarlos.

3 votos

El DMA se utiliza normalmente para obtener múltiples bytes, y sólo se interrumpe cuando se han recibido todos. Interrumpir después de un solo byte es normal cuando no usando DMA, así que me hace preguntarme: ¿qué sentido tiene la complicación extra de usar DMA para eso?

5 votos

@MichelKeijzers Entonces lo que se hace es más o menos lo mismo que se haría en implementaciones puramente basadas en interrupciones. Por lo tanto, no hay ningún beneficio en el uso de DMA en este caso y su problema original es probablemente no resuelto por el DMA, pero por su reescritura de su (ISR, configuración) de código.

8voto

duskwuff Puntos 1570

El DMA no es un sustituto de las interrupciones, sino que suelen utilizarse conjuntamente. Si estás usando DMA para enviar datos a través de una UART, por ejemplo, todavía necesitas una interrupción para decirte cuando el envío está completo.

0 votos

Es cierto, tal vez sólo en el STM32 el mecanismo de interrupción (no DMA puro) es un poco torpe en comparación con el DMA directamente.

2 votos

@duskwuff En realidad no; puedes hacer un sondeo para ver cuándo se hace el DMA, y bien podrías quieren porque una de las razones principales para utilizar DMA es no tener que molestarse con el puerto serie hasta que tu programa esté en un estado en el que pueda actuar sobre los datos recibidos. O para DMA saliente, puedes simplemente sondear para ver si es posible añadir más al buffer de envío.

1 votos

@MichelKeijzers: IDK el chip específico, pero por lo general la alternativa a DMA no es literalmente interrupciones, es programado-IO (donde se utiliza instrucciones de la CPU para leer / escribir datos desde / hacia un registro de E / S). En un manejador de interrupciones, típicamente harías una lectura, y luego tal vez otra en caso de que un carácter entrara mientras estabas leyendo la primera, especialmente si eso no disparará otra interrupción. O leer hasta que un búfer interno esté vacío, si existe tal búfer. Obviamente necesitas más interrupciones para PIO, y las configuras de forma diferente.

5voto

dchanson Puntos 29

El uso de DMA introduce algunas preguntas y desafíos interesantes más allá de todas las otras consideraciones del uso de periféricos UART. Te daré algunos ejemplos: Asume que tu uC está sentado en un bus RS485 (o lo que sea) con otros dispositivos. Hay muchos mensajes en el bus, algunos están destinados a tu uC, otros no. Además, supongamos que todos estos vecinos de bus hablan un protocolo de datos diferente, lo que implica que las longitudes de los mensajes son diferentes.

Algunas preguntas que sólo surgen cuando se utiliza el DMA son:

  • ¿cuándo interrumpo?
    • A los DMA sólo les gusta interrumpir cuando han transferido una cantidad preestablecida de datos.
    • ¿Qué hacer si nunca se reciben suficientes datos para activar una interrupción DMA?
  • ¿Qué pasa si sólo recibes un mensaje parcial cuando el DMA se interrumpe?
  • ¿Qué aspecto tienen sus topes RX? ¿Son lineales o circulares?
    • DMA puede ser un participante de búferes circulares rebelde en el sentido de que sólo obedece el límite de la dirección, pero no tiene ningún problema en pasar por encima de los otros punteros en el sistema de búferes circulares.

De todos modos, sólo es un elemento de reflexión.

0 votos

Gracias por estas consideraciones. Actualmente siempre recibo 1 byte y lo almaceno en un buffer de anillo, ya que efectivamente mis mensajes (MIDI) pueden tener diferentes longitudes y no sé cuál es la siguiente. En mi bucle principal compruebo si hay mensajes completos para procesarlos (y si están completos, los elimino del buffer de anillo). Así que siempre recibiré suficientes datos (a menos que me falten bytes, tengo que comprobarlo). Mi buffer de RX es sólo de 1 byte, pero lo copio a un buffer anular/circular. No he comprobado si está lleno (hay que añadirlo).

0 votos

No te preocupes. Estoy seguro de que tu aplicación estará bien programada. Como otros mencionaron, el DMA es genial, pero no es gratis del todo. Introduce consideraciones adicionales en el sistema que no existen si se puede prescindir de él.

0 votos

Bueno, espero, todavía soy un principiante.

3voto

guest101 Puntos 21

En el lado de la recepción (si no recuerdo mal), el DMA finaliza cuando coincide con un carácter o en el recuento de terminales. Algunos protocolos y muchas aplicaciones interactivas no encajan fácilmente en este modelo y es necesario manejar las cosas carácter por carácter. Las técnicas de DMA también pueden ser frágiles si el enlace de comunicaciones no es fiable, la pérdida de un solo carácter en el flujo puede estropear fácilmente su máquina de estado DMA.

0 votos

Efectivamente, recibo byte a byte y lo copio manualmente a un buffer de anillo para procesarlo después.

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