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.

[参考译文] MSP430FR5994:异常处理程序(以及 TI 与 GCC)

Guru**** 2391355 points
Other Parts Discussed in Thread: MSP-EXP430FR5994, MSP430FR5994

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1002284/msp430fr5994-exception-handlers-and-ti-vs-gcc

器件型号:MSP430FR5994
主题中讨论的其他器件:MSP-EXP430FR5994

作为 TI MSP430/CCS 环境的新手、请原谅一个天真的问题!

简式:

我编写了一个在使用 TI C 编译器编译时能够正确执行的应用程序。  但是、当使用 GCC 编译时、它会失败、最后我假设在0x8000 (JMP 0x0000)处有一个异常。  因此、我有三个相关问题:

  • GCC 编译器会导致 TI 编译器无法解决的问题、这是什么?
  • 0x80000是特殊地址、还是它只是从存储器末尾运行(为什么?)
  • 从何处了解有关异常处理(及其调试)的更多信息?

一些详细信息:

它似乎在延迟环路内发生故障、即(有效):

set_led_on();
while (get_counter() < desired) {
  asm("nop");
}
set_led_off();

如果延迟很短、我就不会得到例外。  一旦发生异常、我会看到 LED 定期闪烁、调试器不再处于控制状态、这意味着处理器将持续复位。  我已禁用 WDT 并在进入循环之前验证 WDTHOLD 是否设置为1、因此这不是问题所在。

我在 CCS 10.3.1.00003中使用 GNU v9.3.1.11 (Mitto Systems Limited)编译器。  正如我提到过的、我在使用 TI v20.2.5LTS 时没有看到这个问题。

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

    该短代码位中没有任何会导致问题的地方。 因此、您可能还没有详细介绍过这一点。

    我使用 GCC 编译器、从未使用过 TI 编译器或此 CCS。

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

    您好!

    我怀疑您使用了错误的链接文件。 对于 CCS、当您使用 GCC 和 TI 编译器时、它将使用不同的链接文件格式。 通常、您不需要更改默认值。 请检查设置并从 Resource Explorer 导入示例工程、并比较编译器设置。  

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

    李霍肯:

    我注意到、如果您使用一个编译器构建工程、则无法(成功)通过 Project =>属性设置切换到另一个编译器。

    相反、似乎有必要继续使用工程编译器。

    我将尝试创建我的应用程序的精简版本--从一个示例项目开始--以便我们能够更好地了解正在发生的情况。

    感谢您提供信息。  我将告诉您发生了什么。

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

    @David Schutlz36:好的一点。  我开始认为这可能是 CCS 问题、而不是代码问题。  (见下文霍肯·李的答复。)

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

    我将包括一个完整的测试计划来演示此问题。

    复制:

    首先在 TI 编译器下进行验证:

    1. 在 CCS 10.3.1中、File => New => CCS Project
    2. 将项目 timer_test_ti 命名为、然后选择 TI v20.5.2LTS 作为编译器
    3. 将 main.c 的内容替换为以下提供的代码
    4. 在 MSP-EXP430FR5994开发板的调试器下编译并运行

    观察:LED 每5秒亮起和熄灭一次。

    现在在 GCC 编译器下进行测试:

    1. 在 CCS 10.3.1中、File => New => CCS Project
    2. 将项目 timer_test_gcc 命名并选择 GNU v9.3.1.11作为编译器
    3. 将 main.c 的内容替换为以下提供的代码
    4. 在 MSP-EXP430FR5004开发板的调试器下编译和运行

    观察:LED 亮起、但在熄灭之前、程序崩溃。  暂停调试器会显示消息"break at address "0x4"、no debug information available、or outside of program code (在地址"0x4"处中断、没有可用的调试信息或程序代码之外)"。

    有趣的是、如果在第81行对 SET_LED_(false)的调用中放置断点、则会看到它在到达前崩溃。  但是,如果您在前面的 NOP (while ()循环内部)上放置一个断点,它会在崩溃之前执行 NOP 的次数是不确定的。

    测试代码:

    (另外,尝试将其作为代码插入会导致服务器错误:您没有权限...,因此我将其内联插入)

    /**
     *@文件 timer_test.c
     *
     *验证在 TI 编译器下编译的 MSP430FR5994的简单程序
     和 GCC 编译器。
     *
     * RDP、2021年5月
     *
     *此文件将作为两个 Code Composer Studio 项目的一部分提供:
     *一个使用 TI 编译器编译、另一个使用 GCC 编译器编译。
     *在 MSP-EXP430FR5994开发板上编译和测试代码。  您
     *应每5秒打开和关闭一次 LED。
     *
     *但是、它似乎在 TI 编译器下工作、但在编译时崩溃
     *在 GCC 编译器下。
     *

    //===========================================================================================================================================
    //包括

    #include
    #include
    #include
    #include

    //===========================================================================================================================================
    //定义和类型

    #define RTC_FREQUENCY 32768L
    #define MS_PER_second 1000L
    #define MS_TO_DURATION (ms)((uint32_t)((ms * RTC_FREQUENCY)/ MS_PER_second)

    //===========================================================================================================================================
    //转发声明

    静态空 set_led (bool on);
    静态空 init_gpos (void);

    静态 void init_buttons (void);
    static void on_button1_press (void);
    static void on_button2_press (void);

    静态空 init_timer (void);
    uint32_t get_time (void);         //获取当前时间作为32位值
    静态 uint16_t get_timer_l (void);
    静态 void ON_TIMER_overflow (void);


    //===========================================================================================================================================
    //本地存储

    /**
     *@brief s_timer_h 保存32位计时器/计数器的高位16位。
     *每次16位 TA0计时器溢出时、它都会递增。
     *
    静态 uint16_t s_timer_h;

    //===========================================================================================================================================
    //主代码

    /**
     * main.c
     *
    int main (void){
     WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器
     init_gpiso();
     init_buttons();
     init_timer();
     _enable_interrupt ();

     while (true){
       uint32_t 至;

       SET_LEed (真);
       printf ("LED 应亮起5秒:\n"\});
       直到= get_time()+ ms_TO_DURATION (5000);
       while (get_time ()<至){
         asm (" nop");
       }

       set_led (false);
       printf ("LED 应关闭5秒:\n"\});
       直到= get_time()+ ms_TO_DURATION (5000);
       while (get_time ()<至){
         asm (" nop");
       }
     }
     返回0;


    //===========================================================================================================================================
    //本地代码

    //================================================================
    //管理 GPIO

    /**
     *@简要初始化 GPIO
     *
    静态空 init_gpiso(){
     //将所有未使用的 GPIO 配置为输出以节省功耗。
     P1OUT =(0x00);
     P1DIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT7);
     // P2.0配置为 UART TX
     // P2.1配置为 UART RX
     P2OUT =(0x00);
     P2DIR =(BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT6);
     P2SEL0 &=~(BIT0 | BIT1);
     P2SEL1 |=(BIT0 | BIT1);
     P3OUT =(0x00);
     P3DIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT4);
     P4OUT =(BIT5);
     P4DIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT4);
     // P5.5配置为 SW2,输入上拉
     // P5.6配置为 SW1,输入上拉
     P5OUT =(BIT5 | BIT6);
     P5DIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT7);
     P5REN |=(BIT5 | BIT6);
     P6OUT =(0x00);
     P6DIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT7);
     P7OUT =(0x00);
     P7DIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT7);
     P8OUT =(0x00);
     P8DIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT7);
     PJOUT =(0x00);
     PJDIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT4);

     //禁用 GPIO 上电默认高阻抗模式以激活
     //先前配置的端口设置(由于我们重新
     //启动时初始化所有 GPIO ...)
     PM5CTL0 &=~LOCKLPM5;


    /**
     *@简要设置演示 LED 亮起或熄灭。
     *
    静态空 set_led (bool on){
     如果(开){
       P1OUT |= BIT0;
     }否则{
       P1OUT &=~BIT0;
     }


    //================================================================
    //管理按钮

    静态空 init_buttons (void){
     //为中断配置 SW1和 SW2
     P5IES =(BIT5 | BIT6);//高/低边沿
     P5IFG = 0;            //清除标志
     P5IE =(BIT5 | BIT6); //中断被启用


    static void on_button1_press (void){asm (" nop");}

    static void on_button2_press (void){asm (" nop");}

    //按钮的端口4中断服务例程
    #if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
    #pragma vector = PORT5_vector
    _interrupt void Port_5 (void)
    #Elif defined (_GNU_)
    void __attribute__((中断(PORT5_vector))) Port_5 (void)
    其他
    错误编译器不受支持!
    #endif

     IF (P5IFG 和 BIT6){
       on_button1_press ();
       P5IFG &=~BIT6;//清除 IFG
     }
     IF (P5IFG 和 BIT5){
       on_button2_press ();
       P5IFG &=~BIT4;//清除 IFG
     }
     _BIC_SR_REGISTER_ON_EXIT (LPM3_BITS);//退出 LPM3


    //================================================================
    //时间管理。

    /**
     * @简要 TA0配置为连续递增模式、时钟频率为32KHz。 一个
     * 16位计数器、它将每(2^16)/32768 = 2秒溢出一次。  。
      溢出中断将使 s_timer_h 递增、我们将其用作高位
     32 位复合计数器的* 16位。
     *

    静态空 init_timer(){
     TA0CTL = tassel__ACLK |  // 32768Hz 源
              MC__Continuous |//连续模式
              TAIE |          //溢出中断
              0;              // TACLR;
     S_TIMER_h = 0;


    /**
     *@brief 返回自重新启动以来32KHz 的节拍数(作为32位值)。
     *
    uint32_t get_time (void){
     uint16_t timer_h;
     uint16_t timer_l;

     执行{
       //对计时器的高位和低位进行快照
       Timer_h = s_timer_h;
       timer_l = get_timer_l ();
       //仅当高阶字未更改时,快照才有效
     } while (timer_h!= s_timer_h);

     //将高16位和低16位的快照组合为32位值。
     返回((uint32_t) timer_h << 16)|(timer_l);


    /**
     *@简要阅读16位计时器
     *
    静态 uint16_t get_timer_l (void){return TA0R;}

    /**
     *@在定时器溢出时的简短说明、使高位16位递增(在中断 lvl 上)
     *
    静态空 ON_TIMER_OVERflow (void){s_timer_h += 1;}

    //计时器溢出中断服务例程
    #if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
    #pragma vector = TIMER0_A1_vector
    _interrupt void 计时器(void)
    #Elif defined (_GNU_)
    void __attribute__((interrupt (TIMER0_A1_vector)) Timer_A0 (void)
    其他
    错误编译器不受支持!
    #endif

     ON_TIMER_overflow();
     TA0CTL &=~TAIFG;                    //清除中断标志
     _BIC_SR_REGISTER_ON_EXIT (LPM3_BITS);//退出 LPM3

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

    两个更新:

    我意识到静态 uint16_t s_timer_h;应标记为易失性。  在做出这一更改后,行为没有变化-- GCC 版本仍然崩溃。

    我比较了这两个项目。  如预期(并视情况而定)、GCC 工程有一个名为 msp430fr5994.ld 的链接器文件、而 TI 工程有一个名为 lnk_msp430fr5994.cmd 的链接器文件。

    因此、我相信这两个项目的链接器文件都是正确的。

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

    我看不到任何可能会给您带来麻烦的东西。 其他问题(请参阅在25.2.1中有关读取 TAxR 的说明)、但没有危险信号。

    当情况不同时、使用调试器检查系统状态。 堆栈框可能会提供线索。 如果所有其他操作都失败、请比较两个编译器生成的汇编代码。

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

    @David Schultz36:感谢您的建议。  当我来自 ARM 世界时、我应该检查哪些寄存器何时发生了分离(您会在这些寄存器中查找什么)?

    同时、我将了解如何让 CCS 发出汇编代码...

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

    它不是您想要查看的寄存器、因为它是堆栈帧。 这将提供程序所在位置的记录。

    我使用 objdump (msp430-elf-objdump -S)查看 gcc .elf 文件输出中的内容。 我用您的代码执行了该操作、没有发现任何明显的问题。 (我没有用于运行它的 fr5994。) 除了您提到的这个易失性问题。 静态的无理使用会使事情复杂化、因为这会使 gcc 不使用标签。 优化还可以通过多种方式掩盖程序流、包括内联函数。 当我感到非常困惑时、我移除了该开关。 (我的默认值为"-O2"。)

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

    我不经常在 MSP430上使用 GCC、但使用 CCS v8.3 (GCC v7.3.2.154 [Mito])运行此程序似乎可以。

    黑暗中的一些画面:

    1) 1)如果您删除 printf()调用,它是否会更改任何内容? 我模糊地回顾,CCS 和 GCC 使用不同的机制。

    2) 2)检查堆栈大小。 我认为堆栈从__heap_end__扩展到了__stack (请参阅.map 文件)。

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

    嗯、对于它的价值、我运行的是更新的 CCS 和更新的 GCC。  关于黑暗中的照片:

    真正奇怪的是,它位于 while ()循环内,在 printf()之后。  通过在循环内的 NOP 指令上放置一个断点、似乎可以在发生故障前将循环运行30到50次(随机)之间的任意位置。

    当它失败时,它最终位于地址0x4,即"JMP"。 环路。  堆栈位于顶层、因此在跳到该堆栈之前、没有什么有趣的东西可以看出来它是如何调用的。

    从.map 文件:

    • _heap_end = 0x1dc2
    • _stack = 0x2c00

    在 while ()循环内部(以及失败时)、SP 为0x2bf4、因此没有堆栈溢出的证据。

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

    请删除 printf(),然后重试。 我非常怀疑 gcc 中的 printf 调用可能不包含特殊命令'\n'。  

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

    我删除了对 printf()的调用。  程序仍然以相同的方式失败。

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

    以下是代码的大幅缩减版本。  运行时、跳转至未初始化的存储器、失败:

    • PC = 0x0A0058 (=>0x3FFF、或"JMP .")
    • SP = 0x002BF4 (看起来合理)
    • SR = 0x0

    (除了:当我尝试插入时 代码,我仍然收到错误消息:您无权访问此服务器上的">e2e.ti.com/.../configure。因此我将插入内联。)

    在 NOP 上使用跳过计数设置断点时、可以看到 NOP 在挂起前随机执行了数次:在我最近的测试中执行了28次。

    /**
     *@文件 timer_test.c
     *
     *验证在 TI 编译器下编译的 MSP430FR5994的简单程序
     和 GCC 编译器。
     *
     * RDP、2021年5月
     *
     *此文件将作为两个 Code Composer Studio 项目的一部分提供:
     *一个使用 TI 编译器编译、另一个使用 GCC 编译器编译。
     *在 MSP-EXP430FR5994开发板上编译和测试代码。  您
     *应每5秒打开和关闭一次 LED。
     *
     *但是、它似乎在 TI 编译器下工作、但在编译时崩溃
     *在 GCC 编译器下。
     *

    //===========================================================================================================================================
    //包括

    #include
    #include

    //===========================================================================================================================================
    //定义和类型

    #define RTC_FREQUENCY 32768L
    #define MS_PER_second 1000L
    #define MS_TO_DURATION (ms)((uint32_t)((ms * RTC_FREQUENCY)/ MS_PER_second)

    //===========================================================================================================================================
    //本地存储

    /**
     当16位 TA0定时器溢出时、*@brief 在中断级别递增、
     * s_timer_h 表示32位计时器/计数器的高序16位。
     *
    volatile uint16_t s_timer_h;

    //================================================================
    //时间管理。

    /**
     * @简要 TA0配置为连续递增模式、时钟频率为32KHz。 一个
     * 16位计数器、它将每(2^16)/32768 = 2秒溢出一次。  。
      溢出中断将使 s_timer_h 递增、我们将其用作高位
     32 位复合计数器的* 16位。
     *

    void init_timer(){
     TA0CTL = tassel__ACLK |  // 32768Hz 源
              MC__Continuous |//连续模式
              TAIE |          //溢出中断
              0;              // TACLR;
     S_TIMER_h = 0;


    /**
     *@brief 返回自重新启动以来32KHz 的节拍数(作为32位值)。
     *
    uint32_t get_time (void){
     uint16_t timer_h;
     uint16_t timer_l;

     执行{
       //对计时器的高位和低位执行快照
       Timer_h = s_timer_h;// s_timer_h 在中断级别递增
       Timer_l = TA0R;     // get_timer_lo ()
       //仅当高阶字未更改时,快照才有效
     } while (timer_h!= s_timer_h);

     //将高字和低字的快照组合成32位字。
     返回((uint32_t) timer_h << 16)| timer_l;


    //计时器溢出中断服务例程
    #if defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
    #pragma vector = TIMER0_A1_vector
    _interrupt void 计时器(void)
    #Elif defined (_GNU_)
    void __attribute__((interrupt (TIMER0_A1_vector)) Timer_A0 (void)
    其他
    错误编译器不受支持!
    #endif

     //在计时器溢出时到达 ere (每2秒一次)
     S_TIMER_h += 1;                      //递增高位定时器字
     TA0CTL &=~TAIFG;                    //清除中断标志
     _BIC_SR_REGISTER_ON_EXIT (LPM3_BITS);//退出 LPM3


    //===========================================================================================================================================
    //主代码

    /**
     * main.c
     *
    int main (void){
     uint32_t 至;

     WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器

       // init_gpisoes();
       P1OUT =(0x00); //将 P1OUT.0设置为 LED 的输出
     P1DIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT7);
       PM5CTL0 &=~LOCKLPM5;

     init_timer();
     _enable_interrupt ();

     P1OUT |= BIT0;// set_led (真);

     // LED 应亮起5秒
     直到= get_time()+ ms_TO_DURATION (5000);
     while (get_time ()<至){
       asm (" nop");
     }
       //使用 GCC 编译器,从不会到达这里。
     P1OUT &=~BIT0;// set_led (false);

     返回0;

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

    首先关闭0xA0058是不存在的内存、也不是未初始化的内存、因为这个部件上只有256KB。

    我想知道您在加电默认设置下离开 MCLK 是否会有问题、但在再次阅读文档时、我发现了其他问题、因为您似乎认为 ACLK 上提供32KHz 晶振控制时钟。 您必须对时钟系统进行一些操作才能实现这一点。 下面是我对 fr5972执行的操作:

      FRCTL0 = FWPW|NWAITS_1;        // set 1 FRAM wait state
      FRCTL0_H = 0;                   // lock FRAM control
      
      CSCTL0 = CSKEY;                 // unlock clock system registers
      CSCTL1 = DCORSEL|DCOFSEL_4;     // Set DCO to 16MHz
      CSCTL2 = SELA__LFXTCLK|SELS__DCOCLK|SELM__DCOCLK; // ACLK = XT1, MCLK = DCO
      CSCTL3 = DIVA__1|DIVM__1|DIVS__16; // set clock dividers
    
      // Startup the LFXT
    
      PJSEL0 |= BIT4|BIT5;              // assign pins to oscillator
      CSCTL4 &= ~LFXTOFF;               // LFXT On
      // Wait for oscillator to start
      do {
        CSCTL5 &= ~LFXTOFFG;          // clear fault flag
        SFRIFG1 &= ~OFIFG;
      } while(SFRIFG1&OFIFG);
    
      CSCTL0_L = 0;                    // lock clock system registers
      

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

    @David Schultz36:正确初始化(或无法初始化)时钟当然会引起问题、但这会引起另外两个问题:

    • 初始化不当的时钟如何导致 PC 跳转至不存在的内存?
    • 为什么该代码在 TI 编译器下而不在 GCC 编译器下可靠地工作?  (也许 crt0启动代码不同?)

    我已经将问题代码缩减到了更小的大小、在这里、它的全部内容是:

    /**
     *@文件 timer_test.c
     *
     *此代码在由 TI 编译器编译时起作用,但在编译时会崩溃
     *由 GCC 编译器提供。
     *

    #include

    int main (void){

     WDTCTL = WDTPW | WDTHOLD;//停止看门狗计时器

     // init_gpisoes();
     P1OUT =(0x00);//将 P1OUT.0设置为 LED 的输出
     P1DIR =(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT4 | BIT6 | BIT7);
     PM5CTL0 &=~LOCKLPM5;

     // init_timer()
     TA0CTL = tassel__ACLK |  // 32768Hz 源
              MC__Continuous |//连续模式
              TACLR;          // TACLR;

     //对于0x7fff 时钟节拍,LED 应亮起
     P1OUT |= BIT0;// set_led (真);
     while (TA0R < 0x7fff){
       asm (" nop");
     }
     //使用 GCC 编译器,从不会到达这里。
     P1OUT &=~BIT0;// set_led (false);

     返回0;

    问题几乎肯定必须出现在 while (TA0R < 0x7fff)语句中、因为我看到 LED 亮起、跳过计数为100的 NOP 上的断点仅在 PC 变为无地之前30到50次被调用。

    我检查了生成的代码。  在 TI 编译器(工作案例)下,while ()循环如下所示:

    39       while (TA0R < 0x7fff){
    01001c:  90B2 7FFF 0350     CMP.W  #0x7fff、&TA0_TA0R
    010022:  2C05               JHS    (0x002e)
    40         asm (" nop");
    010024:  4303               NOP     
    39       while (TA0R < 0x7fff){
    010026:  90B2 7FFF 0350     CMP.W  #0x7fff、&TA0_TA0R
    01002c:  2BFB               JLO    (0x0024)
    43       P1OUT &=~BIT0;// set_led (false);
    01002e:

    在 GCC 下编译的相应 while ()循环(故障情况)如下所示:

    39       while (TA0R < 0x7fff){
    00402c:  421C 0350          MOV.W  &TA0_TA0R、R12
    004030:  403D 7FFE          MOV.W  #0x7ffe、R13
    004034:  9C0D               CMP.W  R12、R13
    004036:  2807               JLO    (0x4046)
    40         asm (" nop");
    004038:  4303               NOP     
    39       while (TA0R < 0x7fff){
    00403a:  421C 0350          MOV.W  &TA0_TA0R、R12
    00403E:  403D 7FFE          MOV.W  #0x7ffe、R13
    004042:  9C0D               CMP.W  R12、R13
    004044:  2FF9               JHS    (0x4038)
    004046:

    我在勘误表中没有看到任何表明 GCC 代码有问题的东西。

    更新:

    我通过 MSP430-elf-objdump 运行两个版本(TI 和 GCC)的输出、很明显、TI 版本会进行一些初始化、但 GCC 版本不会。  这可能会有很多解释。  这会导致另外一个(希望也是最后一个)问题:在哪里可以找到 TI 和 GCC 版本的启动代码?  我想验证启动代码是否考虑了差异。

    更新2:

    我将提出一个新问题("在哪里可以找到 TI 和 GCC 版本的启动代码")、因为这似乎是可能的原因、但现在它已深深地埋在这个线程中。  如果这不能解释挂起的原因、我将再次讨论这一主题。

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

    @David Schultz36:我在运行 TI 编译的代码后运行了 GCC 编译的代码,结果意外地完成了,没有崩溃。  这会影响您关于某些寄存器未正确初始化的理论。  我希望将 TI 启动代码与 GCC 启动代码进行比较、可以看出这种情况的原因。

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

    您能否将其与汇编语言进行比较、以便我们能够分析根本原因?  

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

    当然。  我有两个文件:test-gcc.objdump 是由 GCC 编译器汇编的代码、test-ti.objdump 是由 TI 编译器汇编的代码。  我可以看到 TI 版本调用__MPU_init(),而 GCC 版本不调用。

    是否有方法将文件附加到此线程?  如果没有、我只需复制并粘贴内容...

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

    可以使用“插入”->“文件”附加文件。

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

    我尝试通过 Insert => Image/video/file 附加文件、然后单击[Upload (上载)]、选择文件名、但对话框中未显示文件名、单击[OK](确定)没有效果。

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

    您好、链接器脚本可能是原因。

    MSP430-GCC-opensource:链接器脚本中缺少 GCC 9.3.0.31 .lowtext 规则

    MSP430-GCC-opensource:GCC 9.2.0.50 msp430fr5994.ld .lowtext bugfix

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

    这可以解释一些事情。  与 MSP430-GCC-opensource 中描述的原因不同:GCC 9.2.0.50 msp430fr5994.ld .lowtext bugfix、我的示例不使用 ISR。

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

    :我的已删除示例根本不使用中断、但仍然失败。  我对您提供的错误报告的理解是、它们只适用于中断处理。  我是否阅读错误?

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

    将计时器配置为使用 ACLK 会生成 ACLK 请求、这将导致振荡器故障、因为 LFXT 引脚配置为 I/O 除非 OFIE 被置位、否则这不应该生成一个中断。 文档中也有这样的描述。

    一个简单的测试是将计时器切换到 SMCLK。 或提供用户 NMI 处理程序。

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

    正确、其他错误报告与 ISR 相关。

    我刚刚尝试使用 CCS Cloud https://dev.ti.com/ide/编译您的最小示例 

    新 CCS 项目、GNU v9.3.1.11、 MSP430FR5994、
    已将其上传到 MSP-EXP430FR5994 Launchpad 上。
    红色 LED 按预期闪烁。 因此、我无法重现错误。