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例程增加注释,xie_sx@126.com
 */

#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例程增加注释,xie_sx@126.com
 */

#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;
    }
}
相关推荐
西岸行者2 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意2 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码2 天前
嵌入式学习路线
学习
毛小茛2 天前
计算机系统概论——校验码
学习
babe小鑫2 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms2 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下2 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。2 天前
2026.2.25监控学习
学习
im_AMBER2 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J2 天前
从“Hello World“ 开始 C++
c语言·c++·学习