CB2201 ADC应用指南
1. 了解CB2201中的ADC
CB2201开发板上有一个16通道的ADC,其中连接到YoC接口上的通道有14个,这14个通道在开发板上的位置如下:
*注意
在使用ADC个通道的时候,一定要注意与这些通道引脚复用的功能。比如:CH14 和CH15 通道复用的是IIC 功能。最需要的注意的是:CH2 和CH3 通道复用的是CSI 程序默认的printf 输出串口,如果使用了CH2 和CH3 通道将导致默认的printf 没有任何输出。*
用户可使用3种模式操作ADC
- 单通道单次转换模式
- 单通道多次转换模式
- 多通道扫描转换模式
1.ADC寄存器说明
寄存器名 | 地址 | 宽度 | 说明 | 复位默认值 |
---|---|---|---|---|
ADC_CR | 0x6000 | 11 | ADC控制寄存器 | 0x0001 |
ADC_DR | 0x6004 | 12 | ADC数据寄存器 | 0x0000 |
ADC_SR | 0x6008 | 9 | ADC状态寄存器 | 0x0000 |
ADC_CMPR | 0x600C | 22 | ADC比较寄存器 | 0x0000 |
ADC_IE | 0x6010 | 3 | ADC中断使能寄存器 | 0x0000 |
ADC_IFLG | 0x6014 | 3 | ADC中断状态寄存器 | 0x0000 |
ADC_STC | 0x6018 | 1 | ADC启动寄存器 | 0x0000 |
ADC_SAMSEL | 0x601C | 1 | ADC采样模式选择寄存器 | 0x0001 |
ADC_DMACR | 0x6020 | 1 | ADC FIFO DMA使能寄存器 | 0x0000 |
ADC_DMADL | 0x6024 | 4 | ADC DMA接收数据深度 | 0x0000 |
1.1 寄存器简介
关于寄存器更详细的描述,请参考CH2201 芯片手册。
ADC_CR ADC控制寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:12] | Reserved | ||
[11:8] | SEQC | R/W | SEQ 模式下,转换次数 |
[7] | Reserved | ||
[6:3] | CH_SEL | R/W | 通道选择 |
[2:1] | CMS | R/W | 模式选择 00 = 单通道单次 01 = 多通道扫描 10 = 单通道连续 |
[0] | ADC_DOWN | R/W | ADC模块关闭 0 = ADC模块使能 1 = ADC模块关闭 |
ADC_DR ADC数据寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:12] | Reserved | ||
[11:0] | DATA | R/W | ADC转换结果 |
ADC_SR ADC状态寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:9] | Reserved | ||
[8] | OVERW | R | 转换结果数据覆盖 |
[7] | VALID | R | 转换结果数据有效 |
[6:3] | CCC | R | 当前转换通道 |
[2] | BUSY | R | ADC正在转换中 |
[1] | CMPF | R | 转换结果匹配中比较寄存器 |
[0] | ADEF | R | 转换结束 |
ADC_CMPR ADC比较寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:22] | Reserved | ||
[21:10] | CMPD | R/W | 比较阈值 |
[9:6] | CNT | R/W | 比较匹配次数 |
[5:2] | CMPCH | R/W | 比较通道选择 |
[1] | CMPCOND | R/W | 比较条件设置 0 = 小于阈值匹配 1 = 大于等于阈值匹配 |
[0] | CMPEN | R/W | 比较功能使能 |
ADC_IE ADC中能使能寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:3] | Reserved | ||
[2] | CMPIE | R/W | 比较匹配中断使能 |
[1] | OVWRIE | R/W | 数据覆盖中断使能 |
[0] | CPLTIE | R/W | 采样转换结束中断使能 |
ADC_IFLG ADC中断状态寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:3] | Reserved | ||
[2] | CMPIE | R/W | 比较匹配中断 |
[1] | OVWRIE | R/W | 数据覆盖中断 |
[0] | CPLTIE | R/W | 采样转换结束中断 |
ADC_STC ADC启动转换寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:1] | Reserved | ||
[0] | START | R/W | ADC采样触发位 |
ADC_SAMSEL ADC采样设置寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:1] | Reserved | ||
[0] | SAMSEL | R/W | 不重要 |
ADC_DMACR ADC DMA控制寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:1] | Reserved | ||
[0] | DMAEN | R/W | DMA功能使能 |
ADC_DMADL ADC DMA数据深度寄存器
Bits | Fields | R/W | Description |
---|---|---|---|
[31:4] | Reserved | ||
[3:0] | DMADL | R/W | DMA触发条件 当ADC采样到足够的数据时(超过DMADL 个数据),就会触发DMA请求 |
2. 驱动程序的使用
*要使用本文中的驱动程序,首先将附录中的驱动文件保存到本地并添加到CDK工程中
.c 文件添加到工程中,.h 文件复制到CDK 的include 路径中*
使用该驱动程序也非常简单:1. 配置ADC通道输入引脚;2. 开始转换并读取转换结果。 具体如下:
2.1 单通道单次转换模式
以下程序演示对两个通道:ADC_CH0 和 ADC_CH10 分别进行单通道单次采样,并将结果打印:
#include <stdio.h>
#include "soc.h"
#include "my_adc.h"
int main(void)
{
uint32_t adc_value;
// single channel, single convertion
adc_pin_init(0); // adc channel 0 pin initialize
adc_pin_init(10); // adc channel 10 pin initialize
while (1) {
adc_single_read(0, &adc_value);
printf("analog value from CH0 = %d\n", adc_value);
adc_single_read(10, &adc_value);
printf("analog value from CH10 = %d\n", adc_value);
mdelay(1000);
}
}
以上程序调用了驱动程序中的两个函数:
adc_pin_init()
第一个参数:ADC通道选择,该参数可以是范围从0 到15
adc_single_read()
第一个参数:ADC通道选择,该参数可以是范围从0 到15
第二个参数:ADC转换结果存放位置,是一个int型指针,函数执行完成后会将ADC结果存入到指针指向的位置
将CB2201 开发板串口连接到计算机,并打开一个串口终端。
编译下载程序,然后复位开发板。
将CH0 或者CH10 通道通过杜邦线连接到GND 或者3.3V 上,看打印结果有什么变化。
2.2 单通道连续转换模式
以下程序演示在Channel 0上,一次连续采样10次,并将采样结果通过串口打印出:
#include <stdio.h>
#include "soc.h"
#include "my_adc.h"
int main (void)
{
uint32_t adc_value[16];
uint32_t tmp_i;
// single channel, continous convertion
adc_pin_init(0);
while (1) {
adc_seq_read(0, 10, adc_value); // ADC onvert 10 times continously
for (tmp_i=0; tmp_i<10; tmp_i++) {
printf("adc_value[%d] = %d\n", tmp_i, adc_value[tmp_i]);
}
mdelay(1000);
}
}
以上程序调用了驱动程序中的两个函数:
adc_pin_init()
第一个参数:ADC通道选择,该参数可以是范围从0 到15
adc_seq_read()
第一个参数:ADC通道选择,该参数可以是范围从0 到15
第二个参数:ADC连续转换次数,该参数可以使范围从0 到15
第三个参数:ADC转换结果存放位置,是一个int型指针,函数执行完成后会将ADC结果存入到指针指向的位置
将CB2201 开发板串口连接到计算机,并打开一个串口终端。
编译下载程序,然后复位开发板。
将CH0 通道通过杜邦线连接到GND 或者3.3V 或者在0到3.3V之间的电压上,看打印结果有什么变化。
在单通道连续转换模式下,每次小的转换操作需要14 个时钟周期。如:连续转换10 次,总共需要140 个时钟周期。
2.3 多通道扫描模式
以下程序演示对ADC 通道从CH0 和CH1 的扫描操作。
#include <stdio.h>
#include "soc.h"
#include "my_adc.h"
int main (void)
{
uint32_t adc_value[16];
uint32_t tmp_i;
// multi-channel, scan mode
adc_pin_init(0);
adc_pin_init(1);
while (1) {
adc_scan_read(1, adc_value); // ADC convert 2 times, from channel 0 to channel 1
for (tmp_i=0; tmp_i<2; tmp_i++) {
printf("adc_value[%d] = %d\n", tmp_i, adc_value[tmp_i]);
}
mdelay(1000);
}
}
以上程序调用了驱动程序中的两个函数:
adc_pin_init()
第一个参数:ADC通道选择,该参数可以是范围从0 到15
adc_scan_read()
第一个参数:ADC通道选择,该参数可以是范围从0 到15,表示在ADC转换中,从CH0 扫描到该参数表示的通道
第二个参数:ADC转换结果存放位置,是一个int型指针,函数执行完成后会将ADC结果存入到指针指向的位置
将CB2201 开发板串口连接到计算机,并打开一个串口终端。
编译下载程序,然后复位开发板。
将CH0 或者CH1 通道通过杜邦线连接到GND 或者3.3V 或者在0到3.3V之间的电压上,看打印结果有什么变化。
2.4 使用ADC中断
以下程序演示如何使用ADC中断。程序开启ADC转换之后可以去执行其他操作,等到ADC 转换完成之后,ADC向CPU 发出中断信号,然后CPU 才会将ADC 转换结果读出。
#include <stdio.h>
#include "soc.h"
#include "my_adc.h"
#include "drv_adc.h"
volatile uint32_t adc_value[16];
volatile uint32_t adc_cmplt;
void adc_interrupt_callback (int32_t idx, adc_event_e event)
{
printf("adc interrupt ...\n");
if (event == ADC_EVENT_CONVERSION_COMPLETE) {
adc_read(adc_value, 10);
adc_cmplt = 1;
}
}
int main (void)
{
uint32_t tmp_i;
// single channel, continous convertion
adc_pin_init(0);
drv_adc_initialize(0, adc_interrupt_callback);
adc_enable_cnv_interrupt();
adc_seq_start(0, 10);
while (1) {
if (adc_cmplt) {
adc_cmplt = 0;
for (tmp_i=0; tmp_i<10; tmp_i++) {
printf("adc_value[%d] = %d\n", tmp_i, adc_value[tmp_i]);
}
mdelay(1000);
adc_seq_start(0, 10);
}
}
}
以上程序中,
首先实现一个ADC中断回调函数:
adc_interrupt_callback, 该函数有两个参数:
第一个参数:ADC设备编号,这个参数在回调函数中用不到的。
第二个参数:ADC中断类型,按照上面寄存器说明中的介绍,ADC中断类型有3 种,分别为:
ADC_EVENT_CONVERSION_COMPLETE, ADC_EVENT_DATA_OVERWRITE, ADC_EVENT_DATA_COMPARE_VALID
然后需要调用adc_pin_init()函数初始化ADC 引脚;
调用drv_adc_initialize()函数指定ADC 的中断回调函数;
调用adc_seq_read()函数,开启单通道连续转换
在函数主循环中,等待ADC 转换完成,并开启新的转换。
按照之前章节中所述开始演示本例程,查看结果。
2.5 使用ADC比较功能
以下程序演示如何使用ADC中的比较功能。
这个功能是:开启ADC采样,如果采样到的数值大于等于(或者小于)用户设定的一个阈值,就会把比较匹配的标志位置起来,如果用户同时开启的相应的中断,则还会产生一个中断。
#include <stdio.h>
#include "soc.h"
#include "my_adc.h"
#include "drv_adc.h"
volatile uint32_t adc_value[16];
volatile uint32_t adc_cmplt, adc_cmp_vld;
void adc_interrupt_callback (int32_t idx, adc_event_e event)
{
printf("adc interrupt ...\n");
if (event == ADC_EVENT_CONVERSION_COMPLETE) {
adc_read(adc_value, 10);
adc_cmplt = 1;
} else if (event == ADC_EVENT_DATA_COMPARE_VALID) {
adc_cmp_vld = 1;
}
}
int main (void)
{
uint32_t tmp_i;
// single channel, continous convertion
adc_pin_init(0);
drv_adc_initialize(0, adc_interrupt_callback);
adc_enable_cnv_interrupt();
adc_enable_cmp_interrupt();
adc_set_compare(0, 4000, ADC_CMP_GE, 0);
//adc_single_start(0);
adc_seq_start(0, 10);
while (1) {
if (adc_cmplt) {
adc_cmplt = 0;
printf("adc_value[%d] = %d\n", 0, adc_value[0]);
mdelay(1000);
//adc_single_start(0);
adc_seq_start(0, 10);
}
if (adc_cmp_vld) {
adc_cmp_vld = 0;
printf("ADC compare valid ...\n");
}
}
}
以上程序中,
首先实现一个ADC中断回调函数:adc_interrupt_callback,
该函数有两个参数:
第一个参数:ADC设备编号,这个参数在回调函数中用不到的。
第二个参数:ADC中断类型,按照上面寄存器说明中的介绍,ADC中断类型有3 种,分别为:
ADC_EVENT_CONVERSION_COMPLETE, ADC_EVENT_DATA_OVERWRITE, ADC_EVENT_DATA_COMPARE_VALID,
这次我们需要处理的类型有两种;
然后需要调用adc_pin_init()函数初始化ADC 引脚;
drv_adc_initialize() 函数指定ADC 的中断回调函数;
adc_enable_xx_interrupt() 使能相应的中断;
adc_set_compare()设置比较条件:该函数需要4 个参数:
- 通道选择:设置需要比较的通道;
- 比较阈值:
- 比较条件:ADC_CMP_GE 表示大于等于阈值,ADC_CMP_LT表示小于阈值;
- 匹配次数:设置需要联系匹配多少次才会设置标志位,0 表示只要匹配一次机会设置标志位继而可以产生中断;
然后再循环中等待转换结果和匹配结果。
本文作者:huanghh
点击查看原文