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.

[参考译文] MSP430FR2355:使用 TOGGLE 引脚测量 MCLK 和 ADC 转换

Guru**** 2538950 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/959453/msp430fr2355-measure-the-mclk-and-adc-conversion-with-toggle-pin

器件型号:MSP430FR2355

尊敬的*

我们需要测量:

1)带引脚切换的 MCLK (在引脚 P2.2上)(该引脚连接到示波器),但我们得到错误的频率,输入时钟为24MHz,引脚切换仅为3MHz,并具有以下代码  

#include 
#include 

void init_CS();
void CS_BypassXT1_HF ();

uint16_t ADC_val = 0;

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

P2SEL0 &=~(BIT2); //选择 P2.2作为 I/O 功能
P2SEL1 &=~(BIT2); //选择 P2.2作为 I/O 功能

P2DIR |= BIT2; //将 P2.2配置为输出方向引脚
P2OUT |= BIT2; //将 P2.2初始值配置为高电平

GPIO_setPeripheralModuleFunctionInputPin (
GPIO_PORT_P2、
GPIO_PIN7、
GPIO_secondary 模块功能
);

GPIO_setPeripheralModuleFunctionInputPin (
GPIO_PORT_P1、
GPIO_PIN6、
GPIO_ternary_module_function
);

//将 P3.7设置为输出方向| LED1
GPIO_setAsOutputPin (
GPIO_PORT_P3、
GPIO_PIN7
);

GPIO_setOutputLowOnPin (
GPIO_PORT_P3、
GPIO_PIN7
);

//将 P3.6设置为输出方向| LED2
GPIO_setAsOutputPin (
GPIO_PORT_P3、
GPIO_PIN6
);

GPIO_setOutputLowOnPin (
GPIO_PORT_P3、
GPIO_PIN6
);

// P2.6上的输出 MCLK
GPIO_setPeripheralModuleFunctionOutputPin (
GPIO_PORT_P2、
GPIO_PIN6、
GPIO_PRIMARY_MODULE_FUNCTION
);

// P1.0上的输出 SMCLK
GPIO_setPeripheralModuleFunctionOutputPin (
GPIO_PORT_P1、
GPIO_PIN0、
GPIO_secondary 模块功能
);

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



init_CS();

ADCCTL0 &=~ADCSHT; //清除 ADCCTL0中的 ADCSHT
ADCCTL0 |= ADCSHT_0; //将 S&H 设置为4个 ADCCLK 周期
//ADCCTL0 |= ADCSHT_1; //将 S&H 设置为8个 ADCCLK 周期
//ADCCTL0 |= ADCSHT_2; //将 S&H 设置为16个 ADCCLK 周期
ADCCTL1 |= ADCSHP_1 | ADCDIV_1 | ADCSSEL_3; // SAMPCON 信号来源于采样定时器| SMCLK/2 | SMCLK 源
ADCCTL2 &=~ADCRES; //清除 ADCCTL2中的 ADCRES
ADCCTL2 |= ADCRES_1; //设置10位

ADCMCTL0 |= ADCINCH_6;

ADCCTL0 |= ADCON | ADCENC;


while (1)
{
P2OUT = 0x04;
P2OUT = 0x00;

/*
ADCCTL0 |= ADCSC;
//P2OUT ^= BIT2;
while (!(ADCIFG & ADCIFG0));
P2OUT ^= BIT2;
*/
}
}

void init_CS()
{

//将 MCLK 设置为24MHz
cs_initClockSignal (
CS_MCLK、
CS_XT1CLK_SELECT、
CS_CLOCK 分频器_1
);
//将 SMCLK 设置为12MHz
cs_initClockSignal (
CS_SMCLK、
CS_XT1CLK_SELECT、
cs_clock_divider
);
//将 ACLK 设置为31.25kHz
cs_initClockSignal (
CS_ACLK、
CS_XT1CLK_SELECT、
cs_clock_divider
);

//初始化外部 HF CLK
CS_BypassXT1_HF ();
}

void CS_BypassXT1_HF ()
{
//启用 HF 模式
HWREG16 (CS_BASE + OFS_CSCTL6)|= XTS;

//关闭 XT1振荡器并启用旁路模式
HWREG16 (CS_BASE + OFS_CSCTL6)|=(XT1BYPASS | XT1AUTOOFF);

while (HWREG8 (CS_BASE + OFS_CSCTL7)&(XT1OFFG)){
//清除 OSC 故障标志
HWREG8 (CS_BASE + OFS_CSCTL7)&=~(XT1OFFG);

//清除全局故障标志。 如果 XT1导致全局故障
//标志要进行设置,这将清除全局错误条件。 如果有的话
//错误条件仍然存在,全局标志将再次出现。
HWREG8 (SFR_BASE + OFS_SFRIFG1)&&~OFIFG;
}
}

2)另外、测量完整 ADC 转换(采样保持、转换、稳定)的正确方法是什么?  

我们使用10位 ADC、在12MHz SMCLK 频率下为6MHz、并将 S&H 设置为4 ADC 周期= 4/6 + 12/6 + 100ns = 2.76us、我们使用以下带 TOGGLE 引脚的代码测量3.3us

#include 
#include 

void init_CS();
void CS_BypassXT1_HF ();

uint16_t ADC_val = 0;

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

P2SEL0 &=~(BIT2); //选择 P2.2作为 I/O 功能
P2SEL1 &=~(BIT2); //选择 P2.2作为 I/O 功能

P2DIR |= BIT2; //将 P2.2配置为输出方向引脚
P2OUT |= BIT2; //将 P2.2初始值配置为高电平

GPIO_setPeripheralModuleFunctionInputPin (
GPIO_PORT_P2、
GPIO_PIN7、
GPIO_secondary 模块功能
);

GPIO_setPeripheralModuleFunctionInputPin (
GPIO_PORT_P1、
GPIO_PIN6、
GPIO_ternary_module_function
);

//将 P3.7设置为输出方向| LED1
GPIO_setAsOutputPin (
GPIO_PORT_P3、
GPIO_PIN7
);

GPIO_setOutputLowOnPin (
GPIO_PORT_P3、
GPIO_PIN7
);

//将 P3.6设置为输出方向| LED2
GPIO_setAsOutputPin (
GPIO_PORT_P3、
GPIO_PIN6
);

GPIO_setOutputLowOnPin (
GPIO_PORT_P3、
GPIO_PIN6
);

// P2.6上的输出 MCLK
GPIO_setPeripheralModuleFunctionOutputPin (
GPIO_PORT_P2、
GPIO_PIN6、
GPIO_PRIMARY_MODULE_FUNCTION
);

// P1.0上的输出 SMCLK
GPIO_setPeripheralModuleFunctionOutputPin (
GPIO_PORT_P1、
GPIO_PIN0、
GPIO_secondary 模块功能
);

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



init_CS();

ADCCTL0 &=~ADCSHT; //清除 ADCCTL0中的 ADCSHT
ADCCTL0 |= ADCSHT_0; //将 S&H 设置为4个 ADCCLK 周期
//ADCCTL0 |= ADCSHT_1; //将 S&H 设置为8个 ADCCLK 周期
//ADCCTL0 |= ADCSHT_2; //将 S&H 设置为16个 ADCCLK 周期
ADCCTL1 |= ADCSHP_1 | ADCDIV_1 | ADCSSEL_3; // SAMPCON 信号来源于采样定时器| SMCLK/2 | SMCLK 源
ADCCTL2 &=~ADCRES; //清除 ADCCTL2中的 ADCRES
ADCCTL2 |= ADCRES_1; //设置10位

ADCMCTL0 |= ADCINCH_6;

ADCCTL0 |= ADCON | ADCENC;


while (1)
{

ADCCTL0 |= ADCSC;
P2OUT ^= BIT2;
while (!(ADCIFG & ADCIFG0));
P2OUT ^= BIT2;

}
}

void init_CS()
{

//将 MCLK 设置为24MHz
cs_initClockSignal (
CS_MCLK、
CS_XT1CLK_SELECT、
CS_CLOCK 分频器_1
);
//将 SMCLK 设置为12MHz
cs_initClockSignal (
CS_SMCLK、
CS_XT1CLK_SELECT、
cs_clock_divider
);
//将 ACLK 设置为31.25kHz
cs_initClockSignal (
CS_ACLK、
CS_XT1CLK_SELECT、
cs_clock_divider
);

//初始化外部 HF CLK
CS_BypassXT1_HF ();
}

void CS_BypassXT1_HF ()
{
//启用 HF 模式
HWREG16 (CS_BASE + OFS_CSCTL6)|= XTS;

//关闭 XT1振荡器并启用旁路模式
HWREG16 (CS_BASE + OFS_CSCTL6)|=(XT1BYPASS | XT1AUTOOFF);

while (HWREG8 (CS_BASE + OFS_CSCTL7)&(XT1OFFG)){
//清除 OSC 故障标志
HWREG8 (CS_BASE + OFS_CSCTL7)&=~(XT1OFFG);

//清除全局故障标志。 如果 XT1导致全局故障
//标志要进行设置,这将清除全局错误条件。 如果有的话
//错误条件仍然存在,全局标志将再次出现。
HWREG8 (SFR_BASE + OFS_SFRIFG1)&&~OFIFG;
}
}

此致、

David。

 

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

    1) 1)您可以检查生成的汇编代码、但4个时钟/语句(赋值)听起来似乎正确。 其中一个可能是使用常数发生器、但那里也有一个分支。 您可以从计时器获取 SMCLK/2。

    如果您需要 MCLK 直接路由到 P2.6 (PSEL=01、DIR=1)、则可以这样做。 [参考数据表(SLASEC4C)表6-64]

    2) 2)在这里、我同样希望差异是仪器的成本。 某些器件具有输出 ADCCLK 的引脚设置(类似于上面的 MCLK)、但我看不到 FR2355的引脚设置。

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

    您好、Bruce、

    感谢您的重播。

    我在代码中做了一些更改、如下所示:

    #include 
    #include 
    
    void init_CS();
    void CS_BypassXT1_HF ();
    
    uint16_t ADC_val = 0;
    
    void main (void){
    WDTCTL = WDTPW | WDTHOLD; //停止看门狗计时器
    
    P2SEL0 &=~(BIT2); //选择 P2.2作为 I/O 功能
    P2SEL1 &=~(BIT2); //选择 P2.2作为 I/O 功能
    
    P2DIR |= BIT2; //将 P2.2配置为输出方向引脚
    P2OUT &=~BIT2; //将 P2.2初始值配置为低电平
    
    P2SEL0 &=~(BIT3); //选择 P2.3作为 I/O 功能
    P2SEL1 &=~(BIT3); //选择 P2.3作为 I/O 功能
    
    P2DIR |= BIT3; //将 P2.3配置为输出方向引脚
    P2OUT |= BIT3; //将 P2.3初始值配置为高电平
    
    GPIO_setPeripheralModuleFunctionInputPin (
    GPIO_PORT_P2、
    GPIO_PIN7、
    GPIO_secondary 模块功能
    );
    
    GPIO_setPeripheralModuleFunctionInputPin (
    GPIO_PORT_P1、
    GPIO_PIN6、
    GPIO_ternary_module_function
    );
    
    //将 P3.7设置为输出方向| LED1
    GPIO_setAsOutputPin (
    GPIO_PORT_P3、
    GPIO_PIN7
    );
    
    GPIO_setOutputLowOnPin (
    GPIO_PORT_P3、
    GPIO_PIN7
    );
    
    //将 P3.6设置为输出方向| LED2
    GPIO_setAsOutputPin (
    GPIO_PORT_P3、
    GPIO_PIN6
    );
    
    GPIO_setOutputLowOnPin (
    GPIO_PORT_P3、
    GPIO_PIN6
    );
    
    // P2.6上的输出 MCLK
    GPIO_setPeripheralModuleFunctionOutputPin (
    GPIO_PORT_P2、
    GPIO_PIN6、
    GPIO_PRIMARY_MODULE_FUNCTION
    );
    
    // P1.0上的输出 SMCLK
    GPIO_setPeripheralModuleFunctionOutputPin (
    GPIO_PORT_P1、
    GPIO_PIN0、
    GPIO_secondary 模块功能
    );
    
    PM5CTL0 &=~LOCKLPM5; //禁用 GPIO 上电默认高阻抗模式
    //激活先前配置的端口设置
    
    
    /*
    P2SEL0 &=~(BIT7); //选择 P2.7作为 XIN
    P2SEL1 |= BIT7; //选择 P2.7作为 XIN
    
    CSCTL4 = SELMS_XT1CLK | SELA_XT1CLK;
    CSCTL5 = SMCLKOFF _0 | DIVS_0 | DIVM_0;
    *
    
    init_CS();
    
    //ADCCTL0 = 0x0100;
    ADCCTL0 &=~ADCSHT; //清除 ADCCTL0中的 ADCSHT
    ADCCTL0 |= ADCSHT_0; //将 S&H 设置为4个 ADCCLK 周期
    //ADCCTL0 |= ADCSHT_1; //将 S&H 设置为8个 ADCCLK 周期
    //ADCCTL0 |= ADCSHT_2; //将 S&H 设置为16个 ADCCLK 周期
    ADCCTL1 |= ADCSHP_1 | ADCDIV_1 | ADCSSEL_3; // SAMPCON 信号来源于采样定时器| SMCLK/2 | SMCLK 源
    ADCCTL2 &=~ADCRES; //清除 ADCCTL2中的 ADCRES
    ADCCTL2 |= ADCRES_1; //设置10位
    
    ADCMCTL0 |= ADCINCH_6;
    
    ADCCTL0 |= ADCON | ADCENC;
    
    _BIC_SR_register (GIE);
    while (1)
    {
    P2OUT = 0x04;
    P2OUT = 0x08;
    /*
    P2OUT = 0x04;
    P2OUT = 0x08;
    
    P2OUT = 0x04;
    P2OUT = 0x08;
    
    P2OUT = 0x04;
    P2OUT = 0x08;
    
    P2OUT = 0x04;
    P2OUT = 0x08;
    
    P2OUT = 0x04;
    P2OUT = 0x08;
    */
    
    }
    }
    
    void init_CS()
    {
    //将 P2.7设置为24MHz 输入时钟的 XIN
    /*GPIO_setPeripheralModuleFunctionInputPin (
    GPIO_PORT_P2、
    GPIO_PIN7、
    GPIO_secondary 模块功能
    );*
    //将 MCLK 设置为24MHz
    cs_initClockSignal (
    CS_MCLK、
    CS_XT1CLK_SELECT、
    CS_CLOCK 分频器_1
    );
    //将 SMCLK 设置为12MHz
    cs_initClockSignal (
    CS_SMCLK、
    CS_XT1CLK_SELECT、
    cs_clock_divider
    );
    //将 ACLK 设置为31.25kHz
    cs_initClockSignal (
    CS_ACLK、
    CS_XT1CLK_SELECT、
    cs_clock_divider
    );
    
    //初始化外部 HF CLK
    CS_BypassXT1_HF ();
    }
    
    void CS_BypassXT1_HF ()
    {
    //启用 HF 模式
    HWREG16 (CS_BASE + OFS_CSCTL6)|= XTS;
    
    //关闭 XT1振荡器并启用旁路模式
    HWREG16 (CS_BASE + OFS_CSCTL6)|=(XT1BYPASS | XT1AUTOOFF);
    
    while (HWREG8 (CS_BASE + OFS_CSCTL7)&(XT1OFFG)){
    //清除 OSC 故障标志
    HWREG8 (CS_BASE + OFS_CSCTL7)&=~(XT1OFFG);
    
    //清除全局故障标志。 如果 XT1导致全局故障
    //标志要进行设置,这将清除全局错误条件。 如果有的话
    //错误条件仍然存在,全局标志将再次出现。
    HWREG8 (SFR_BASE + OFS_SFRIFG1)&&~OFIFG;
    }
    }
    

    当我只有它时  

    P2OUT = 0x04;
    P2OUT = 0x08;

    在 while 循环中、我进行以下反汇编  

    --------------------------------------

    _BIC_SR_register (GIE);
    0081c2:C232 DINT
    0081c4:4303 NOP
    102 P2OUT = 0x04;
    $C$L3:
    0081c6:42E2 0203 MOV.B #4、&P2_OUT
    103 P2OUT = 0x08;
    0081ca:42F2 0203 MOV.B #8、P2_P2OUT
    100 while (1)
    0081ce:3FFB JMP ($C$L3)
    0081d0:4303 NOP

    --------------------------------------

    我用示波器查看两个信号 P2.2和 P2.3、可以看到 P2OUT = 0x04;具有三个周期~ 3* 41.6ns 和 P2OUT = 0x08;+ JMP 具有5个周期~ 208ns  

    1个周期为41.6ns = 1/24MHz

    我在 DS 中发现 JMP 始终为2个周期、但无法在 数据表中找到 MOV.B #4、&P2_P2OUT 是否为3个周期?

    当我放置多个(超过2次)  

    P2OUT = 0x04;
    P2OUT = 0x08;

    那么一切都很慢,因为我觉得它是从 FRAM (最大8MHz)执行的,因为我在示波器中看到了一些延迟  

    我如何在源代码中告诉哪些代码应该被放置到 RAM 中以实现更快的执行?  

    此致、

    David。

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

    这里有比我更好的向导、但这两条指令看起来都是使用常数发生器("R,&EDe")的格式 I、因此有2个字和3个周期。 [参考用户指南表4-2和 4-10]。

    我在 RAM 中放入代码已经有很多年了、但 CCS "汇编器"手册(SLAU131V)第8.5.2.1节讨论了如何执行该操作。

    未经请求:我不清楚您的目标是什么。 是否要生成方波、检查 MCLK 或计时代码序列? 我问、可能还有另一种方法可以做任何事情。

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

    尊敬的 Bruce:

    我们已将 MSP 的外部时钟和 MCLK 设置为24MHz,并且我们还可以在10位模式下对 ADC 使用6MHz (最小 S&H 为4ADC_CYCLE + 12ADC_CYCLE,用于转换+ 100ns 趋稳,如 DS 所示)

    我想编写代码,以便在变量中尽可能快地进行 ADC 转换,然后从不同的模拟通道执行此操作三次。

    如果我不将代码放入 RAM 中、那么它将从 FRAM 中执行、最大值为8MHz、不会使用24MHz MCLK 满电位。

    此外、使用 ROM 中的 TI 驱动程序库函数并不是最快的方法(它使用24MHz MCLK)、但这些函数是通用函数、具有启动转换并获取值所需的更多指令。

    因此、在 ADC 的首次初始化完成后(选择第一个用于转换的模拟通道) 、我想在主 while 环路中以24MHz 执行以下操作

    -start ADC 转换[ADCCTL0 |= ADCSC;]

    等待 thill 转换完成[ while (!(ADCIFG & ADCIFG0));]

    -获取值并复位 ADCIFG0标志[ ADC_val = ADCMEM0;]

    -更改模拟信道并重复上代码

    我尝试了以下操作  

    while (1)
    {
    P2OUT |= BIT2;
    ADCCTL0 |= ADCSC;
    while (!(ADCIFG & ADCIFG0));
    ADC_val = ADCMEM0;
    P2OUT &=~BIT2;
    } 

    我从 p2.2变为高电平到 p2.2变为低电平得到5.2us

    ADC 采样保持+转换+ t_Settling 应该是2.7us ,因此获取广播值和引脚切换实际上可能使用另一个2.5us?

    接下来、我要做的是将整个主函数设置为 RAM、如以下 __attribute__((ramfunc)) void main (void)

     对于上面的代码我得到什么: 而不是5.2us -> 3.8us,所以3.8 -2.7 = 1.1us 如果正确 的话, 以下反汇编代码大约是27个周期??

    119 P2OUT |= BIT2;
    $C$L3:
    0020b8:D2E2 0203 BIS.B #4、&P2_P2OUT
    122 ADCCTL0 |= ADCSC;
    0020bc:D392 0700 BIS.W #1、&ADC_ADCCTL0
    123 while (!(ADCIFG & ADCIFG0));
    $C$L4:
    0020c0:B392 071C Bit.W #1、&ADC_ADCIFG
    0020c4:27FD JEQ ($C$L4)
    125. ADC_val = ADCMEM0;
    0020c6:4292 0712 20D4 MOV.W &ADC_ADCMEM0、&ADC_val
    129 P2OUT &=~BIT2;
    0020cc:C2E2 0203 BIC.B #4、&P2_P2OUT
    105 while (1)
    0020d0:3FF3 JMP ($C$L3)
    0020d2:4303 NOP 

    此致、

    David。

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

    看看我对22个时钟进行计数的序列。 进入流水线级后、我会变得有点模糊。 (正如我提到过的、这个主题的某个地方有一些向导。 [David? Zrno?]) MSP430确实具有1个时钟指令、但这些指令很少出现在位流代码中、这些器件通常需要执行这些操作。

    我不确定我能得到比这更简约的体验。 不同的方法可能会查看整个序列。 如果您可以安排在 ADC 运行(下一个操作)时获取 ADCMEM0 (对于上一个操作)、则可以使用一些旋转时间。

    根据代码片段、我怀疑这三个通道不是连续的、但如果是连续的、您可以使用 CONSEQ=3、MSC=0来避免在操作之间切换 ENC (设置 INCH)。

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

    您好、Bruce、

    当我进行 PCB 布局时、我没有注意到为了使用 ADC 序列转换、我必须使用连续的通道、在下一个版本中、我将尝试更改该通道、但随后我将丢失一个正在使用的 SAC 输出。 我将通过托盘连接 A0、A1和 A2、以最大程度地提高 ADC 转换。

    我也没有说明如何正确地对反汇编过程中的周期进行计数、因此我想将其放置在示波器上并测量时间。

    如何做到这一点?  

    "

    不同的方法可能会查看整个序列。 如果您可以安排在 ADC 运行(下一个操作)时获取 ADCMEM0 (对于上一个操作)、则可以使用一些旋转时间。

    "

    此致、

    David。

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

    我所说的就是这样的

    ADCCTL0 |= ADCSC;//开始
    时(!(ADCIFG 和 ADCIFG0))/*empty*/;//等待
    ADCCTL0 |= ADCSC://开始下
    一个 adcvar = ADCMEM0;//从第一个结果-一场比赛,但我们预计将赢得72 MCLK 比赛
    
    

    这意味着您不必在之间切换 ADCINCH、但听起来这并不是您的选择之一。

    (我真的想念 DMA。)