天天看點

CB2201 ADC應用指南CB2201 ADC應用指南

CB2201 ADC應用指南

1. 了解CB2201中的ADC

CB2201開發闆上有一個16通道的ADC,其中連接配接到YoC接口上的通道有14個,這14個通道在開發闆上的位置如下:

CB2201 ADC應用指南CB2201 ADC應用指南

*注意

在使用ADC個通道的時候,一定要注意與這些通道引腳複用的功能。比如:CH14 和CH15 通道複用的是IIC 功能。最需要的注意的是:CH2 和CH3 通道複用的是CSI 程式預設的printf 輸出序列槽,如果使用了CH2 和CH3 通道将導緻預設的printf 沒有任何輸出。*

使用者可使用3種模式操作ADC

  1. 單通道單次轉換模式
  2. 單通道多次轉換模式
  3. 多通道掃描轉換模式

1.ADC寄存器說明

寄存器名 位址 寬度 說明 複位預設值
ADC_CR 0x6000 11 ADC控制寄存器 0x0001
ADC_DR 0x6004 12 ADC資料寄存器 0x0000
ADC_SR 0x6008 9 ADC狀态寄存器
ADC_CMPR 0x600C 22 ADC比較寄存器
ADC_IE 0x6010 3 ADC中斷使能寄存器
ADC_IFLG 0x6014 ADC中斷狀态寄存器
ADC_STC 0x6018 1 ADC啟動寄存器
ADC_SAMSEL 0x601C ADC采樣模式選擇寄存器
ADC_DMACR 0x6020 ADC FIFO DMA使能寄存器
ADC_DMADL 0x6024 4 ADC DMA接收資料深度

1.1 寄存器簡介

關于寄存器更詳細的描述,請參考CH2201 晶片手冊。

ADC_CR ADC控制寄存器

Bits Fields R/W Description
[31:12] Reserved
[11:8] SEQC SEQ 模式下,轉換次數
[7]
[6:3] CH_SEL 通道選擇
[2:1] CMS

模式選擇

00 = 單通道單次

01 = 多通道掃描

10 = 單通道連續

[0] ADC_DOWN

ADC子產品關閉

0 = ADC子產品使能

1 = ADC子產品關閉

ADC_DR ADC資料寄存器

[11:0] DATA ADC轉換結果

ADC_SR ADC狀态寄存器

[31:9]
[8] OVERW R 轉換結果資料覆寫
VALID 轉換結果資料有效
CCC 目前轉換通道
[2] BUSY ADC正在轉換中
[1] CMPF 轉換結果比對中比較寄存器
ADEF 轉換結束

ADC_CMPR ADC比較寄存器

[31:22]
[21:10] CMPD 比較門檻值
[9:6] CNT 比較比對次數
[5:2] CMPCH 比較通道選擇
CMPCOND

比較條件設定

0 = 小于門檻值比對

1 = 大于等于門檻值比對

CMPEN 比較功能使能

ADC_IE ADC中能使能寄存器

[31:3]
CMPIE 比較比對中斷使能
OVWRIE 資料覆寫中斷使能
CPLTIE 采樣轉換結束中斷使能

ADC_IFLG ADC中斷狀态寄存器

比較比對中斷
資料覆寫中斷
采樣轉換結束中斷

ADC_STC ADC啟動轉換寄存器

[31:1]
START ADC采樣觸發位

ADC_SAMSEL ADC采樣設定寄存器

SAMSEL 不重要

ADC_DMACR ADC DMA控制寄存器

DMAEN DMA功能使能

ADC_DMADL ADC DMA資料深度寄存器

[31:4]
[3:0] DMADL

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轉換結果存放位置,是一個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_seq_read()

第二個參數:ADC連續轉換次數,該參數可以使範圍從0 到15

第三個參數:ADC轉換結果存放位置,是一個int型指針,函數執行完成後會将ADC結果存入到指針指向的位置

将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_scan_read()

第一個參數:ADC通道選擇,該參數可以是範圍從0 到15,表示在ADC轉換中,從CH0 掃描到該參數表示的通道

将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_EVENT_CONVERSION_COMPLETE, ADC_EVENT_DATA_OVERWRITE, ADC_EVENT_DATA_COMPARE_VALID,           

這次我們需要處理的類型有兩種;

drv_adc_initialize() 函數指定ADC 的中斷回調函數;

adc_enable_xx_interrupt() 使能相應的中斷;

adc_set_compare()設定比較條件:該函數需要4 個參數:

  1. 通道選擇:設定需要比較的通道;
  2. 比較門檻值:
  3. 比較條件:ADC_CMP_GE 表示大于等于門檻值,ADC_CMP_LT表示小于門檻值;
  4. 比對次數:設定需要聯系比對多少次才會設定标志位,0 表示隻要比對一次機會設定标志位繼而可以産生中斷;

然後再循環中等待轉換結果和比對結果。

本文作者:huanghh

點選檢視原文

繼續閱讀