使用的MSP430型号为MSP430F5529LP(Lauchpad)
下面详述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的寄存器说明中则直接给出了对应的定时器:
对于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应该为:
TAxCCR1的值将只影响占空比。
选择其他的输出模式请根据实际进行设置。
4.设置输入通道
上图来自:
这里选择P6.0作为ADC输入引脚。
5.设置ADC12SHP位
该位控制采样的模式。
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,那么:
无法完成任务。这里测试的情况是采样点数不够。
所以只能设置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输出:文章来源:https://www.toymoban.com/news/detail-404081.html
补充DMA操作:文章来源地址https://www.toymoban.com/news/detail-404081.html
#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
}
到了这里,关于MSP430 ADC12 最高采样率测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!