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.

[FAQ] MSP430 System Reset 事件处理

Other Parts Discussed in Thread: MSP430F5529

MSP430提供了许多系统复位中断事件,包括掉电复位(BOR),看门狗超时(WDTTO)或高侧电源电压监控(SVSH)等。

发生复位时,复位原因由MSP430 CPU的系统System peripheral (SYS)来记录。像MSP430上的其他分组中断一样,您可以通过读取相关的中断向量寄存器来确定是哪个事件导致了中断,即查看寄存器称为SYSRSTIV(系统复位中断向量)。

中断向量寄存器根据发生的最高优先级事件返回一个数字。例如,对于MSP430F5529上的SYSRSTIV,事件(和关联的枚举)包括:

注意:请查看设备的相关用户指南和数据表,以获取准确的SYSRSTIV寄存器描述。 

1.    读取SYSRSTIV寄存器

在MSP430上处理分组中断的最常见方法是使用switch-case语句读取关联的中断向量寄存器,以获取当前待处理的最高优先级事件。

MSP430F5529 的SYSRSTIV如下所示:

switch ( __even_in_range( SYSRSTIV, SYSRSTIV_PMMKEY ) )

{

    case SYSRSTIV_NONE:          break;       // No Interrupt pending

    case SYSRSTIV_BOR:           break;       // SYSRSTIV : BOR

    case SYSRSTIV_RSTNMI:        break;       // SYSRSTIV : RST/NMI

    case SYSRSTIV_DOBOR:         break;       // SYSRSTIV : Do BOR

    case SYSRSTIV_LPM5WU:        break;       // SYSRSTIV : Port LPM5 Wake Up

    case SYSRSTIV_SECYV:         break;       // SYSRSTIV : Security violation

    case SYSRSTIV_SVSL:          break;       // SYSRSTIV : SVSL

    case SYSRSTIV_SVSH:          break;       // SYSRSTIV : SVSH

    case SYSRSTIV_SVML_OVP:      break;       // SYSRSTIV : SVML_OVP

    case SYSRSTIV_SVMH_OVP:      break;       // SYSRSTIV : SVMH_OVP

    case SYSRSTIV_DOPOR:         break;       // SYSRSTIV : Do POR

    case SYSRSTIV_WDTTO:         break;       // SYSRSTIV : WDT Time out

    case SYSRSTIV_WDTKEY:        break;       // SYSRSTIV : WDTKEY violation

    case SYSRSTIV_KEYV:          break;       // SYSRSTIV : Flash Key violation

    case SYSRSTIV_FLLUL:         break;       // SYSRSTIV : FLL unlock

    case SYSRSTIV_PERF:          break;       // SYSRSTIV : peripheral/config area fetch

    case SYSRSTIV_PMMKEY:        break;       // SYSRSTIV : PMMKEY violation

    default:                     break;

}

2.    在何处使用IV switch-case语句?

如果您已经编写了switch-case语句来处理诸如GPIO端口或计时器之类的中断,那么您应该已经知道如何使用它们。下面是处理GPIO中断的示例。

通常,可以在中断服务程序内部找到switch-case语句。您可以通过执行以下两项操作来创建中断服务程序:

(1)使用__interrupt关键字创建中断函数;

(2) vector pragma会告知MSP430代码生成工具将下一个函数的地址放入中断向量表中。

#pragma vector=PORT1_VECTOR

__interrupt void pushbutton_ISR (void) { switch(__even_in_range( P1IV, 10 ))

{                

     case 0x00: break; // None

     case 0x02: break; // Pin 0

     case 0x04: break; // Pin 1

     case 0x06: break; // Pin 2

     case 0x08: break; // Pin 3

     case 0x0A: break; // Pin 4

     case 0x0C: break; // Pin 5

     case 0x0E: break; // Pin 6

     case 0x10: break; // Pin 7

     default: _never_executed();

     GPIO_toggleOutputOnPin( GPIO_PORT_P1, GPIO_PIN0 );

     break;

}

另外由于在运行中断服务程序(ISR)时会禁用中断(默认情况下),因此当您的中断响应代码不仅仅是简单地读取或写入寄存器时,您需要格外小心。如果您的代码涉及更多功能,我们强烈建议您在

ISR函数中设置一个标志,并在main()中处理该事件。

3.    在何处处理SYSRSTIV?

一般来说,第一反应可能是创建一个复位ISR功能,类似于上面显示的G​​PIO中断示例。但实际上这是不能成功的,主要是因为编译器会忽略下面的语句:

#pragma vector=RESET_VECTOR

即使设备头文件定义了RESET_VECTOR,编译器仍会忽略编译指示。复位向量由C编译器使用函数c_int00()自动处理。该函数会处理各种事情,例如设置堆栈和堆,初始化全局变量和静态变量以及branch到main()。由于用户不会重写此功能,因此最好让编译器忽略RESET_VECTOR #pragma。(您可以在编译器的运行时支持(RTS)库附带的源文件boot.c中找到此函数)

处理SYSRSTIV的最简单方法是将代码放在main()函数的开头。在例子中创建了一个Reset_ISR()函数并从main()调用,如下所示:

void main (void) {

    // Stop watchdog timer

   WDT_A_hold(WDT_A_BASE);

   // Determine the cause of previous reset event

   RESET_ISR();

   // Initialize GPIO

   initGPIO();

   while( 1 )

   {

       __no_operation();

   }

}

 

 

void Reset_ISR(void) {

   switch (__even_in_range(SYSRSTIV, SYSRSTIV_PMMKEY))

   {

       case SYSRSTIV_NONE:                       // No Interrupt pending

                               __no_operation();

                               break;

       case SYSRSTIV_BOR:                        // SYSRSTIV : BOR

                               __no_operation();

                               break;

       case SYSRSTIV_RSTNMI:                     // SYSRSTIV : RST/NMI

                               __no_operation();

                               break;

       case SYSRSTIV_DOBOR:                      // SYSRSTIV : Do BOR

                               __no_operation();

                               break;

       case SYSRSTIV_LPM5WU:                     // SYSRSTIV : Port LPM5 Wake Up

                               __no_operation();

                               break;

       case SYSRSTIV_SECYV:                      // SYSRSTIV : Security violation

                               __no_operation();

                               break;

       case SYSRSTIV_SVSL:                       // SYSRSTIV : SVSL

                               __no_operation();

                               break;

       case SYSRSTIV_SVSH:                       // SYSRSTIV : SVSH

                               __no_operation();

                               break;

       case SYSRSTIV_SVML_OVP:                   // SYSRSTIV : SVML_OVP

                               __no_operation();

                               break;

       case SYSRSTIV_SVMH_OVP:                   // SYSRSTIV : SVMH_OVP

                               __no_operation();

                               break;

       case SYSRSTIV_DOPOR:                      // SYSRSTIV : Do POR

                               __no_operation();

                               break;

       case SYSRSTIV_WDTTO:                      // SYSRSTIV : WDT Time out

                               __no_operation();

                               break;

       case SYSRSTIV_WDTKEY:                     // SYSRSTIV : WDTKEY violation

                               __no_operation();

                               break;

       case SYSRSTIV_KEYV:                       // SYSRSTIV : Flash Key violation

                               __no_operation();

                               break;

       case SYSRSTIV_FLLUL:                      // SYSRSTIV : FLL unlock

                               __no_operation();

                               break;

       case SYSRSTIV_PERF:                       // SYSRSTIV : peripheral/config area fetch

                               __no_operation();

                               break;

       case SYSRSTIV_PMMKEY:                     // SYSRSTIV : PMMKEY violation

                               __no_operation();

                               break;

       default: break;

   }

}

您可以在上面的__no_operation()处来替换为具体应用程序所需的代码。

注意:编译器提供了一种将代码插入c_int00()重置函数的方法。如果定义的话,则重置函数将调用名为_system_pre_init()的函数。尽管我们的首选是显式地处理main()中的reset event,但是如果有必要,使用pre-init函数可以使您更早地处理事件。