viernes, 9 de febrero de 2018

ADC Rápido en Arduino Leonardo

Este artículo fué publicado previamente, en inglés, en el blog R6500.

El problema

Es posible usar la función Arduino analogRead para leer un valor analógico en uno de los pines habilitados para ello. En la placa Arduino Leonardo hay 12 entradas analógicas. Las típicas entradas Arduino estándar de A0 a A5 y las seis líneas adicionales A6 a A11 que corresponden a D4, D6, D8, D9, D10 y D12.
Los ADC contenidos en los MCU de Atmega, utilizadas en las placas Arduino, son convertidores de 10 bits. Para hacer una conversión, la función analogRead tarda 100us. Se supone que el MCU necesita ese tiempo para dar una conversión de precisión de 10 bits. Pero 100us, para algunas aplicaciones, puede ser demasiado tiempo. Limita, de hecho, la frecuencia máxima de muestreo analógico a 10 kHz y esto no tiene en cuenta el tiempo necesario para procesar los datos leídos.

Se puede hacer mejor. Se puede hacer más rápido. Pero, como es normal en la vida, debe haber algunas contras para cada pro. Por tanto, si quiere hacer conversiones más rápidas, necesitas saber qué estás perdiendo con ello.

El convertidor del Atmega 32u4

Sospecho que otros Arduinos basados en ATmega incluyen un ADC similar, pero no estoy seguro. El ADC usa un reloj interno que se obtiene del reloj del sistema (16MHz en Arduino Leonardo)  dividido por un factor entre 2 y 128 usando un registro de configuración específico.

En Arduino Leonardo, el divisor se establece en el valor máximo de 128, por lo que, a una frecuencia de reloj de la CPU de 16 MHz, obtenemos una frecuencia de reloj del ADC de 125 kHz.
Para obtener el tiempo necesario para realizar una conversión a partir de la frecuencia de reloj del ADC, podemos consultar una tabla en la hoja de datos ATmega 42u4.

Número de ciclos para realizar una conversión
Hay tres tipos de conversión: Primera conversión, Conversiones normales y Conversión activada automáticamente. Los tipos que se aplican a analogRead son los dos primeros, pero el primero solo se aplica a la primera conversión, por lo que podemos usar la columna central (Conversión Normal) como caso típico. 

El ADC necesita hacer dos cosas para proporcionar una conversión: Sample and Hold y SAR Conversion. En la tabla, encontramos que esos necesitan 1.5 y 13 ciclos para un total de 14.4 ciclos. Como la frecuencia de ADC es de 125 kHz, el tiempo total de ADC es de 14.5 / 125 kHz = 116 us. De ahí viene el tiempo aproximado de 100us de analogRead.

La hoja de datos del MCU establece que necesitamos una frecuencia de ADC entre 50 kHz y 200 kHz para obtener la resolución máxima de 10 bits. Con una frecuencia de 200kHz podríamos acortar el tiempo total de ADC a 72,5us. Lamentablemente, la opción del divisor de reloj próxima a 128 es 64, por lo tanto, no podemos seleccionar 200 kHz. Solo podemos seleccionar 125kHz, 250kHz ... Cualquier opción más allá de 125kHz, usando un reloj maestro de 16MHz, va más allá de las recomendaciones de Atmel para la MCU.

Al separar las dos acciones que realiza el ADC, obtenemos un tiempo de muestreo de 12us y un tiempo de conversión de SAR de 104us. Si aumentamos la frecuencia de ADC podríamos acortar esos tiempos. Sabemos que no obtendremos la resolución máxima pero, ¿cuáles son exactamente los efectos secundarios?

Sample and Hold

Para comprender el sistema de Sample and Hold podemos usar una de las figuras en la hoja de datos de ATmega 32u4:

El circuito Sample and Hold (S & H) está compuesto por un interruptor, una resistencia y un condensador. Al comienzo de la conversión, el interruptor se cierra durante el tiempo de captura  (1,5 ciclos de reloj de ADC). Después de ello, el interruptor se abre y el circuito ADC SAR realiza la conversión real. El circuito S & H es importante porque la señal no debería cambiar durante la conversión SAR. Ello está garantizado por el hecho de que el interruptor está abierto durante la conversión.

Un punto fundamental acerca de los circuitos S & H es que el condensador debe cargarse al voltaje de entrada, durante el tiempo de captura, antes de que comience la conversión. Como se trata de un circuito RC, en teoría, el voltaje del condensador nunca llegará a la entrada. En la práctica, solo necesitamos acercarnos al voltaje de entrada que se necesita para la resolución del convertidor. Para un ADC de 10 bits, para obtener un error insignificante necesitamos llegar a 1/2^11 del valor de referencia del ADC que normalmente es de 5V para las placas Arduino.

La carga de RC, suponiendo que el peor caso de condensador arrancando en cero, será modelado por:

En el peor de los casos, el voltaje de entrada será de 5V y, para cumplir con la precisión de 10 bits requerida, el valor del condensador del valor de entrada debe llegar a 1/2 ^ 11 del valor de entrada.

De ello se obtiene:

Operando con un reloj del ADC de 125kHz sabemos que el tiempo de captura es 12us, por lo que la constante de tiempo debe ser 1,57us o menos. Como la capacidad es 14pF, la resistencia total debe estar por debajo de 112 kOhm. Debido a que la resistencia interna de ADC puede llegar hasta 100k, queda limitada la resistencia externa a aproximadamente 12 kOhm. Esto es consistente con el hecho de que la hoja de datos de MCU recomienda resistencias externas al ADC de 10 kOhm o menos.

La fórmula anterior es bastante importante. Cuando se usa el ADC. A una frecuencia de sistema de 16MHz, el tiempo de captura no puede ser mayor que 12us, por lo que no se debe usar una resistencia externa total al ADC mayor de 12 kOhm. Usar una mayor resistencia podría limitar la resolución de ADC disminuyendo la cantidad efectiva de bits que obtiene del ADC.

Si, por ejemplo, solo se necesitan 8 bits porque estamos descartando los 4 bits inferiores que resultan de la conversión, solo necesitamos tener una constante de tiempo de 5,4 us (tiempo de muestreo dividido por ln (9)) así que, con la misma capacidad del ADC de 14pF sólo necesitararemos una resistencia total por debajo de 386k Ohm. Teniendo en cuenta la resistencia ADC máxima de 100k interna, solo necesita garantizar una resistencia externa máxima de 286k Ohm.


Conversión SAR

El MCU ATmega 32u4 usa un Registro de Aproximación Succesiva (SAR) para realizar la conversión. Este es el tipo más común de convertidor que se puede encontrar en los MCU. Estos convertidores obtienen un bit en cada ciclo de reloj. Por tanto, para obtener un valor de 10 bits de resolución, necesitamos 10 ciclos de reloj. De la tabla que se encuentra en la hoja de datos, sabemos que la conversión real tarda 13 ciclos. Los 3 ciclos adicionales son probablemente para tareas de sincronización.

El aumento de la frecuencia del reloj durante la operación de conversión afectará la resolución del ADC, pero el efecto no es fácil de modelar . Sin embargo, puede medirse. Afortunadamente, alguien ha hecho estas mediciones.

En el sitio web de Open Music Labs puedes encontrar estos dos artículos:



Son una lectura bastante interesante y explican más detalles sobre la operación S & H. Los enlaces se aplican al ATmega 328p, pero no creo que el ADC ATmega 32u4 sea muy diferente.

El resultado es que al aumentar la frecuencia de ADC se reduce el número equivalente de bits (ENOB) de la conversión. Observese que a la frecuencia mínima de 125 kHz, la ENOB no es de 10 bits, sino algo superior a 9. Además, a 250 y 500 kHz, la ENOB también es más de 9, pero bajando. A 1MHz, la ENOB es más de 8. Para frecuencias mayores que eso, la ENOB cae por debajo de 8 bits.

Finalmente, podemos encontrar los problemas potenciales de utilizar una frecuencia de ADC mayor:
  • La resolución (número de bits) podría estar limitada por el S & H

  • La resolución (número de bits) estará limitada durante la conversión
La cantidad de bits de un ADC es un número entero, pero el Número Equivalente de Bits (ENOB) no lo es. A 125 kHz, si el S & H no es el factor limitante, se obtendrán aproximadamente 9,5 bits de datos. Es decir, la relación entre el valor máximo que puede convertir y el ruido de conversión se limitará a una relación de 2 ^ 9,5. Si no se necesitan más de 9 bits de resolución real, es posible aumentar la frecuencia de reloj del ADC hasta 500 kHz, pero debe verificarse que el S & H también será capaz de mantener esa velocidad para el valores de resistencia externa del ADC. Para una operación de 8 bits, se puede alcanzar un reloj 1MHz. Eso es ocho veces la velocidad de conversión original.

Programa ejemplo

Para cambiar el reloj del ADC, se ha de cambiar el Registro de control y estado ADC A (ADCSRA).


Los 3 bits inferiores de este registro determinan el divisor utilizado para obtener el reloj ADC a partir de la frecuencia del reloj principal del MCU.

  
Para 111 obtenemos un preescalador 128 que corresponde a la frecuencia Arduino de 125 kHz.
Para 110 obtenemos un divisor 64 que obtiene un reloj de 250 kHz. Para 101 obtenemos 500kHz y para 100 obtenemos 1MHz.

El siguiente programa de ejemplo hace 4 conversiones en secuencia. La primera con el valor por defecto de 125kHz, la segunda a 250kHz, la tercera a 500kHz y la última a 1MHz.


El programa también alterna el pin 3 de Arduino antes y después de cada llamada a analogRead para que se pueda medir el tiempo total asociado a esta función.





A partir de las medidas, podemos ver cómo el tiempo de ejecución de la función analogRead se reduce a la mitad en cada llamada a medida que se cambia el registro ADCSRA para obtener mayores frecuencias ADC.

Afortunadamente, la función analogRead no modifica el registro ADCSRA. Si ese fuera el caso, no podríamos modificar la velocidad del ADC sin crear una nueva función analogRead.


Código en Github (11/02/2018)

El código está ahora disponible en Github:

https://github.com/R6500/Leonardo/blob/master/FastAdcTest.ino

 

No hay comentarios:

Publicar un comentario