Módulo 2.3

Periféricos Analógicos: ADC

Conversión analógico-digital con el SAADC del nRF

Santi Scagliusi, PhD

Comenzar arrow_downward
conversion_path
SAADC
Aproximaciones sucesivas
tune
Resolución
8, 10, 12, 14 bits
swap_horiz
Modos
Single-ended, Diferencial
code
Zephyr API
adc_read, devicetree

Qué es un ADC

El mundo real es analógico; los microprocesadores son digitales.

help Por qué necesitamos un ADC

Los sensores miden magnitudes físicas (temperatura, luz, presión, voltaje) y generan señales analógicas continuas. El microcontrolador solo entiende valores digitales discretos.

thermostat
Temperatura
light_mode
Luz
speed
Presión
lightbulb
ADC = Analog-to-Digital Converter
Convierte un voltaje analógico continuo en un número digital que el procesador puede usar en cálculos.

Proceso de conversión

Señal Analógica ADC Señal Digital
Continuo
Muestras
Discreto

SAADC: Successive Approximation ADC

El nRF utiliza un ADC de aproximaciones sucesivas: una búsqueda binaria del voltaje.

search Cómo funciona: Búsqueda binaria

Imagina que tienes que adivinar un número del 0 al 255. En lugar de probar uno por uno, preguntas: "¿Es mayor que 128?" y divides el rango a la mitad en cada pregunta.

Paso 0/8
sensors
Voltaje de entrada (Vin): ? (valor a descubrir)

speed Especificaciones del SAADC

Tasa máxima de muestreo 200 ksps
Resoluciones disponibles 8, 10, 12, 14 bits
Canales analógicos 8 (AIN0-AIN7)
Referencia interna 0.6V
bolt
Ventaja del SAR ADC: Buen balance entre velocidad, precisión y consumo de energía. Ideal para aplicaciones embebidas de bajo consumo.

Muestreo y Tiempos

El teorema de Nyquist y los tiempos críticos en la conversión ADC.

Teorema de Nyquist
fsample >= 2 x fmax
La frecuencia de muestreo debe ser al menos el doble de la frecuencia máxima de la señal

Ejemplo práctico

Si quieres medir una señal de audio de hasta 20 kHz:

fsample >= 2 x 20 kHz = 40 kHz mínimo
En la práctica se usa 44.1 kHz (CD) o 48 kHz para tener margen
warning
Aliasing: Si muestreas por debajo de Nyquist, aparecen frecuencias fantasma que distorsionan la señal. No hay forma de recuperar la información perdida.

Tiempos de conversión

download
Tiempo de adquisición (tACQ)
El condensador interno se carga al voltaje de entrada
arrow_downward
calculate
Tiempo de conversión (tCONV)
El SAR realiza las N comparaciones
Tiempo total por muestra:
ttotal = tACQ + tCONV
Opciones de tACQ en nRF
3 us
5 us
10 us
15 us
20 us
40 us
...
Default
Mayor tACQ = mejor precisión con fuentes de alta impedancia

Resolución del ADC

Más bits = mayor granularidad, pero también mayor tiempo de conversión.

Resolucion Niveles LSB (con Vref=0.6V) Velocidad Uso típico
8 bits 256 2.34 mV Más rápido Detección simple (batería baja)
10 bits 1,024 0.59 mV Rápido Sensores básicos
12 bits 4,096 0.15 mV Medio Mediciones de precisión
14 bits 16,384 0.037 mV Más lento Alta precisión (instrumentación)

Comparación visual de resoluciones

8 bits 256 niveles
10 bits 1,024 niveles
12 bits 4,096 niveles
14 bits 16,384 niveles
Resolución en voltaje (LSB)
LSB = Vref / 2N
info
LSB (Least Significant Bit) es el cambio mínimo de voltaje que el ADC puede detectar. Un LSB de 0.15 mV significa que cambios menores a eso no se reflejan en la salida digital.

Modos de Entrada

Single-ended para señales simples, diferencial para rechazar ruido.

input

Single-ended

Mide el voltaje entre el pin de entrada y GND.

Sensor ADC AINx GND
check_circle Simple de usar
check_circle Solo necesita 1 pin
cancel Sensible al ruido en GND
swap_horiz

Diferencial

Mide la diferencia entre dos pines. El ruido común se cancela.

Sensor ADC AIN+ AIN- ruido cancelado
check_circle Rechaza ruido en modo común
check_circle Mayor precisión
cancel Requiere 2 pines
lightbulb
Cuándo usar diferencial: Sensores con cables largos, entornos con ruido electromagnético (motores, fuentes switching), o cuando necesitas máxima precisión. Ejemplos: termopares, celdas de carga, sensores de puente de Wheatstone.

Ganancia y Referencia

Ajusta el rango de entrada para maximizar la resolución efectiva.

tune Opciones de ganancia

La ganancia amplifica (o atenúa) la señal de entrada antes de la conversión.

1/6
0.167x
1/5
0.2x
1/4
0.25x
1/3
0.33x
1/2
0.5x
1
1x
2
2x
4
4x

straighten Referencias de voltaje

Interna
Precisión, no requiere componentes externos
0.6V
VDD/4
Ratiométrica (varía con VDD)
~0.825V

Cálculo del rango de entrada

Rango = +/- Vref / Ganancia
Ejemplo con Ref=0.6V, Gain=1/6:
Rango = +/- 0.6V / (1/6) = +/- 0.6V x 6 = +/- 3.6V
Ejemplo con Ref=0.6V, Gain=4:
Rango = +/- 0.6V / 4 = +/- 0.15V
Útil para señales muy pequeñas
warning
Atención: Si la señal de entrada excede el rango calculado, la lectura se saturará en el valor máximo o mínimo. Asegúrate de conocer el rango de tu sensor.

APIs Disponibles

Dos opciones: Zephyr ADC API (portable) o nrfx SAADC (avanzado).

widgets
Zephyr ADC API
Recomendado para la mayoría de casos
check_circle Portable entre diferentes SoCs
check_circle Configuración via Devicetree
check_circle API simple y bien documentada
check_circle Funciones de conversión a mV
#include <zephyr/drivers/adc.h>
memory
nrfx SAADC Driver
Para casos avanzados
check_circle Acceso a todas las funciones del HW
check_circle Integración con PPI/DPPI
check_circle Muestreo activado por hardware
warning Solo para nRF (no portable)
#include <nrfx_saadc.h>
lightbulb
Recomendación: Usa la Zephyr ADC API para proyectos nuevos. Solo necesitas nrfx si requieres muestreo continuo de alta velocidad disparado por hardware (ej: sincronizado con PWM via PPI).

Ejemplo con Zephyr API

Configuración Devicetree para el canal ADC.

boards/nrf52840dk_nrf52840.overlay
/ {
zephyr,user {
io-channels = <&adc 0>;
};
};
&adc {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
/* Canal 0 en pin AIN0 */
channel@0 {
reg = <0>;
zephyr,gain = "ADC_GAIN_1_6";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,input-positive = <NRF_SAADC_AIN0>;
zephyr,resolution = <12>;
};
};
info
ADC_GAIN_1_6 con referencia interna 0.6V permite medir hasta 3.6V (el rango completo de un GPIO).
Propiedades clave
zephyr,gain ADC_GAIN_1_6
zephyr,reference ADC_REF_INTERNAL
zephyr,resolution 12 bits

Código C para lectura ADC

Implementación completa en main.c

src/main.c
#include <zephyr/drivers/adc.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(adc_sample, LOG_LEVEL_INF);
/* Obtener especificacion del canal desde DT */
static const struct adc_dt_spec adc_channel =
ADC_DT_SPEC_GET(DT_PATH(zephyr_user));
int main(void) {
int16_t sample_buffer;
int err;
if (!adc_is_ready_dt(&adc_channel)) {
LOG_ERR("ADC not ready"); return -1;
}
adc_channel_setup_dt(&adc_channel);
struct adc_sequence sequence = {
.buffer = &sample_buffer, .buffer_size = sizeof(sample_buffer),
};
adc_sequence_init_dt(&adc_channel, &sequence);
/* Loop de lectura */
while (1) {
err = adc_read(adc_channel.dev, &sequence);
int32_t mv = sample_buffer;
adc_raw_to_millivolts_dt(&adc_channel, &mv);
LOG_INF("Voltage: %d mV", mv);
k_msleep(1000);
}
}

Flujo de trabajo del código

Secuencia de llamadas para lectura ADC con Zephyr.

1
ADC_DT_SPEC_GET
Obtener configuración desde Devicetree
2
adc_channel_setup_dt
Configurar el hardware del canal
3
adc_read
Leer valor raw del ADC
4
adc_raw_to_millivolts_dt
Convertir a milivoltios
check_circle
Ventaja del API de Zephyr: La macro ADC_DT_SPEC_GET extrae automaticamente toda la configuracion (ganancia, referencia, resolucion) del devicetree, simplificando el codigo C.

Resumen del Módulo

Conceptos clave sobre el ADC en sistemas embebidos NRF.

conversion_path

SAADC

ADC de aproximaciones sucesivas con busqueda binaria. Balance ideal entre velocidad, precision y consumo.

tune

Configuración

Resolucion (8-14 bits), ganancia (1/6 a 4x), y referencia (0.6V interna) determinan rango y precision.

code

Zephyr API

ADC_DT_SPEC_GET para config, adc_read para lectura, adc_raw_to_millivolts_dt para conversion.

tips_and_updates

"Elige la resolución mínima que necesites y la ganancia que maximice tu rango efectivo."

Más bits no siempre es mejor: considera el ruido del sistema y la velocidad requerida.

Referencia Rápida

Fórmulas y configuración típica para consulta.

Fórmulas importantes
fsample >= 2 x fmax (Nyquist)
LSB = Vref / 2N
Rango = +/- Vref / Ganancia
Configuración típica
Referencia ADC_REF_INTERNAL (0.6V)
Ganancia ADC_GAIN_1_6
Rango resultante 0 - 3.6V