树莓派 Pico ADC 底层全解析:硬件架构、工作模式、寄存器与应用避坑
1.ADC 外设简介
RP2040 内置了一个逐次逼近型(SAR)ADC,该 ADC 使用独立的 48MHz 时钟,最大采样速率可达 500ksps(每秒 500,000 次采样),适合于中等速率的信号采集,其分辨率为 12 位,意味着它可以将模拟信号转换为 4096(2^12)个不同的数字值(该 ADC 的有效位数 ENOB 为 8.7,表示实际能达到的精度)。

RP2040 内置的 ADC 外设与 GPIO 的连接如下:

这里,有一个数字控制器专门负责管理 ADC 的操作,并提供了额外的功能:
- 单次采样模式或自由运行采样模式:ADC 可以配置为只执行一次采样(One-shot 单次模式),或者连续不断地进行采样(free-running capture mode 自由运行模式)
- 带有DMA接口的采样 FIFO:ADC 采样的数据会存储在一个 FIFO 缓冲区中,并且可以通过 DMA(直接存储器访问)接口将数据传输到系统内存中,减轻 CPU 的负担
- 节拍定时器:该定时器具有 16 位整数和 8 位小数的分辨率,用于设置自由运行模式下的采样速率,节拍定时器可以精确控制采样的时间间隔
- 轮询采样多个通道:在自由运行模式下,ADC 可以轮流对多个输入通道进行采样,而不仅限于单个通道,这在需要同时采集多个信号时非常有用
- 可选的右移至 8 位:在自由运行模式下,采样结果可以选择性地右移到 8 位,这样采样数据可以以字节(8 位)形式通过 DMA 传输到系统内存中的缓冲区,对于减少内存占用和处理字节数据更为方便
在使用 ADC 外设时,需要注意需要确保引脚的数字功能被禁用。这是通过设置引脚的 Pad Control 寄存器中的 IE 位(输入使能)为低电平(IE = 0)和 OD 位(开漏驱动)为高电平(OD = 1)来实现的。

此外,ADC 输入电压的最大值是由数字 IO 供电电压(IOVDD)决定的,而不是 ADC 供电电压(ADC_AVDD)。例如,如果 IOVDD 供电电压为 1.8V,那么即使 ADC_AVDD 供电电压为 3.3V,ADC 输入电压也不应超过 1.8V。否则,电压超过 IOVDD 会导致通过 ESD 保护二极管产生泄漏电流,可能会损坏芯片。

树莓派 Pico 的 ADC 引脚输入阻抗大约为 100KΩ,这个阻抗对于大多数应用来说是合适的,如果信号源阻抗高于 ADC 输入阻抗,可能导致信号衰减,降低测量精度。
前面我们提到,RP2040 内置了一个逐次逼近型(SAR)ADC,其结构框图如下:

SAR ADC 内部 DAC 单元是关键组成部分之一,的作用是将数字信号转换为模拟信号,用于与输入的模拟信号进行比较
SAR ADC 的工作过程可以概述如下:
- 逐位逼近:SAR ADC 通过逐次逼近算法进行模数转换,首先,它从最高有效位 MSB 开始,将该位设置为 1,然后通过内部 DAC 将此数字信号转换为模拟电压
- 比较器比较:然后,这个生成的模拟电压与输入的模拟信号进行比较,如果 DAC 生成的电压比输入的模拟信号高,SAR 会将该位清零;如果低,则保持为 1
- 继续逐位逼近:这个过程会依次进行,逐次决定每个位的值,直到所有位都确定下来
- 最终输出:在完成所有位的逐次逼近后,最终的数字值就代表了输入模拟信号的数字化结果
DAC单元在这个过程中不断地生成不同的电压值,并与输入信号进行比较,以逐步确定输入信号的数字值。因此,DAC 的精度和线性度对于 SAR ADC 的整体性能至关重要。在 RP2040 的 ADC 中,这个 DAC 单元是内置的,不需要外部的 DAC 模块来完成模数转换过程。
SAR ADC(逐次逼近寄存器模数转换器)是由数字控制器和模拟电路组合而成,该 ADC 需要一个 48MHz 的时钟(clk_adc),可以来自 USB PLL(锁相环)。采样一次需要 96 个时钟周期(96 × 1/48MHz)= 2 微秒,采样频率为 500ksps 的情况下。在启用 ADC 之前,必须正确设置时钟。

一旦为 ADC 模块提供了时钟并取消了其复位,通过将 CS 控制寄存器的 EN 位设置为 1,那么将启动 ADC 的模拟硬件的短暂内部上电序列;经过几个时钟周期后,CS 控制寄存器的 READY 位将变为高电平,表示 ADC 已准备好开始第一次转换。

ADC 可以随时通过清除 CS 控制寄存器的 EN 位来禁用,以节省电能,需要注意的是,ADC 的输入是电容性的,会在输入端内置 1pF 的电容,在 500ksps 的采样速率下,其有效阻抗也超过 100kΩ,对于直流测量,通常不需要缓冲。
2.ADC 工作模式
RP2040 的 ADC 可以选择两个工作模式:
- 单次采样模式:该模式适用于需要在特定时刻进行一次性模数转换的场景,启动一次转换后,ADC 会在 96 个时钟周期内完成采样并返回结果
- 自由运行采样模式:这种模式适用于需要连续采样的场景,例如实时数据采集,ADC 在完成一次转换后会自动开始下一次转换,除非特意设置延迟
2.1 单次采样模式
在单次采样模式下,通过将 CS.START_ONCE 数据位写入 1,可以立即启动一个新的模数转换过程。当转换开始时,CS.READY 数据位会变为低电平,表示当前正在进行转换。经过 96 个 clk_adc 时钟周期后,CS.READY 数据位会再次变为高电平,表明转换已经完成。

转换完成后,12 位的转换结果将会存储在 RESULT 寄存器中。

在开始转换之前,可以通过写入 CS.AINSEL 数据位来选择需要采样的 ADC 输入通道。AINSEL 的值为 0 到 3 时,对应选择 GPIO 26 到 29 的 ADC 输入通道;当 AINSEL 的值为 4 时,选择的是内部温度传感器。

需要注意的是,在切换 AINSEL 值时,不需要等待稳态时间,这意味着你可以在转换开始前任意切换输入通道,而不会对转换结果产生负面影响。
2.2 自由运行采样模式
在自由运行采样模式下,通过设置 CS.START_MANY 位位,ADC 将自动以固定的间隔启动新的转换。最新的转换结果始终保存在 RESULT 寄存器中。然而,如果需要通过中断(IRQ)或 DMA 进行采样数据的传输,则必须启用 ADC 的 FIFO。

通过调节 DIV 分频寄存器的 DIV.INT 和 DIV.FRAC 数据位,可以控制采样速率:

默认情况下(DIV = 0),新转换在前一个转换完成后立即开始,因此每 96 个时钟周期会产生一个新的采样数据。假设时钟频率为 48MHz,这将使 ADC 的采样速率达到 500k 样本每秒(ksps)。
如果将 DIV.INT 设置为某个正值 n,则 ADC 将在每 n + 1 个时钟周期触发一次,尽管如果当前正在进行转换,ADC 会忽略该触发信号,因此通常 n 应该大于或等于 96。例如,将 DIV.INT 设置为 47999 时,如果使用 48MHz 的时钟,ADC 将以 1k 样本每秒的速度运行。
定时器支持分数速率分频。当 DIV.FRAC 数据位设置为非零值时,ADC 将在 1 + INT + FRAC/256 个时钟周期平均启动一次新转换,并通过在 INT + 1 和 INT + 2 之间改变采样间隔来实现。
3.多输入采样
通过设置 CS 寄存器的 RROBIN 数据位可以进入多输入采样模式,使得 ADC 自动切换采样不同的输入通道,从而实现在自由运行模式下,自动轮流采集多个输入通道的数据,无需手动干预:

在 CS.RROBIN 数据位中,设置某个位为 1 就会让对应的输入通道被 ADC 自动采样。设置多个位为 1 时,ADC 会按照这些通道的顺序轮流采样;如果 CS.RROBIN 中的所有位都设置为 0,那么循环采样功能将被禁用,即 ADC 只会一直采样当前的 CS.AINSEL 指定的通道。
即使 AINSEL 的初始值不在 RROBIN 指定的通道中,ADC 仍然会从当前通道开始工作,并逐个采样 RROBIN 中设置的通道。例如 AINSEL 的初始值为 0,RROBIN 设置为 0x06(即只设置了第 1 和第 2 位),则 ADC 将按照以下顺序进行通道采样:
- 通道 0
- 通道 1
- 通道 2
- 通道 1
- 通道 2
- 通道 1……
并会一直按照这个顺序重复采样直到失能 CS.RROBIN 数据位。
4.采样接收 FIFO
在 RP2040 的 ADC 模块中,采样结果可以直接从 RESULT 寄存器读取,也可以存储在一个本地的接收 FIFO 缓冲区中,我们通过 FIFO 寄存器读出。

FIFO 操作由 FCS FIFO 控制寄存器寄存器控制:

其中,各个标志位含义如下:

4.1 FIFO 的使能和读取
当 FCS.EN 数据位被设置为 1 时,每次 ADC 转换的结果将被写入 FIFO,此时,我们可以:
- 软件轮询 FCS 寄存器的状态位,等待每个采样数据可用时进行读取
- 使用中断或 DMA 在收到 ADC 的 IRQ 中断信号或 DREQ DMA 请求信号后,从 FIFO 中读取采样数据
4.2 FIFO 的溢出
如果 FIFO 已满时又有新的转换结果到来,会设置 FCS.OVER 错误标志位,但 FIFO 中的现有数据不会被覆盖;这种情况下,后续的转换结果会丢失。
4.3 FIFO 数据写入格式
FCS 寄存器有两个位用于控制写入 FIFO 的数据格式:
FCS.SHIFT位:当设置为 1 时,FIFO 中的数据会被右移 4 位(FIFO 的 bits 7:0 对应转换结果的 bits 11:4)。这样可以方便 8 位 DMA 传输到字节缓冲区,以实现更深的捕获缓冲区,但会牺牲一些精度。FCS.ERR位:当设置为 1 时,FIFO 中每个值的 ERR 标志位都会被置位,表示发生了转换错误,此时我们应该尝试使用下一次采样得到的数据或增大转换时间。
需要注意的是,虽然 FIFO 数据发生了位移,但 FIFO.ERR 标志位会保持在原来的位置,仍然指示该样本是否发生了转换错误;换句话说,即使开启了 FCS.SHIFT 来缩小 FIFO 数据宽度,FIFO.ERR 标志位依然会准确地指示该样本是否经历了转换错误,不会因为数据位移而发生改变。
这些错误表明在规定的时间内,一个或多个位的比较未能完成。通常,这是由比较器亚稳态引起的,即当输入信号接近比较器阈值时,转换所需的时间更长。
4.4 FIFO 与 DMA 配合使用
RP2040 的 DMA 控制器可以通过读取 ADC 样本 FIFO 寄存器来获取 ADC 样本。这一过程由 ADC_DREQ 系统数据请求信号控制。在使用 DMA 传输 ADC 数据时,需要注意以下几点:
- 启用 FIFO (FCS.EN):FIFO 必须启用,以便将 ADC 转换结果写入 FIFO。默认情况下,FIFO 是禁用的,以防止在执行一次性转换时意外填充 FIFO。
- 启用 ADC 的DMA请求 (FCS.DREQ_EN):必须启用 ADC 的 DMA 请求信号 DREQ,以便 DMA 可以根据 ADC 的请求信号从 FIFO 读取数据
- 选择 DMA 通道的 DREQ_ADC 数据请求信号:使用的 DMA 通道必须选择 DREQ_ADC 数据请求信号,以确保 DMA 可以与 ADC 的数据请求信号同步工作
- 设置 DREQ 断言阈值 (FCS.THRESH):DREQ 断言阈值应设置为 1,以便当 FIFO 中有一个样本时,DMA 就开始传输。需要注意的是,这也是 IRQ 断言的阈值,因此在非 DMA 使用场景中,可能会需要更高的值来减少中断频率
- 8 位 DMA 传输的配置:如果 DMA 传输大小设置为 8 位(即将数据传输到内存中的字节数组),则必须启用 FCS.SHIFT,以预先将 FIFO 样本右移变为一个字节的数据
- 多通道采样配置:如果需要采样多个输入通道,可以在
CS.RROBIN中设置对应通道的 5 位掩码(包括 4 个外部输入通道和温度传感器),此外,CS.AINSEL必须选择第一个采样通道 - 配置 ADC 采样率:在启动 ADC 之前,应该先配置好 ADC 采样率
配置好 ADC 之后,应先启动 DMA 通道,然后启动 ADC 转换(通过设置 CS.START_MANY 数据位)。DMA 完成后,可以停止 ADC 或迅速启动新的 DMA 传输。清除 CS.START_MANY 数据位 以停止 ADC 之后,软件应轮询 CS.READY 数据位确保最后一次转换已完成,并清空 FIFO 中的任何多余的采样数据。
4.5 FIFO 与中断配合使用
当 FIFO 中的采样数量达到可配置的阈值 FCS.THRESH 时,可以生成中断。但需要注意的是,我们需要先使能通过 INTE 寄存器的 FIFO 数据位使能中断:

中断状态可以从 INTS 寄存器中读取。通过将 FIFO 中的采样数量降到低于 FCS.THRESH 设置的采样阈值来清除中断:


我们可以通过 INTF 寄存器手动触发 ADC 中断,设置位为 1 则强制触发中断,而不需要等待 FIFO 中的采样数量达到阈值:

我们可以通过 INTS 寄存器来读取中断屏蔽和强制操作后的中断触发情况:

5.ADC 的有效精度
这里,数据手册中还提到了对 RP2040 的 ADC 精度进行测试的内容,测量了其有效位数(ENOB),简单来说,对其 ADC 的 ENOB(有效位数)、INL(积分非线性)和 DNL(微分非线性)三个参数指标进行测试,具体内容这里并不进行详细解读,需要的同学可自行查看。

6.内置温度传感器
RP2040 微控制器的温度传感器通过测量一个偏置双极型二极管的基极-发射极电压(Vbe)来确定温度。该传感器连接到第五个 ADC 通道(AINSEL=4)。通常情况下,Vbe 在 27°C 时约为 0.706V,温度与电压的关系如下:
T = 27 - (ADC_voltage - 0.706) / 0.001721
这里,ADC_voltage 代表基极-发射极电压,它随温度变化而改变,每升高 1°C,Vbe 电压降低约 1.721mV。
需要注意的是,温度传感器对参考电压的误差非常敏感。例如:参考电压降低 1%(如从 3.3V 降到 3.267V),同样的 ADC 值 891 对应的温度会变为 24.3°C。仅 1% 的参考电压变化会导致超过 4°C 的温度误差。因此,为提高内部温度传感器的精度,建议考虑使用外部参考电压。
在使用温度传感器之前,需要先通过 CS.TS_EN 数据位使能其偏置电源,这会增加 ADC_AVDD 上约 40μA 的电流消耗。
RP2040 的温度传感器适合基本的温度测量,但在高精度场合需要考虑参考电压的稳定性,并可能需要进行校准以补偿 Vbe 和 Vbe 斜率的变化。

RP2040 内置了一个逐次逼近型(SAR)ADC,该 ADC 使用独立的 48MHz 时钟,最大采样速率可达 500ksps(每秒 500,000 次采样),适合于中等速率的信号采集,其分辨率为 12 位,意味着它可以将模拟信号转换为 4096(2^12)个不同的数字值(该 ADC 的有效位数 ENOB 为 8.7,表示实际能达到的精度)。
浙公网安备 33010602011771号