模数转换器(analog-to-diaital converter,通常称为ADC)是一种模拟与数字转换器,支持12路外部模拟输入和若干内部模拟信号选择。
Ai-WB2的ADC支持以下四种模式:单次单诵道转换、连续单诵道转换、单次多通道转换和连续多通道转换模式。转换结果为1214116bits左对齐模式。ADC拥有深度为32的FIFO,支持多种中断和DMA操作。 ADC除了用于普通模拟信号测量外,还可以用于测量供电电压,比外ADC还可以通过测量内/外部二极管电压用于温度检测。
本文将详细介绍如何通过Ai-WB2的ADC模块对电位计进行电压采样。
一:ADC介绍
BL602芯片内置一个12bits 的逐次逼近式模拟数字转换器(ADC),支持12 路外部模拟输入和若干内部模拟信号选择。ADC可以工作在单次转换和多通道扫描两种模式下,转换结果为12/14/16bits左对齐模式。ADC 拥有深度为32的FIFO,支持多种中断,支持DMA 操作。ADC 除了用于普通模拟信号测量外,还可以用于测量供电电压,此外ADC 还可以通过测量内/外部二极管电压用于温度检测。
Ai-WB2的ADC具有如下特性:
高性能
· 可以选择12-bit,14-bit,16-bit 转换结果输出
· ADC 转换时间最快0.5us(12-bit 转换结果)
· 支持1.8V3.3V 可选参考电压
· 支持DMA 将转换结果搬运到内存
· 支持单通道转换和多通道扫描两种模式
· 支持单端与差分两种输入模式
· 支持抖动补偿
· 支持用户自行设定转换结果偏移值
· 扫描模式时钟最大支持1M,非扫描模式支持2M
模拟通道数
· 12 路外部模拟通道
· 2 路DAC 内部通道
· 1路VBAT/2 通道
· 1路TSEN 通道
ADC的功能框图如下:
ADC 模块包含五大部分,分别为前端输入通道选择器,程控放大器,ADC 采样模块,数据处理模块以及FIFO。输入通道选择器用于选择需要采样的通道,既包含外部模拟信号,也包含内部模拟信号,程控放大器用于对输入信号做进一步处理,可以根据输入信号的特点,比如直流,交流,进行设定,以便得到更准确的转换值。ADC 采样模块是最主要的功能模块,实现通过逐次比较的方式,得到模拟信号到数字信号的转换。转换的结果为12bit,数据处理模块负责将转换的结果进一步处理,包括添加通道信息等。最后得到的数据会推送到最后端的FIFO 中。
BL602中,ADC通道与GPIO的对应关系如下:
二:ADC驱动API
在bl_iot_sK中,ADC的HOSAL层高级APl在 components/platform/hosal/include/hosal_adc.h中定义。常用的驱动API函数如下:
· int hosal_adc_init(hosal_adc_dev_t *adc):初始化ADC。参数说明如下:
· adc:ADC设备。其定义如下:
- /**
- * @brief Define ADC dev hosal handle
- */
- typedef struct {
- uint8_t port; /**< @brief adc 端口 */
- hosal_adc_config_t config; /**< @brief adc 配置 */
- hosal_dma_chan_t dma_chan; /**< @brief adc dma 通道 */
- hosal_adc_irq_t cb; /**< @brief adc 回调函数 */
- void *p_arg; /**< @brief p_arg 回调函数参数 */
- void *priv; /**< @brief priv 用户自定义数据 */
- } hosal_adc_dev_t;
复制代码 其中,hosal_adc_config_t为ADC配置,其定义如下:
- /**
- * @brief Define ADC config args
- */
- typedef struct {
- uint32_t sampling_freq; /**< @brief 采样频率(以Hz为单位) */
- uint32_t pin; /**< @brief adc 引脚 */
- hosal_adc_sample_mode_t mode; /**< @brief adc 采样模式 */
- uint8_t sample_resolution; /**< @brief adc 采样精度 */
- } hosal_adc_config_t;
复制代码 其中hosal_adc_sample_mode_t的定义如下:
- /**
- * @brief ADC MODE type
- */
- typedef enum {
- HOSAL_ADC_ONE_SHOT, /**< @brief 单次采样 */
- HOSAL_ADC_CONTINUE /**< @brief 持续采样 */
- } hosal_adc_sample_mode_t;
复制代码 · 返回值:成功时返回0,否则返回EIO或其他值
· int hosal_adc_add_channel(hosal_adc_dev_t *adc,uint32_t channel):添加向ADC设备添加ADC通道。参数说明如下:
· adc:ADC端口设备
· ochannel:需要添加的ADC通道
· 返回值:成功时返回0,否则返回EIO或其他值
· int hosal_adc_remove_channel(hosal_adc_dev_t *adc, uint32_t channel):移除ADC诵道。参数说明如下:
· adc:ADC端囗设备
· ochannel:需要移除的ADC通道
· 返回值:成功时返回0,否则返回EIO或其他值
· int hosal_adc_value_get(hosal_adc_dev_t *adc, uint32_t channel,uint32_t timeout):读取单个ADC采样结果。参数说明如下:
· adc:ADC端口设备
· channel:ADC通道
· otimeout:超时时长
· 返回值:如果读取失败,则返回-1:否则返回ADC值
· int hosal_adc_tsen_value_get(hosal_adc_dev_t*adc):获取ADC端囗的TSEN值。参数说明如下:
· adc:ADC端口设备
· 返回值:如果读取失败,则返回-1:否则返回ADC值
· int hosal_adc_sample_cb_reg(hosal_adc_dev_t *adc,hosal_adc_cb_t cb):注册ADC回调函数(该函数未具体实现)
· adc:ADC端口设备
· cb:回调函数,当cb不为NULL时,表示注册;当cb为NULL时,表示注销。其定义如下:
- typedef void (*hosal_adc_irq_t)(void *parg);
复制代码 请注意:指针cb 中的 adc 必须与传递给 hosal_adc_sample_cb_reg 的 adc 指针相同,驱动程序必须通过调用 cb 通知上层 ADC 数据是否已在硬件或内存(DMA)中准备好。
· 返回值:成功时返回0,否则返回EIO或其他值
· int hosal_adc_start(hosal_adc_dev_t *adc,void *data,uint32_t size):启动ADC采样(该函数未具体实现)。参数说明如下:
· adc:ADC端口设备
· data:用于储存采样结果
· size:储存ADC采样结果长度
· 返回值:成功时返回0,否则返回EIO或其他值
· int hosal adc_stop(hosal_adc_dev_t *adc):ADC停止采样(该函数未具体实现)。参数说明如下:
· adc:ADC端口设备
· 返回值:成功时返回0,否则返回EIO或其他值
· hosal_adc_finalize(hosal_adc_dev_t *adc):释放ADC。参数说明如下:
· adc:ADC端囗设备
· 返回值:成功时返回0,否则返回EIO或其他值
三:ADC使用示例
下面将演示通过ADC的通道4(GPIO5)来对电位计的电压进行采样。示例代码如下:
- #include <stdio.h>
- #include <string.h>
- #include <FreeRTOS.h>
- #include <task.h>
- #include <stdio.h>
- #include <stdbool.h>
- #include <hosal_dma.h>
- #include <hosal_adc.h>
- #include <blog.h>
- #define TAG "adc_demo"
- /********** BL602 ************
- * channel0 -----> gpio12
- * channel1 -----> gpio4
- * channel2 -----> gpio14
- * channel3 -----> gpio13
- * channel4 -----> gpio5
- * channel5 -----> gpio6
- * channel7 -----> gpio9
- * channel9 -----> gpio10
- * channel10 -----> gpio11
- * channel11 -----> gpio15
- */
- static hosal_adc_dev_t adc0;
- static void adc_init(void){
- adc0.port = 0;
- adc0.config.sampling_freq = 340;
- adc0.config.pin = 5;
- adc0.config.mode = HOSAL_ADC_ONE_SHOT; // 配置为单次采样
- int ret = hosal_adc_init(&adc0);
- if (ret != 0) {
- blog_error("init adc failed. \r\n");
- return;
- }
- hosal_adc_add_channel(&adc0, 4);
- printf("adc init done\r\n");
- }
- void adc_task(void* params){
- adc_init();
- printf("adc task start...\r\n");
- vTaskDelay(500);
- while(true){
- //hosal_adc_start(&adc0);
-
- int ret = hosal_adc_value_get(&adc0, 4, 20);
- if(ret < 0){
- printf("adc sample failed:%d\r\n",ret);
- continue;
- }
- printf("adc value = %d\r\n",ret);
- vTaskDelay(10);
-
- }
- hosal_adc_finalize(&adc0);
- }
- void main(void) {
- hosal_dma_init();
- printf("adc demo inited\r\n");
- xTaskCreate(adc_task, "adc_task", 1024, NULL, 15, NULL);
- }
复制代码 注意:HOSAL层使用了DMA方式采样,因此需要调用 hosal_dma_init 函数来初始化DMA模块。
|
|