MSPM0L1306例程学习-ADC部分(3)

MSPM0L1306例程学习系列

使用的TI的官方例程,即SDK里边包含的例程代码。

可以到TI官网下载并且安装SDK: https://www.ti.com.cn/tool/cn/download/MSPM0-SDK/

MCU使用的是MSPM0L1306, 对于ADC部分,有10个例程:

前边讲了4个例程,今天接着讲2个例程,通过DMA进行进行ADC转换结果的传输,其中一个例程是12位的分辨率,另一个例程是8位的分辨率。 两个例子的简单比较如下:

  1. 在AD的工作模式都选择了单通道 多次转换的工作模式,选择adc通道2(PA25),这个可以根据实际需要进行修改的;
  2. 参考电压的选择上,都直接使用了电源电压作为基准电压。 要特别注意,如果使用内部参考电压源,那么ADC的时钟上限为4MHz。
  3. 有个采样保持时间,通过定时计数器0或者1来设置。这个跟ADC的分辨率有关,具体可以查看手册,里边有个公式计算。12位分辨率,例程里是250ns;8位分辨率,例程设置的是62.5ns。
  4. 启用了FIFO寄存器,是一个32位的寄存器,将从这个寄存器读取ADC的转换结果。因为是32位的,所以会将两次的转换结果存放在一起。所以,如果转换了1000次,实际上只要读500次,因为每次能读取两个结果。目前是这么理解的,有错的话,后续再回来更正:)
  5. 需要重点理解的是,DMA触发的相关配置。
    a. DMA Samples Count,一次DMA触发要传输的ADC转换结果数;
    b. Enable DMA Triggers, 配置可以触发DMA进行传输的触发源。

第1个例程的注解如下:



下边这一页的配置要重点理解下,总感觉例程有不是很合理的地方~

代码简单注释如下:

c 复制代码
/*
 * ADC转换的SDK例程
 * 文件名:adc12_max_freq_dma.c
 * 描述:
 *   ADC转换使用DMA来传输结果,12位分辨率。
 *   1、单通道、多次转换、自动采样模式、软件触发;
 *   2、启用FIFO,选择ADC输入通道2(PA25)
 *   3、直接使用电源电压做参考电压
 *   4、转换ADC_SAMPLE_SIZE=1024次,将通过DMA存放到数组gADCSamples[]中;
 *   5、代码中设有断点语句__BKPT(0),会自动进入断点,查看数据;
 *
 * 操作描述:
 *   1、下载程序;
 *   2、添加观察变量gADCSamples,全速运行;
 *   3、系统会自动停在断点处,查看ADC的采样结果值;
 *
 * 注意事项:
 *   1、注意系统时钟的配置,ADC的时钟为32MHz
 *   2、在SYSCONFIG图形配置工具中并没有完成所有的参数配置;
 *     部分的参数配置,在主程序通过调用库函数的形式进行重新配置;
 *   3、不能使用内部参考电压源VREF,启用内部电压,ADC时钟限制为4MHz;
 *
 * 思考:
 *   1、程序只跑一遍,如果想要不断的执行,while(1)循环应该怎么修改?
 *   2、如果没有外部电压接入PA25, 把ADC的通道换成A15,内部源监控通道,VDD/3,数据比较规律?
 *
 * 修改:
 *   基于官方的sdk例程增加注释,[email protected]
 */

#include "ti_msp_dl_config.h"

//宏定义了ADC的转换次数
#define ADC_SAMPLE_SIZE (1024)

//当启用FIFO时,2个转换结果会被压缩为一个32位存放在FIFODATA寄存器
//所以,读取FIFO的次数要减半,右移一位
#define ADC_FIFO_SAMPLES (ADC_SAMPLE_SIZE >> 1)

//定义16位的数组来存放ADC的转换结果.
uint16_t gADCSamples[ADC_SAMPLE_SIZE];

//标志变量,ADC的转换结果是否已经传输完成;
volatile bool gCheckADC;

int main(void)
{
    //器件初始化
    SYSCFG_DL_init();

    //DMA的基本工作模式在SYSCONFIG里已经配置;
    //此处配置DMA的传输通道信息,一般要配置3个参数,从哪搬到哪,搬多少
    //1、源地址, FIFODATA寄存器的地址,从这个寄存器读取数据往外搬
    //2、目的地址, 存档转换结果的数组的起始地址, 直接将数据搬到数组中
    //3、传输大小,要搬运的次数
    DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID,(uint32_t) DL_ADC12_getFIFOAddress(ADC12_0_INST));
    DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gADCSamples[0]);
    DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, ADC_FIFO_SAMPLES);

    DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);

    //配置器件的中断
    NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN);

    //ADC12的转换完成标志位清零
    gCheckADC = false;

    //软件启动ADC12转换
    DL_ADC12_startConversion(ADC12_0_INST);

    //等待ADC12的转换完成标志位变为true,该标志在中断里设置
    while (false == gCheckADC)
    {
        __WFE();
    }

    //断点,程序运行到此处会自动进入断点,可查看ADC的转换结果
    __BKPT(0);


    while (1)
    {
        __WFI();
    }
}

/*
 * ADC12中断处理函数
 * 通过DMA传输完成中断来判断ADC转换结束
 *
 */

void ADC12_0_INST_IRQHandler(void)
{
    switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST))
    {
        case DL_ADC12_IIDX_DMA_DONE:
            gCheckADC = true;
            break;
        default:
            break;
    }
}

第2个例程的注解如下:





代码简单注释如下:

c 复制代码
/*
 * ADC转换的SDK例程
 * 文件名:adc12_max_freq_dma_8bit.c
 * 描述:
 *   ADC转换使用DMA来传输结果,8位分辨率
 *   1、单通道、多次转换、自动采样模式、软件触发;
 *   2、启用FIFO,选择ADC输入通道2(PA25)
 *   3、直接使用电源电压做参考电压
 *   4、转换ADC_SAMPLE_SIZE=1024次,将通过DMA存放到数组gADCSamples[]中;
 *   5、代码中设有断点语句__BKPT(0),会自动进入断点,查看数据;
 *
 * 操作描述:
 *   1、下载程序;
 *   2、添加观察变量gADCSamples,全速运行;
 *   3、系统会自动停在断点处,查看ADC的采样结果值;
 *
 * 注意事项:
 *   1、注意ADC的时钟选择SYSOSC,工作在32MHz
 *   2、在SYSCONFIG图形配置工具中并没有完成所有的参数配置;
 *     部分的参数配置,在主程序通过调用库函数的形式进行重新配置;
 *   3、不能使用内部参考电压源VREF,启用内部电压,ADC时钟限制为4MHz;
 *
 * 思考:
 *   1、代码有一定的优化空间.例如,两个中断里的标志没有具体区分开来
 *
 * 修改:
 *   基于官方的sdk例程增加注释,[email protected]
 */

#include "ti_msp_dl_config.h"

#define ADC_SAMPLE_SIZE (1024)

//当启用FIFO时,2个转换结果会被压缩为一个32位的数据存放在FIFODATA寄存器
#define ADC_FIFO_SAMPLES (ADC_SAMPLE_SIZE >> 1)

uint16_t gADCSamples[ADC_SAMPLE_SIZE];

volatile bool gCheckADC;
volatile bool gADCError;

int main(void)
{
    //器件初始化
    SYSCFG_DL_init();

    //DMA的基本工作模式在SYSCONFIG里已经配置;
    //此处配置DMA的传输通道信息,一般要配置3个参数,从哪搬到哪,搬多少
    //1、源地址, FIFODATA寄存器的地址,从这个寄存器读取数据往外搬
    //2、目的地址, 存档转换结果的数组的起始地址, 直接将数据搬到数组中
    //3、传输大小,要搬运的次数。 放到了while(1)循环中
    DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID,(uint32_t) DL_ADC12_getFIFOAddress(ADC12_0_INST));
    DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gADCSamples[0]);

    //配置器件的中断
    NVIC_EnableIRQ(ADC12_0_INST_INT_IRQN);

    gCheckADC = false;
    gADCError = false;

    while (1)
    {
        DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, ADC_FIFO_SAMPLES);

        DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);
        DL_ADC12_enableDMA(ADC12_0_INST);
        DL_ADC12_startConversion(ADC12_0_INST);

        //查询ADC是否处于忙状态。
        //在单通道多次转换的模式下,一旦ADC被触发,无论转换是否停止,ADC将继续采样,直到完成相应次数的转换
        //??需要进一步探讨下,这个语句的具体作用
        if (DL_ADC12_STATUS_CONVERSION_ACTIVE == DL_ADC12_getStatus(ADC12_0_INST))
        {
            DL_ADC12_stopConversion(ADC12_0_INST);
        }

        while ((false == gCheckADC) && (false == gADCError))
        {
            //只有两个条件都满足,才在这里等待
            __WFE();
        }

        //为什么要先禁用,有启用? 感觉没必要??
        DL_ADC12_disableConversions(ADC12_0_INST);
        DL_ADC12_enableConversions(ADC12_0_INST);

        //断点,程序运行到此处会自动进入断点,可查看ADC的转换结果
        __BKPT(0);

        gCheckADC = false;
        gADCError = false;
    }
}

/*
 * ADC12中断处理函数
 *
 */

void ADC12_0_INST_IRQHandler(void)
{
    switch (DL_ADC12_getPendingInterrupt(ADC12_0_INST))
    {
        case DL_ADC12_IIDX_DMA_DONE:
            gCheckADC = true;
            break;
        case DL_ADC12_IIDX_UNDERFLOW:
            gADCError = true;
            break;
        default:
            break;
    }
}
相关推荐
东京老树根22 分钟前
SAP学习笔记 - 开发27 - 前端Fiori开发 Routing and Navigation(路由和导航)
笔记·学习
阿阳微客6 小时前
Steam 搬砖项目深度拆解:从抵触到真香的转型之路
前端·笔记·学习·游戏
Chef_Chen11 小时前
从0开始学习R语言--Day18--分类变量关联性检验
学习
键盘敲没电11 小时前
【IOS】GCD学习
学习·ios·objective-c·xcode
海的诗篇_12 小时前
前端开发面试题总结-JavaScript篇(一)
开发语言·前端·javascript·学习·面试
AgilityBaby12 小时前
UE5 2D角色PaperZD插件动画状态机学习笔记
笔记·学习·ue5
AgilityBaby12 小时前
UE5 创建2D角色帧动画学习笔记
笔记·学习·ue5
武昌库里写JAVA14 小时前
iview Switch Tabs TabPane 使用提示Maximum call stack size exceeded堆栈溢出
java·开发语言·spring boot·学习·课程设计
一弓虽15 小时前
git 学习
git·学习
Moonnnn.17 小时前
【单片机期末】串行口循环缓冲区发送
笔记·单片机·嵌入式硬件·学习