¿Por qué no usar siempre DMA en lugar de interrupciones con UART en STM32? [cerrado]

8

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

Sin embargo, esta noche utilizando DMA funcionó bastante rápido.

Dado que, en la medida en que leo, DMA es más rápido y alivia la CPU, ¿por qué no usar siempre DMA en lugar de interrupciones? Sobre todo porque en el STM32 parece haber algunos problemas.

Estoy usando STM32CubeMx / HAL.

    
pregunta Michel Keijzers

6 respuestas

22

Si bien DMA alivia la CPU y, por lo tanto, puede reducir la latencia de otras aplicaciones controladas por interrupciones que se ejecutan en el mismo núcleo, existen costos asociados:

  • Solo hay una cantidad limitada de canales DMA y existen limitaciones sobre cómo estos 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 tiene una transferencia masiva de I2C cada 5 ms, esto parece ser un mejor candidato para DMA que un comando de depuración ocasional que llega a UART2.

  • Configurar y mantener DMA es un costo por sí solo. (Normalmente, la configuración de DMA se considera más compleja que la configuración de la transferencia normal basada en interrupciones por carácter, debido a la administración de la memoria, a la mayoría de los periféricos involucrados, a la DMA que utiliza interrupciones y la posibilidad de que necesite analizar los primeros caracteres fuera de DMA). De todos modos, ver más abajo.)

  • DMA puede usar potencia adicional , ya que es otro dominio del núcleo que necesita ser cronometrado. Por otro lado, puede suspender la CPU mientras la transferencia DMA está en curso, si el núcleo lo admite.

  • DMA requiere búferes de memoria para trabajar (a menos que esté haciendo DMA de periférico a periférico), por lo que hay un costo de memoria asociado.

    (El costo de la memoria puede también está presente cuando se usan interrupciones por carácter, pero también puede ser mucho menor o desaparecer si los mensajes se interpretan de inmediato dentro de la interrupción).

  • DMA produce una latencia porque la CPU solo recibe una notificación cuando la transferencia está completa / la mitad está completa (consulte las otras respuestas).

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

    • Esto puede significar que es necesario procesar los primeros caracteres de un mensaje utilizando interrupciones por carácter: por ejemplo, al interactuar con un XBee, primero debe leer el tipo y tamaño de paquete y luego activar una transferencia DMA en un búfer asignado.

    • Para otros protocolos, esto puede no ser posible si solo usan delimitadores de fin de mensaje: por ejemplo, protocolos basados en texto que usan '\n' como delimitador. (A menos que el periférico DMA admita la coincidencia en un personaje).

Como puede ver, hay muchas compensaciones que considerar aquí. Algunos están relacionados con las limitaciones de hardware (cantidad de canales, conflictos con otros periféricos, coincidencia con los caracteres), otros se basan en el protocolo utilizado (delimitadores, longitud conocida, búferes de memoria).

Para agregar algunas pruebas anecdóticas, me he enfrentado a todas estas concesiones en un proyecto de hobby que usaba muchos periféricos diferentes con protocolos muy diferentes. Hubo algunas concesiones que hacer, en su mayoría basadas en la pregunta "¿Cuántos datos estoy transfiriendo y con qué frecuencia voy a hacer eso?". Básicamente, esto le proporciona una estimación aproximada del impacto de la simple transferencia controlada por interrupciones en la CPU. Por lo tanto, le di prioridad a la transferencia I2C antes mencionada cada 5 ms sobre la transferencia UART cada pocos segundos que utilizaron el mismo canal DMA. Otra transferencia de UART que ocurre con más frecuencia y con más datos, por otro lado, tiene prioridad sobre otra transferencia I2C, lo que ocurre con menos frecuencia. Es todas las compensaciones.

Por supuesto, usar DMA también tiene ventajas, pero eso no es lo que pediste.

    
respondido por el Jonas Schäfer
9

El uso de DMA generalmente significa que ya no está tomando una interrupción en cada carácter, sino que solo después de haber 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 después de que se haya recibido el último carácter en el búfer.

Esta latencia puede ser algo malo, especialmente en una aplicación sensible a la latencia, como MIDI, donde unos pocos ms aquí y allá pueden agregar serios problemas de jugabilidad para las presentaciones en vivo.

    
respondido por el Dave Tweed
8

DMA no es un sustituto de las interrupciones, ¡se suelen utilizar juntas! Si está utilizando DMA para enviar datos a través de un UART, por ejemplo, aún necesita una interrupción para avisarle cuando se complete el envío.

    
respondido por el duskwuff
5

El uso de DMA presenta algunas preguntas y desafíos interesantes más allá de todas las otras consideraciones del uso de periféricos UART. Te voy a dar algunos ejemplos: Supongamos que su unidad de control de voz se encuentra en un bus RS485 (o lo que sea) con otros dispositivos. Hay muchos mensajes en el autobús, algunos están destinados a su unidad de control de voz, otros no. Además, suponga 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 solo surgen cuando se usa DMA son:

  • ¿Cuándo interrumpo?
    • A los DMA solo les gusta interrumpir cuando transfieren una cantidad predeterminada de datos.
    • ¿Qué debe hacer si nunca recibe datos suficientes para desencadenar una interrupción DMA?
  • ¿Qué sucede si solo recibe un mensaje parcial cuando se interrumpe el DMA?
  • ¿Cómo son tus buffers RX? ¿Son lineales o circulares?
    • DMA puede ser un participante de búfer circular ingobernable en el sentido de que solo obedece al límite de la dirección, pero no tiene problemas para pasar los otros punteros en el sistema de búfer circular.

De todos modos, solo es algo para pensar.

    
respondido por el pgvoorhees
3

En el lado de recepción (como recuerdo) DMA termina en una coincidencia de caracteres o en el recuento de terminales. Algunos protocolos y muchas aplicaciones interactivas no encajan fácilmente en este modelo y realmente necesita 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 confiable, perder un solo carácter en el flujo puede desordenar fácilmente su máquina de estados DMA.

    
respondido por el Dean Franks
1

He usado el STM32CubeMx / HAL en un par de proyectos ahora y he encontrado que el software de manejo de UART que genera tiene deficiencias definidas en el lado de recepción.

En la transmisión, normalmente deseará enviar un bloque de datos o una línea de texto. En este caso, usted sabe por adelantado cuánto tiempo dura la transferencia de datos y, por lo tanto, el uso de DMA es una solución obvia. Recibes una interrupción una vez que se completa la transferencia y puedes usar la función de devolución de llamada de UART TX para indicar a tu código principal que la transmisión está completa y puedes enviar otro bloque de datos.

Cuando se trata de la recepción de datos, las funciones proporcionadas por ST suponen que usted sabe cuántos caracteres le dará el dispositivo de envío antes de que comience a enviar. Normalmente esto no se sabe. La funcionalidad de interrupción coloca los datos recibidos en un búfer y solo indica que hay datos disponibles cuando se ha recibido el número de caracteres predefinido. Si intenta utilizar la DMA o la funcionalidad de interrupción para recibir datos mediante la configuración de transferencias secuenciales de un solo carácter, el tiempo de configuración para cada uno de ellos significará que perderá los caracteres a una velocidad distinta a la velocidad de datos más lenta comenzar a perder datos dependerá de la velocidad de reloj de su procesador) y cargará el procesador excesivamente, sin dejar ciclos de instrucciones para ningún otro procesamiento

Para solucionar esto, escribí mi propia función de controlador de interrupciones que almacena los datos en un pequeño búfer circular local y establece un conteo que se lee con el código principal (un semáforo de conteo RTOS) para indicar que los datos están listos . El código principal puede luego recopilar los datos de este búfer en su tiempo libre, no importa si hay algún retraso en la recopilación de los datos, siempre que el búfer local no se desborde antes de que se recopilen los datos.

    
respondido por el uɐɪ

Lea otras preguntas en las etiquetas