MSP430 ADC12最高采样率测试详解

使用的MSP430型号为MSP430F5529LP(Lauchpad)

MSP430x5xx and MSP430x6xx Family User's Guide
给出:其内置12位ADC的
最高采样率约为200ksps

下面详述ADC设置过程。

目录

1.设置ADC转换模式为Repeat-single-channel;

2.设置ADC的转换时钟sample-and-hold source (SHI)

3.设置定时器A为输出模式

4.设置输入通道

5.设置ADC12SHP位

6.设置采样保持时间


1.设置ADC转换模式为Repeat-single-channel;

  

请通过设置ADC12CONSEQx位来设置转换模式。

2.设置ADC的转换时钟sample-and-hold source (SHI)

选择为定时器A的输出;

对于ADC12SHSx位, 默认值为0h,也就是ADC12SC位控制一次转换或多次转换的开始。在这一点上,官网上给出的大部分例程都保持默认设置。比如:

https://dev.ti.com/tirex/explore/node?devices=MSP430F5529&node=ALGZRALuAjj-L1sgzhrl-Q__IOGqZri__LATEST

本例程中需要选择定时器输出控制转换的开始, MSP430x5xx and MSP430x6xx Family User's Guide 中告诉我们需要查找device-specific data sheet

在这一点上,MSP430G2553 的ADC10的寄存器说明中则直接给出了对应的定时器:

下图摘自
MSP430x2xx Family  User's Guide

 对于F5529的ADC12,我们在 MSP430F552x, MSP430F551x Mixed-Signal Microcontrollers 中可以找到答案: 

这样,设置ADC12SHS位为ADC12SHS_1,就可以通过TA0.1输出一个PWM波控制ADC转换。

注意,由于使用了TimerA控制转换,我们就不再需要控制ADC12SC位来开启转换。

也就是说官网示例中的以下语句我们不需要。

 ADC12CTL0 |= ADC12SC;                   // Start sampling/conversion

同理,官网的给出的单通道重复转换的另一个示例中:

https://dev.ti.com/tirex/explore/node?devices=MSP430F5529&node=AF4y3ALvJIfHLG8i78B81g__IOGqZri__LATEST

 ADC12MSC位的设置我们也不再需要,因为我们是通过定时器输出的PWM波来控制转换的,ADC12MSC位被设置为1时,得到一个数据后,下一个数据将会被立即转换,并不受PWM波的控制。(见下)

3.设置定时器A为输出模式

TA0.1输出应为周期为200kHz的PWM波。

 这里选择Output Mode 3,输出PWM波的周期只受TAxCCR0控制。

如果你的MSP430 SMCLK为8MHz,且SMCLK被选为定时器的时钟源,那么TAxCCR0应该为:

\mathrm{TAxCCR0}=\frac{8MHz}{200kHz}=40

TAxCCR1的值将只影响占空比。

选择其他的输出模式请根据实际进行设置。

4.设置输入通道

上图来自:

MSP430F5529 LaunchPad™ Development Kit  (MSPEXP430F5529LP) 

slau533d.pdf

上图仍然来自:
MSP430F552x, MSP430F551x Mixed-Signal Microcontrollers

这里选择P6.0作为ADC输入引脚。

5.设置ADC12SHP位

该位控制采样的模式。

Extended Sample Mode:

Pulse Sample Mode: 

这里的理解为:SHI(已经被我们设置为定时器的输入)控制采样和转换时序。

对于 Extended Sample Mode,采样时长将与其高电平时间保持一致,这样在某些情况下可能导致转换出错。

比如,每次采样间隔完全足够完成一次转换,但由于低电平时间过短(比如占空比为99%),t_convert短于13个ADC12CLK,转换就会出错。

对于Pulse Sample Mode,SHI的上升沿触发采样开始,但采样时长由ADC12SHT位控制(见下一部分)

6.设置采样保持时间

由于需要达到最高转换速率,这里的设置需要异常谨慎。

下面稍作分析。

上图仍然来自:MSP430F552x, MSP430F551x Mixed-Signal Microcontrollers

 上图来自:MSP430x5xx and MSP430x6xx Family User's Guide

ADC12 clock source默认值为0,即ADC12OSC,其频率范围为:4.2~5.4MHz。

这里估算时按5MHz算,则其周期为:1/5M=200ns=0.2us

而我们需要达到的转换速率为200kHz,即每5us开始一次新的采样转换。

假如我们设置ADC12SHT0x位为0010b,也就是采样时间为16个ADC12CLK,则至少需要16*0.2=3.2us进行采样。

同时在当前配置下,t_convert的最小值为2.4us,那么:

\large t_{sample}+t_{convert}\geq 5.6\mu s>5\mu s

无法完成任务。这里测试的情况是采样点数不够。

所以只能设置ADC12SHT0x为0001b或0000b,其他值统统不行。

另一种解决方案,通过设置ADC12SSELx位将时钟源换为SMCLK,并将主频调成25MHz(需要进行升压操作,详见PMM模块说明,这里不多说,进而实现要求.

当然当你主频过高时,不要忘记采样时间也有要求,需要大于1000ns,否则也可能出问题。

下面贴完整代码:

#include <Clock_init.h>
/**
 * main.c
 */
unsigned int i=0;
volatile unsigned int buf[200];
int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

  Clock_init();
  Timer_Init();
  ADC12_Init();
}

#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
{
  switch(__even_in_range(ADC12IV,34))
  {
  case  0: break;                           // Vector  0:  No interrupt
  case  2: break;                           // Vector  2:  ADC overflow
  case  4: break;                           // Vector  4:  ADC timing overflow
  case  6:                                  // Vector  6:  ADC12IFG0
          buf[i]=ADC12MEM0;//*3.3/4096.0; 变成浮点数将会来不及采样
          i++;
          if(i>200) i=0;
          break;
  case  8: break;                           // Vector  8:  ADC12IFG1
  case 10: break;                           // Vector 10:  ADC12IFG2
  case 12: break;                           // Vector 12:  ADC12IFG3
  case 14: break;                           // Vector 14:  ADC12IFG4
  case 16: break;                           // Vector 16:  ADC12IFG5
  case 18: break;                           // Vector 18:  ADC12IFG6
  case 20: break;                           // Vector 20:  ADC12IFG7
  case 22: break;                           // Vector 22:  ADC12IFG8
  case 24: break;                           // Vector 24:  ADC12IFG9
  case 26: break;                           // Vector 26:  ADC12IFG10
  case 28: break;                           // Vector 28:  ADC12IFG11
  case 30: break;                           // Vector 30:  ADC12IFG12
  case 32: break;                           // Vector 32:  ADC12IFG13
  case 34: break;                           // Vector 34:  ADC12IFG14
  default: break;
  }
}

系统频率设置为25MHz (需要设置PMM升压)

void upVcc(void)//核心电压上升3级
{
    PMMCTL0_H = PMMPW_H;                      //开启PMM电源管理,即开锁
    SVSMLCTL |= SVSMLRRL_1 + SVMLE;        //配置SVML电压
    PMMCTL0 = PMMPW +PMMCOREV_3;           //配置内核电压,选择3级
    while((PMMIFG & SVSMLDLYIFG)==0);      //等待配置完成
    PMMIFG &=~ (SVMLVLRIFG + SVMLIFG + SVSMLDLYIFG);
    if((PMMIFG & SVMLIFG)==1)
        while((PMMIFG & SVMLVLRIFG)==0);
    SVSMLCTL &=~ SVMLE;                    //关闭SVML
    PMMCTL0_H = 0x00;                     //锁存配置,即关锁
}

void Clock_init()         //XT2为时钟源
{

      upVcc();
      P5SEL |= BIT2+BIT3;                       // Port select XT2

      UCSCTL6 &= ~XT2OFF;                       // Enable XT2
      UCSCTL3 |= SELREF_5+FLLREFDIV_2;                      // FLLref = XT2 4MHz  divider:4
                                                // Since LFXT1 is not used,
                                                // sourcing FLL with LFXT1 can cause
                                                // XT1OFFG flag to set
      UCSCTL4 |= SELA_2;                        // ACLK=REFO,SMCLK=DCO,MCLK=DCO


      UCSCTL2 = FLLD_1 + 24; //N=24         SMCLK=MCLK=DCOclkdiv:(N+1)*FFLrefclk/4=25MHz  FFLD=1—>D=2为默认值 -> DCOclk=50MHz


      UCSCTL0 = 0x0000;                         // Set lowest possible DCOx, MODx
      UCSCTL1 = DCORSEL_7;                      // Set RSELx for DCO = 16 MHz

      // Loop until XT1,XT2 & DCO stabilizes - in this case loop until XT2 settles
      do
      {
        UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
                                                // Clear XT2,XT1,DCO fault flags
        SFRIFG1 &= ~OFIFG;                      // Clear fault flags
      }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag

      UCSCTL6 &= ~XT2DRIVE0;                    // Decrease XT2 Drive according to
                                                // expected frequency 4MHz

  }

ADC12初始化:

void ADC12_Init()
{
    P6SEL |= BIT0;                            // Enable A/D channel A0

    ADC12CTL0 = ADC12SHT0_1 + ADC12ON;

    ADC12CTL1= ADC12SHP + ADC12CONSEQ_2 + ADC12SHS_1;  //SHS1: TimerA 0_1 output ADC source clk:SMLCK

    ADC12MCTL0 = ADC12INCH_0; //Channel 0

    ADC12IE=0x01; //Enable interrupt

    ADC12CTL0 |= ADC12ENC;

    __bis_SR_register(GIE);       // Enter LPM0, Enable interrupts
}

定时器设置:

void Timer_Init()
{
    P1DIR |= BIT2;  //Set p1.2 as TimerA output
    P1SEL |= BIT2;
    TA0CTL= TASSEL_2 + MC_1 + TACLR;
    TA0CCTL1=OUTMOD_3;
//    CCTL1=CCIE;  // Don't need Timer interrupt here
    TA0CCR0=125; //T=5us
    TA0CCR1=62;  // Set the duty. Can be any value in this project

}

结果:

输入10kHz正弦波测试,每周期应该采样得到20个数据点。

 TimerA的PWM波从P1.2输出:

补充DMA操作:

#include <msp430.h>
#include <stdint.h>

extern unsigned int buf[200];

void DMA_Init()
{
    // Setup DMA0
    DMACTL0 = DMA0TSEL_24;                    // ADC12IFGx triggered
    DMACTL4 = DMARMWDIS;                      // Read-modify-write disable
//    DMA0CTL &= ~DMAIFG;
    DMA0CTL = DMADT_4+DMAEN+DMADSTINCR_3+DMASRCINCR_0; // Rpt single tranfer
    DMA0SZ = 200;                               // DMA0 size = 200

    __data20_write_long((uintptr_t) &DMA0SA,(uintptr_t) &ADC12MEM0);
                                              // Source block address DMA将存储ADC数据
    __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) &buf);
                                              // Destination single address数据存至buf数组中

    __bis_SR_register(LPM0_bits + GIE);      
    __no_operation();                         // used for debugging
}

物联沃分享整理
物联沃-IOTWORD物联网 » MSP430 ADC12最高采样率测试详解

发表评论