TI Stellaris LM4F ADC指南

2019-07-27 17:58发布

本帖最后由 TI_MCU 于 2012-3-16 17:52 编辑

最近没怎么上论坛,忽然想起还有篇很久前写成的文章,发上来分享下:


TI Stellaris LM4F ADC指南
[V1.0]
[作者: Richard Ma]
[Email: mxschina@gmail.com]
TI Stellaris LM4F ADC指南.pdf (637.37 KB, 下载次数: 218) 2012-3-16 17:36 上传 点击文件名下载附件
=========================================================
Texas InstrumentsStellaris LM4F上提供了模拟部分全新设计的ADC模块,提供了最高可到1MSPS12-bit高精度ADC,较之M3系列有不少变化。本文将从硬件功能、软件使用两个方面介绍ADC模块的使用。软件方面结合了TIStellarisWare驱动库,以避免繁琐复杂的寄存器操作,故硬件功能介绍时也尽量避免具体的寄存器。读者可以先阅读第一章了解ADC模块的工作方式及特点,再结合第二章的示例代码深入理解ADC的使用。

1.ADC硬件功能
Stellaris LM4F系列中,内置了12-bit的模/数转换模块(ADC),提供了以下特性:
    - 最高采样速率可达1MSPS
    - 支持单端及差分输入
    - 内置温度传感器
    - 64x硬件平均
    - 可编程采样序列控制器及相应深度的结果FIFO
    - 多触发源启动采样
    - 数字比较器
    - 支持DMA结果传输

本章中将对ADC的功能及特性进行介绍,希望读者能在读完这篇文章后对LM4F ADC有初步了解。

1.1.ADC模块结构
如下图所示,M4中提供了212-bit /数转换模块(ADC0ADC1),这些模块共享相同的通道,不同的型号通道数量有所区别(232系列有24个通道,231系列有12个通道)。除了这些通道以外,还有一个温度传感器,用于测量芯片内部温度以监视芯片状态,可以视作一路额外的通道。

使用ADC单元时需要注意,输入ADC模块的时钟应不低于16MHz
1.PNG

1.2. ADC 转换单元及参考电压

2.jpg

TI Stellaris LM4F中的ADC使用了逐次逼近 (SAR) 型的ADC转换单元,在芯片内部没有提供参考源。根据器件手册,为不同的器件提供参考电压的方式不同,如上图所示,主要有两种。

如左边所示,其中一种(LM4F231H5QR)不支持由外部提供参考电压,而使用VDDA作为参考电压。在使用这种类型的器件时,需要务必保证VDDA的稳定。

上图右边的另一类(LM4F232H5QD)可以由外部的VREF+VREF-管脚提供外部参考电压。

1.3. ADC 功能及使用
不同于传统单片机内ADC的采样-读取的方式,TI Stellaris LM4FADC的采样通过采样序列控制器(SampleSequencers)控制,可以采样多组数据后,一次性获得结果。在Stellaris中,即使只需采样一组数据,也需要使用Sequencer。如上图所示,启动测量需要触发(Trigger),由其它设备、外来触发源或内核产生。当转换完成或其它条件(用户配置)满足时,会产生响应的中断(Interrupt)或触发(Trigger)。中断用于通知内核,触发用于控制其它模块的动作(如关闭PWM输出)。使用ADC完成ADC采样需要进行如下步骤:
3.jpg

1.3.1. 采样序列控制器(Sample Sequencer)
1.1节可以看出,使用M4ADC的即是对Sequencer的设置和使用。配置完成后,Sequencer将自动控制ADC转换及保存数据。采用Sequencer + FIFO的好处是,可以在ADC完成一系列采样后,再读取全部结果,中间过程全部由硬件自动完成而无需消耗指令周期。

下图展示了Sequencer的工作原理,以ADC中的Sequencer0 (SS0)为例,SS0最多可以设置8组采样序列,且不一定填满8(可以停止在任意位置)Sequencer中存储的是ADC通道(0代表通道0),序列中采样通道允许重复。

4.jpg

如上图配置SS0后,启动SequencerADC会自动按设定顺序采集通道0 (CH0)、通道5 (CH5)、通道8
(CH8)……本例中,第5次采样(CH3)被定为采样序列的终止,当完成该次采样后,会自动停止,并根据配置通知处理器内核。

采样的结果会被自动存入采样结果缓存中。缓存采用FIFO进行存储,每一组序列(Sequencer)都有对应的FIFO,其深度等于该序列的最多序列组数,以存储本组序列的采样结果。采样结果可以在序列采样完成后,由内核从同一个寄存器中依次读出,也可以设置DMA模块自动传送到所需位置。转换完成时,若FIFO已满,新数据不会写入,但会溢出状态寄存器会被置位。

TI Stellaris LM4F中,每个ADC模块包含了4组采样序列,每个采样序列的最多组数不同,FIFO的大小也各不相同,可以根据用户的需求灵活使用。这些序列及组数、FIFO深度的情况如下表所示。

5.jpg

在序列中,最大组数不可超过,但不一定充满。任意位置都可以设为序列的终点;同时也可以配置任意位置也触发中断。

同一个ADC模块中的多个序列允许同时启动,这时其优先级决定其工作的先后。优先级为0-3,可以由用户配置,但须保证每个Sequencer的优先级各不相同。

    - Sequencer启动可以使用以下的触发源:
    - 内核触发(默认)
    - 模拟比较器单元(Analog Comparator)
    - GPIO输入信号
    - 通用定时器(Timer)
    - PWM模块
    - Sequencer自己(使用连续采样模式)

1.3.2.硬件平均单元
有时候,为了获得更加准确的结果,需要将多次采样的结果进行平均,Stellaris LM4F中提供了硬件平均单元来完成这一任务。硬件平均的原理是连续进行多次转换,通过硬件计算结果的平均值。计算完成后,结果会被放入结果FIFO作为一次采样的结果。目前,Stellaris LM4F系列支持2x4x8x16x32x以及64x硬件平均。

硬件平均会降低输出结果的最高速率,若使用8x硬件平均(即使用8个结果进行平均),当设置ADC的采样速率为1MSPS时,则结果的最高输出速率为125KSPS(1M / 8)

2.ADC驱动及代码示例
2.1.
ADC驱动库使用
使用ADC需要通过调用StellarisWare驱动库进行如下步骤:
1)通过SysCtlPeripheralEnable使能ADC模块及使用的通道所在管脚。示例代码:
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

2)使用GPIOPinTypeADCGPIO管脚配置为ADC功能。示例代码:
    GPIOPinTypeADC(GPIO_PORTE_BASE,GPIO_PIN_5 | GPIO_PIN_6);

3)配置启动采样的信号源,使用ADCSequenceConfigure。示例代码:
    ADCSequenceConfigure(ADC0_BASE, 0,ADC_TRIGGER_PROCESSOR, 0);

参数中第一个为ADC的基址;第二个为使用的采样序列号,可以为0~3;第三个是信号源,可以是如下值:
    ADC_TRIGGER_PROCESSOR – 程序中调用ADCProcessorTrigger函数启动
    ADC_TRIGGER_COMP0 – 通过比较器0启动
    ADC_TRIGGER_COMP1 – 通过比较器1启动
    ADC_TRIGGER_COMP2 – 通过比较器2启动
    ADC_TRIGGER_EXTERNAL – 通过GPIO引脚外部输入信号启动
    ADC_TRIGGER_TIMER – 通过Timer启动
    ADC_TRIGGER_PWM0 – 通过PWM0模块启动
    ADC_TRIGGER_PWM1 – 通过PWM1模块启动
    ADC_TRIGGER_PWM2 – 通过PWM2模块启动
    ADC_TRIGGER_PWM3 – 通过PWM3模块启动
    ADC_TRIGGER_ALWAYS – 一直反复启动

第四个参数为优先级,可以为0~30的优先级最高,3最低。当使用多个序列时,优先级不可重复。

4)通过ADCSequenceStepConfigure配置每一步序列。使用时需要配置如下参数:
    ADCSequenceStepConfigure(ADC0_BASE,序列器编号, 步数, 采样通道配置);

采样通道可以选择从ADC_CTL_CH0直到ADC_CTL_CHx之一 (x为最大通道数减一)。同时也可以配置为ADC_CTL_TS采集温度。还可以附加如下参数:
    ADC_CTL_IE – 完成该次采样时,触发中断
    ADC_CTL_END – 本次采样为本序列终点
    ADC_CTL_CMP0 ~ ADC_CTL_CMP7中一个,将结果送入比较器0~7

使用示例:
    ADCSequenceStepConfigure(ADC0_BASE,1, 1, ADC_CTL_CH9);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 2,ADC_CTL_CH21 | ADC_CTL_IE | ADC_CTL_END)

5)使能采样序列,使用ADCSequenceEnable。示例代码:
    ADCSequenceEnable(ADC0_BASE, 1);

代码中数字1表示使用采样序列1

6)当完成上面配置后,ADC就准备好启动采样了。根据配置不同,当不同的触发源触发后,ADC采样序列控制器会自动启动,控制ADC完成采样。如果配置为直接由处理器内核启动,可以调用ADCProcessorTrigger启动采样。

7)当采样完成,若配置了中断,会进入中断处理函数。同时也可以通过查询ADC中断寄存器状态,来判断转换是否完成。

8)转换完成后,可以使用ADCSequenceDataGet读取数据。该函数可以一次性将结果填入数组,但须保证所给的数组的空间足够大。如转换了5组结果在FIFO中,所给数组空间应大于5,否则可能导致数组溢出。示例代码:
    unsigned long ADCResult[8];
    ADCSequenceDataGet(ADC0_BASE, 0,ADCResult);

ADCSequenceDataGet中的数字0表示读取采样序列控制器序列0中存储的结果。读取出结果的个数等于当前FIFO中存储的结果的个数。

9)M4中的ADC12位,所以读出的结果应该在0~4095之间。

2.2.示例代码
如下为ADC使用的示例代码,该代码在LM4F232H5QD上调试通过。

  1. #include "inc/hw_types.h"
  2. #include "inc/hw_memmap.h"
  3. #include "driverlib/adc.h"
  4. #include "driverlib/sysctl.h"
  5. #include "driverlib/pin_map.h"
  6. #include "driverlib/gpio.h"

  7. int main(void)
  8. {


  9.     // 存储结果的数组
  10.     unsigned longulADC0_Value[3];

  11.     // 配置系统时钟为50MHz
  12.     SysCtlClockSet(SYSCTL_SYSDIV_4| SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

  13.     // 使能ADC0.
  14.     SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

  15.     // 使能ADC0中使用到的通道所在管脚对应的GPIO
  16.     SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

  17.     // 将通道所在管脚配置为GPIO功能
  18.     GPIOPinTypeADC(GPIO_PORTE_BASE,GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6);

  19.     // 配置采样序列1的启动条件为处理器触发
  20.     ADCSequenceConfigure(ADC0_BASE,1, ADC_TRIGGER_PROCESSOR, 0);

  21.     // 配置采样序列1的采样步骤:
  22.     // - 第0步:采通道8
  23.     // - 第1步:采通道9
  24.     // - 第2步:采通道21,并在采样结束后停止,置中断寄存器标志位
  25.     ADCSequenceStepConfigure(ADC0_BASE,1, 0, ADC_CTL_CH8);
  26.     ADCSequenceStepConfigure(ADC0_BASE,1, 1, ADC_CTL_CH9);
  27.     ADCSequenceStepConfigure(ADC0_BASE,1, 2, ADC_CTL_CH21 | ADC_CTL_IE | ADC_CTL_END);

  28.     // 使能采样序列1
  29.     ADCSequenceEnable(ADC0_BASE,1);

  30.     // 清除采样序列1的中断标志位以方便之后查询
  31.     ADCIntClear(ADC0_BASE,1);

  32.     while(1)
  33.     {
  34.         // 启动采样序列1的转换
  35.         ADCProcessorTrigger(ADC0_BASE,1);

  36.         // 等待采样序列1转换完成
  37.         while(!ADCIntStatus(ADC0_BASE,1, false));

  38.         // 读取序列1 FIFO中的采样结果
  39.         ADCSequenceDataGet(ADC0_BASE,1, ulADC0_Value);


  40.         // 使用数据
  41.         // 用户代码…
  42.         // 用户代码…
  43.     }
  44. }
复制代码
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。