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.

[参考译文] MSP430FR4133:当 P1.2或 P2.6上的中断被置位时、在 LPM0下运行的 RTC 失败

Guru**** 2589245 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/778683/msp430fr4133-rtc-running-under-lpm0-fails-when-interrupts-on-p1-2-or-p2-6-are-set

器件型号:MSP430FR4133

大家好、

这个问题需要我很长时间才能解决、这必须有一个解决方案。

在一个 RTC 中断之后、每秒将获取9次读数。  尽管《用户手册》中已经说明过、RTC 中断仍必须在 ISR 例程中清除。 这只是一个测试例程。 volatile unsigned long 整数递增1。 一个很短的 LED 指示灯闪烁、并显示 LCD 上的更新编号。 然后调用 LPM0以等待下一个 RTC 中断。

问题是、当 P1.2或 P2.6在 IO 初始化中设置了它们的中断时、此代码块将完全失败。 最终、在最终项目中、还有其他类似的中断必须与 RTC 同时运行。 这需要一个解决方案。

   //配置按钮 S1 (P1.2)中断
   GPIO_selectInterruptEdge (GPIO_PORT_P1、GPIO_PIN2、GPIO_HIGH_TO_LOW_TRANSITION);
   GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P1、GPIO_PIN2);
   GPIO_clearInterrupt (GPIO_PORT_P1、GPIO_PIN2);
//   GPIO_enableInterrupt (GPIO_PORT_P1、GPIO_PIN2);

   //配置按钮 S2 (P2.6)中断
   GPIO_selectInterruptEdge (GPIO_PORT_P2、GPIO_PIN6、GPIO_HIGH_TO_LOW_TRANSITION);
   GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P2、GPIO_PIN6);
   GPIO_clearInterrupt (GPIO_PORT_P2、GPIO_PIN6);
//  GPIO_enableInterrupt (GPIO_PORT_P2、GPIO_PIN6);

    _bis_SR_register (LPM0_bits | GIE);        //进入睡眠模式
     __no_operation();     //主循环结束

#pragma vector = RTC_vector
_interrupt void RTC_ISR (void)

   RTC_clearInterrupt (RTC_BASE、RTC_overflow_interrupt_FLAG);

   _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);                                                                   //编辑、这现在出现在 ISR 例程的顶部

   P1OUT |= BIT0;   //打开 LED1
   _DELAY_CYCLES (100000);

   IReturn=IReturn+10;

   P1OUT &=~BIT0;   //关闭 LED1
 _DELAY_CYCLES (100000);

 


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

    LPM0 EXIT 语句在 RTC_clearInterrupt 语句之后被移动到正确的位置、但循环仍然正常、但在 P2.6中断矢量启用时仍然失败。 其次、我认为这两个语句都是不必要的、因为它们是 RTC 中断自动的。 这比我的薪酬等级高得多、我希望有人对此有所帮助。 R.

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    "失败"是什么意思? 复位? ISR_TRAP? 冻结? 永远睡不着? 显示不正确的数字?

    RTC 中断的频率如何? 您是否必须实际按下按钮、或者启用是否足够?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    永远的睡眠,有点像。 它实际上在中断例程内循环(这就是 LED 的作用)、因为中断的速度是中断速度的5倍。 尝试复位 RTC 模块没有任何作用。 无论如何,这一点不应是必须的。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    快来思考一下、速度可能快20倍! R:测试在工作时闪烁频率为1Hz、在不工作时闪烁频率至少为10Hz。 当快速闪烁时,它永远不会返回到 int main(),因为 LCD 数字不会递增。 R.
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    其中任何一项都不涉及按钮按压。 这是与 LaunchPad 分开的例程、不过 IO 初始化和 LCD 初始化非常相似。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    以下语句适用于没有使能中断的 Px 引脚。 仅用于

    //   RTC_clearInterrupt (RTC_BASE、RTC_overflow_interrupt_FLAG);
    // __BIC_SR_REGISTER_ON_EXIT (LPM0_Bits);

    语句。

    首先、当中断例程顶部的两条额外语句存在时、一切都正常。 其次、当中断不存在时、中断的速度太快、LED 每秒闪烁至少10次、并且没有模数设置会影响它。  我敢说会振荡?

    当两个 Px 引脚中的任何一个被中断使能时、无论是否有这两条语句、都不会有任何中断。

    这里真正的问题是为什么在 Px 引脚上设置中断使能会影响 RTC。 需要一位专家来解决这个问题! R.

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

    是的、您必须在 ISR 中明确地清除 RTC 中断。 我在用户指南(SLAU445H)中看不到其他建议。

    出于好奇、尽管有人说 RTCIFG (也称为 RTCIF)是只读且只能使用 RTCIV 清除的(UG 表15-2)、但观察到的行为是它可以直接清除。

    我打包了代码片段并将其运行在 Launchpad 上、我得到了我期望的结果:(a)如果 ISR 清除 RTC 中断、它将每秒闪烁1次。 (b)如果 ISR 未清除中断、它会更快地闪烁(由于__delay-s 可能是每秒5次)。 我看不到启用(或不启用)引脚中断的副作用。

    我不确定你和我的表现有何不同。

    #include "driverlib.h"
    int main (void)
    {
    WDT_A_HOLD (WDT_A_base);
    
    //从示例 RTC_ex1_countmode.c 中删除了 RTC 设置
    GPIO_setAsOutputPin (GPIO_PORT_P1、GPIO_PIN0);
    PMM_unlockLPM5 (); //启用 GPIO
    //设置 DCO FLL 基准= REFO
    CS_initClockSignal (CS_FLLREF、CS_REFOCLK_SELECT、CS_Clock_divider);
    //set ACLK = REFO
    CS_initClockSignal (CS_ACLK、CS_REFOCLK_select、CS_Clock_divider);
    
    //初始化 RTC
    #define INTERVAL_TIME 32768
    RTC_INIT (RTC_BASE、INTERVAL_TIME、RTC_CLOCDIVIDER_1);
    RTC_clearInterrupt (RTC_BASE、RTC_overflow_interrupt_FLAG);
    RTC_enableInterrupt (RTC_BASE、RTC_overflow_interrupt);
    RTC_START (RTC_BASE、RTC_CLOCKSOURCE_XT1CLK);
    
    //配置按钮,来自 E2E 项目:
    //配置按钮 S1 (P1.2)中断
    GPIO_selectInterruptEdge (GPIO_PORT_P1、GPIO_PIN2、GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P1、GPIO_PIN2);
    GPIO_clearInterrupt (GPIO_PORT_P1、GPIO_PIN2);
    GPIO_enableInterrupt (GPIO_PORT_P1、GPIO_PIN2);
    
    //配置按钮 S2 (P2.6)中断
    GPIO_selectInterruptEdge (GPIO_PORT_P2、GPIO_PIN6、GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P2、GPIO_PIN6);
    GPIO_clearInterrupt (GPIO_PORT_P2、GPIO_PIN6);
    GPIO_enableInterrupt (GPIO_PORT_P2、GPIO_PIN6);
    
    while (1)
    {
    _bis_SR_register (LPM0_bits | GIE); //进入睡眠状态
    __no_operation(); //主循环结束
    }
    /*NOTREACHED*/
    返回(0);
    }
    
    无符号长整型 IReturn;// uint32_t per E2E
    #pragma vector = RTC_vector
    __interrupt void RTC_ISR (void)
    {
    RTC_clearInterrupt (RTC_BASE、RTC_overflow_interrupt_FLAG);
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//编辑、这现在出现在 ISR 例程的顶部
    P1OUT |= BIT0;//打开 LED1
    _DELAY_CYCLES (100000);
    IReturn = IReturn + 10;
    P1OUT &=~BIT0;//关闭 LED1
    __DELAY_CYCLLES (100000);
    }
    
    #pragma vector=Port1_vector
    __interrupt void P1_ISR (void)
    {
    P1IFG = 0; //混合并忽略
    return;
    }
    #pragma vector=port2_vector
    __interrupt void P2_ISR (void)
    {
    P2IFG = 0; //混合并忽略
    返回;
    }
    

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

    在一夜安眠后、考虑到我想要"清理" LaunchPad 作者的布拉格代码位置、我醒来时发现了一个真正的可能性、主要是由从该论坛上阅读的数百篇文章推动的。

    问题显然是 Px 中断矢量的设置引起的、在 LaunchPad 中、这些矢量与 main.c 程序中的其余 IO 一起定义。 我第一次看的时候觉得很奇怪,现在我还是觉得很奇怪。

    我有三个程序:periph.h、periph.c 和 main.c

    periph.h :include 声明、extern 数组声明、程序声明
    periph.c :array 定义、所有 init()定义以及数字拆分子例程
    main.c:只是主程序和主程序子例程(就是它应该的方式,对吧? 嗯,不是很安静!)

    今天的第一次尝试是将 Px 中断向量集移动到 main.c 程序。 所有其他 IO init 语句都留在 periph.c 中,

    void Init_ivectors ()

    //配置按钮 S1 (P1.2)中断
    GPIO_selectInterruptEdge (GPIO_PORT_P1、GPIO_PIN2、GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P1、GPIO_PIN2);
    GPIO_clearInterrupt (GPIO_PORT_P1、GPIO_PIN2);
    GPIO_enableInterrupt (GPIO_PORT_P1、GPIO_PIN2);

    //配置按钮 S2 (P2.6)中断
    GPIO_selectInterruptEdge (GPIO_PORT_P2、GPIO_PIN6、GPIO_HIGH_TO_LOW_TRANSITION);
    GPIO_setAsInputPinWithPullUpResistor (GPIO_PORT_P2、GPIO_PIN6);
    GPIO_clearInterrupt (GPIO_PORT_P2、GPIO_PIN6);
    GPIO_enableInterrupt (GPIO_PORT_P2、GPIO_PIN6);


    问题迎刃而解!!

    在 pragma vector ISR 例程中、RTC 中断矢量仍然必须清除、但删除了 LPM0 EXIT 语句。 现在、一切都正常工作。

    我将返回并查找说明 RTC 中断标志会自动清除的语句、可能会发现我读起来不太对。 我会告诉您我发现了什么。
    Robert。 )
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    结束语:

    我确信这一点以前已经被发现、但即使在我阅读的论坛上的所有帖子之后、我也从未遇到过这种情况。

    IO 中断声明现在返回到它们所属的 periph.c 中。 程序按应有的方式运行。

    原始 LaunchPad 软件示例将所有 IO init 语句放置在 main.c 程序中。 如前所述、我认为这很奇怪。 在我将这些语句重新放入我认为它们属于的 perif.c 后,即使是简单的测试例程也不会运行。

    然后、IO 中断 init 语句被移至 main.c 程序的底部、就像在原始 LaunchPad 软件示例中一样、所有运行时问题都消失了。

    但现在 IO 中断语句从 IO 初始化的其余部分分离出来、并且在考虑了早餐时的这个原始"修复"(我的妻子是对的、我是一个无聊的人!)之后、我将 IO 中断语句重新放置到 periph.c 中、仍然在函数 Init_ivectors 下分离。  我认为改变 main.c init()语句的顺序可能会有所不同。

    真是个惊喜! 三个关键的 init()语句是内联的,因此我不会忘记以这种方式放置它们。 其他两个 init()语句可以放在前面或后面,但这三个内联语句必须按此顺序排列,始终如此!

       init_lcd();
       init_rtc();
       init_gpio();Init_Clock();Init_ivectors ();

    执行图示。

    Robert。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    大家好、Bruce、
    我在《用户手册》中找到了这一段。 我不是很确定这些内容是如何定义的、感谢您为此提供的帮助。

    1.3.4.1中断接受

    5.中断请求标志在单源标志上自动复位。 多个源标志保持被设定以进行处理
    通过软件。

    6、SR 的所有位被清零、SCG0除外、因此终止了任何低功耗模式。 因为 GIE 位会进一步清零
    中断被禁用。

    在第6段中、LPM0看起来会在 ISR 进入时终止、因此无需 LPMx 退出语句。

    在第5段中、中断标志在单源标志上自动复位。 什么是单源标志?

    Robert。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    >在第5段中、中断标志在单源标志上自动复位。 什么是单源标志?
    我不知道 TI 教科书中"单个来源"的定义。 我可以想到的唯一示例是 TAxCCTL0:CCIFG。 IV 寄存器的存在表明 TI 不会将 RTCIFG 视为单源。 在任何情况下、我认为"被置位、直到通过读取 RTCIV 寄存器将其清零"[UG 章15.2.4节]优先于任何一般性声明。

    >在第6段中、LPM0看起来会在 ISR 进入时终止、因此无需 LPMx 退出语句。
    ISR 处理清除 SR 中的 CPUOFF、以便 ISR 可以运行。 堆叠的 SR (步骤3)仍然设置了 CPUOFF。 这是一项功能。
    如果要唤醒 main、则需要清除堆栈式 SR ("_ON_EXIT")中的 CPUOFF。