This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430FR5969:ADC12无法继续采样

Guru**** 2562120 points
Other Parts Discussed in Thread: MSP430FR5969

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/603955/msp430fr5969-adc12-wont-keep-sampling

器件型号:MSP430FR5969

Howdy、

我正在与 MSP430FR5969合作、尝试使内部 ADC 正常工作。 我将复制中的代码、但我将引导您完成我的思考过程。

我希望采样频率约为100kHz。 采样保持设置为16个周期时、我将 DCO 设置为4MHz、并使用 TA0.1运行双位 PWM、从而提供2MHz 的 PWM (2MHz/16个周期采样保持= 125kHz)。 当我调试代码时、它将采集大约30-100个样本(看起来正确)、然后在之后停止采样(它卡在"while (!(!(ADC12IFGR0 & BIT0));")、此时它应该采集701个样本、然后复位回0。 它在破坏我的大脑!

#include 

void gpioinit();
void clockinit();
void timerinit();
void timertest();
void adcinit();


unsigned int index;
int results[700];

int main (void){
WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器

索引= 0;

gpioinit();
clockinit();
timerinit();
timertest();
adcinit();

while (1){

ADC12CTL0 |= ADC12SC;
while (!(ADC12IFGR0 & BIT0));

结果[索引]= ADC12MEM0; //读取转换结果
索引=索引+ 1;
if (索引=699)
索引= 0;

}

}

void gpioinit (void){

P1SEL1 |= BIT2; //配置 ADC 输入 A2
P1SEL0 |= BIT2;

}
void clockinit (void){

//时钟系统设置-使用 msp430fr5969.h 查找定义

CSCTL0_H = CSKEY >> 8; //解锁 CS 寄存器
CSCTL1 = DCOFSEL_3; // DCO = 4MHz
CSCTL2 = SELA_VLOCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 SMCLK = MCLK = DCO
// ACLK = VLOCLK
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1; //将所有分频器设置为1
CSCTL0_H = 0; //锁定 CS 寄存器

}

void timerinit (void){

//禁用 GPIO 上电默认高阻抗模式以激活
//先前配置的端口设置
PM5CTL0 &=~LOCKLPM5;

//使用 TimerA0.1以100kHz 的频率定期触发 ADC
TA0CCR0 = 1; //频率= 4MHz/(TA0CCR0+1)= 2MHz
TA0CCR1 = 1; //占空比 Ton =(TA0CCR1 + 1)/4MHz
TA0CCTL1 = OUTMOD_7; //设置/复位模式
TA0CTL = tassel__SMCLK | MC__UP | TACLR;// SMCLK,向上计数模式,清除 TAR

}

void adcinit(){

//查看表5-23中的时序参数
//配置 ADC12
ADC12CTL0 &=~ADC12ENC; //禁用 ADC12
ADC12CTL0 &=~ADC12ON;
ADC12CTL0 = ADC12SHT0_2; //配置16个 ADCCLK 周期的采样和保持时间
ADC12CTL1 = ADC12SH_1 | ADC12SHP | ADC12CONSEQ_2; // ADCCLK = MODOSC;采样计时器、从 TA0.1 (SHS_1)触发、重复单通道
ADC12CTL2 = ADC12RES_2; // 12位转换结果
ADC12MCTL0 |= ADC12INCH_2 | ADC12DIF; //通道2 ADC 输入选择;Vref=AVCC
ADC12CTL0 |= ADC12ON;
ADC12CTL0 |= ADC12ENC;

}

void timertest (void){

//使用 TimerB0.1以100kHz 的频率定期触发 ADC
TB0CCR0 = 1; //频率= 1MHz/(TA0CCR0+1)= 2MHz
TB0CCR1 = 1; //占空比 Ton =(TB0CCR1 + 1)/2MMHz
TB0CCTL1 = OUTMOD_7; //设置/复位模式
TB0CTL = TBSSEL_SMCLK | MC__UP | TBCLR;// SMCLK、向上计数模式、清除 TBR

P1DIR |= BIT4; //P1.4输出
P1SEL0 |= BIT4; //P1.4至 TB0.1

}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Kevin:

    我想我知道您的问题是什么。 您似乎在前一个转换完成之前触发另一个转换的速度过快。 我认为 、对于如何将定时器用作 ADC 的触发 器存在误解(可能是对在这种情况下如何使用触发器一词的误解)。 这条语句出错了:" 采样保持设置为16个周期、我将 DCO 设置为4MHz、并使用 TA0.1运行双位 PWM、从而提供2MHz 的 PWM (2MHz/16周期采样保持= 125kHz)"这听起来像是一种解释、其中计时器 PWM 为 ADC 模块提供时钟源、然后您的采样保持时间将会关闭其中的许多时钟周期-这是不正确的。

    实际上、定时器只启动或"触发" ADC 采样和转换周期、ADC 采样和转换时序实际上由不同的时钟控制、在本例中为 MODOSC (本部分为4.8MHz)。 因此、ADC 将在 PWM 的每个单周期触发启动新的转换-在本例中为2MHz、这对于 ADC 来说太快(仅支持高达200ksps)。 一旦 ADC 采样和转换被 PWM 触发、您配置的采样保持周期数将会增加、但这是 MODOSC 周期数的结果-请参阅 ADC12CTL1寄存器中的 ADC12SSELx 位、 ADC12DIVx 位允许您根据需要对该时钟源进行分频。

    您可以这样描绘它:

                 _________________________________                                                                    _
     ADC    |<-- 16个 MODOSC 周期-->_________________________ |
                 _                                                                                                                                _
    TA0.1   ||________________________________ ||_

    最后、我还看到 ADC12SC 位在每次 while 循环迭代时都被置位-这将导致另一个 ADC 触发。 我建议在 while (1)之前移动此行、以便它开始第一次转换、然后让计时器触发其余转换。

    如何解决此问题:您提到了您的真正目标是 以 大约100kHz 的频率对信号进行采样。 首先、了解采样率与使用 ADC12SHTx 位设置的采样保持时间之间存在差异。 采样率可能是您想要的100kHz 采样率-对于计时器触发的 ADC、这意味着您应该将计时器设置为创建100kHz PWM。 这将为您提供100kHz 采样时间。 对于采样和保持时间、应根据您所测量内容的特性进行设置。 有关 确定 正确采样保持时间的更多信息、请参阅用户指南 www.ti.com/lit/pdf/slau367中的第34.2.6.3节采样时序注意事项。 确保采样和保持时间将小于触发频率、以便在下一次触发前完成转换。 根据您测量的内容、您可以将采样保持时间设置为最小设置。 发生的情况是、计时器将触发 ADC、ADC 将以您设置的采样保持时间运行、然后等待下一个触发。 因此、触发器(在您的情况下为计时器)实际上是在采样发生时设置的。

    这里有一个定时器触发 ADC 的示例:

    我希望这有助于您启动并运行 ADC。

    此致、

    Katie

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    哇! 首先、感谢您的回答。 我认为这是我在 E2E 上得到的最佳响应。 你说得对、我错误地想到了触发。 这对我来说现在更有意义了。

    其次,我做了您建议的更改,代码现在工作正常:)

    非常感谢、
    Kevin
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引述 USER="Kevin Schmidgall"]我认为这是我在 E2E 上得到的最佳响应。

    你让我的一天变得很美好:-)

    很高兴我能提供帮助!

    -Katie

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好 Katie、我还有另外一个问题!

    我一直在使用代码来采样1kHz 正弦波、2Vp-p 我要连接的代码应以200kSPS 的速率进行采样。 这意味着、采集一个周期的输入信号应该需要200个样本、200、000Sps/1000Hz = 200S (如果我正在正确地考虑这一点、并且我的代码是正确的)。

    不过、我看到捕获一个周期的波形需要大约100s。 您可以在下面的附加波形中看到这一点。 波形具有正确的峰间值、但样本数量看起来不正确。 我也用100kSps 的采样率完成了它、一个周期大约需要50个样本。 我已经检查了示波器上的输入信号、它的频率为1kHz。 我还检查了计时器信号、它的频率是正确的。  

    
    
    #include 
    
    void gpioinit();
    void clockinit();
    void timerinit();
    void timertest();
    void adcinit();
    
    
    unsigned int index;
    int results[700];
    
    int main (void){
    WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
    
    索引= 0;
    
    gpioinit();
    clockinit();
    timerinit();
    timertest();
    adcinit();
    ADC12CTL0 |= ADC12SC;
    
    
    while (1){
    
    while (!(ADC12IFGR0 & BIT0));
    
    结果[索引]= ADC12MEM0; //读取转换结果
    索引=索引+ 1;
    if (索引=699)
    索引= 0;
    }
    
    }
    
    void gpioinit (void){
    
    P1SEL1 |= BIT2; //配置 ADC 输入 A2
    P1SEL0 |= BIT2;
    
    }
    void clockinit (void){
    
    //时钟系统设置-使用 msp430fr5969.h 查找定义
    
    CSCTL0_H = CSKEY >> 8; //解锁 CS 寄存器
    CSCTL1 = DCOFSEL_3; // DCO = 4MHz
    CSCTL2 = SELA_VLOCLK | SELESS__DCOCLK | SELM_DCOCLK;//设置 SMCLK = MCLK = DCO
    // ACLK = VLOCLK
    CSCTL3 = DIVA__2 | DIVS__2 | DIVM__2; //将所有分频器设置为1
    CSCTL0_H = 0; //锁定 CS 寄存器
    
    }
    
    void timerinit (void){
    
    //禁用 GPIO 上电默认高阻抗模式以激活
    //先前配置的端口设置
    PM5CTL0 &=~LOCKLPM5;
    
    //使用 TimerA0.1以100kHz 的频率定期触发 ADC
    TA0CCR0 = 9; //频率= 1MHz/(TA0CCR0+1)= 100kHz (9)
    TA0CCR1 = 5; //占空比 Ton =(TA0CCR1 + 1)/1MHz (5)
    TA0CCTL1 = OUTMOD_7; //设置/复位模式
    TA0CTL = tassel__SMCLK | MC__UP | TACLR;// SMCLK,向上计数模式,清除 TAR
    
    }
    
    void adcinit(){
    
    //查看表5-23中的时序参数
    //配置 ADC12
    ADC12CTL0 &=~ADC12ENC; //禁用 ADC12
    ADC12CTL0 &=~ADC12ON;
    ADC12CTL0 = ADC12SHT0_2; //配置16个 ADCCLK 周期的采样和保持时间
    ADC12CTL0 = ADC12SHT1_2; //配置16个 ADCCLK 周期的采样和保持时间
    ADC12CTL1 = ADC12SH_1 | ADC12SHP | ADC12CONSEQ_2; // ADCCLK = MODOSC;采样计时器、从 TA0.1 (SHS_1)触发、重复单通道
    ADC12CTL2 = ADC12RES_2; // 12位转换结果
    ADC12MCTL0 |= ADC12INCH_2; //通道2 ADC 输入选择;Vref=AVCC
    ADC12CTL0 |= ADC12ON;
    ADC12CTL0 |= ADC12ENC;
    
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Kevin:

    我认为这种情况下的问题是、在下一个 ADC 采样之前、没有足够的时间通过您的 while 环路。 我怀疑如果您检查 ADC12OVIFG、您会发现存在溢出-这意味着 ADC 采样速度可能足够快、但您可能缺少样本、因为您读取 ADC12MEM 的速度不够快、因为通过 while 环路需要太长的时间。 while 循环中没有太多代码-问题更多的是、你不能让 MCLK (CPU 时钟)相对于采样频率运行得足够快、这样你就能够在下一个采样前完成代码。 在当前代码中、DCO 设置为4MHz、MCLK 设置为2分频、因此它仅为2MHz。 您以200kHz 的频率进行采样、因此您只需保留10个 CPU 周期即可完成整个环路-这太紧了。 尝试不要将 MCLK 除以、可能需要将 DCO 设置为8MHz (您可以将 SMCLK 除以4、这样您就不必根据需要更改计时器设置)。 如果你这样做、我怀疑你会得到你所期望的结果。

    此致、
    Katie
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    非常感谢! 来解决它。

    此致、
    Kevin