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] [常见问题解答] MSP430f6779 电源监测器中断服务例程 SVSH 和 SVSL

Other Parts Discussed in Thread: MSP430F6779, MSP-FET

器件型号:MSP430f6779

主题中讨论的其他器件:MSPWAREMSP-EXP430F5529MSP430F6779AMSP-FET

问:我想检测电源电压下降并将数据写入内部闪存。

实际遇到的问题是,我的代码会在上电时而不是断电时进入 ISR。

以下是我的代码 

 

#include <msp430.h> 
 
/*
 * main.c
 */
void write_SegC(void);
void copy_from_FlashC(void);
void PMM_config(void);
void UCS_config(void);
 
char Flash_Data[20] = {0,0,3,4,5,6,7,8,0,0,0,5,5,5,0,8,8,9,2,3};
char Flash_Data1[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 
int main(void) {
         WDTCTL = WDTPW | WDTHOLD;      // 停止看门狗计时器
         P1DIR |= BIT0;
         P1REN |= BIT6;
         UCS_config();
        PMM_config();
        UCS_config();
while(1)
{
 
   copy_from_FlashC();
}
return 0;
}
void copy_from_FlashC(void)
   {
       unsigned int i;
       char *Flash_ptrC;
   //   char *Flash_ptrD;
 
       Flash_ptrC = (char *) 0x1880;           // 初始化闪存段 C ptr
 
 
       // Flash_ptrD = (char *) 0x1800;           // 初始化闪存段 D ptr
     //   Flash_ptrD = (char*) Flash_Data[0];
 
       FCTL3 = FWKEY;                         // 清除锁定位
     // FCTL1 = FWKEY | ERASE;                 // 设置擦除位
     //   *Flash_ptrD = 0;                       // 虚拟写入以擦除闪存段 D
     // FCTL1 = FWKEY | WRT;                   // 为写入操作设置 WRT 位
       FCTL1 = FWKEY;
       FCTL4 = FWKEY | MGR0 ;
 
       for (i = 0; i < 20; i++)
       {
       //     *Flash_ptrD++ = *Flash_ptrC++;     // 将值段 C 复制到段 D
               Flash_Data1[i] = *Flash_ptrC++;
       }
 
       FCTL1 = FWKEY;                         // 清除 WRT 位
       FCTL3 = FWKEY | LOCK;                   // 设置锁定位
    }
 
 
   void write_SegC(void)
   {
       P1OUT |= BIT0;
 
       unsigned int i;
       char *Flash_ptr;                       // 初始化闪存指针
 
       Flash_ptr = (char *)0x1880;
 
       FCTL3 = FWKEY;                         // 清除锁定位
       FCTL1 = FWKEY | ERASE;                 // 设置擦除位
       *Flash_ptr = 0;                         // 虚拟写入以擦除闪存段
       FCTL1 = FWKEY | WRT;                   // 为写入操作设置 WRT 位
 
 
       for (i = 0; i < 20; i++)
       {
           *Flash_ptr++ = Flash_Data[i];             // 将值写入闪存
       }
 
       FCTL1 = FWKEY;                         // 清除 WRT 位
       FCTL3 = FWKEY | LOCK;                   // 设置锁定位
       P1OUT &= ~BIT0;
   }
   void PMM_config(void)
   {
       //解锁 PMM
         PMMCTL0_H=PMMPW_H;
         PMMCTL0_L|=PMMCOREV_3;
         //检查电压电平
         switch(PMMCTL0&PMMCOREV_3)
         {
           //最高内核电压设置
           case PMMCOREV_3:
             //设置高侧监控器和监测器
             SVSMHCTL=SVMHE|SVSHE|SVSHRVL_3|SVSMHRRL_7;
           break;
         }
         //清除中断标志
         PMMIFG&=~(SVMLIFG|SVMHIFG|SVMHVLRIFG|SVMLVLRIFG);
         //设置中断
         PMMRIE|=SVMLIE|SVMHIE|SVMHVLRIE|SVMLVLRIE;
         //锁定 PMM
         PMMCTL0_H=0;
   }
#pragma vector = SYSNMI_VECTOR
__interrupt void SYS_NMI(void)
{
 switch(SYSSNIV)
        {
               //内核电源电压监测器中断
               case SYSSNIV_SVMLIFG:
                //报告错误的事件
                //设置标志
               break;
               //输入电源电压监测器中断
               case SYSSNIV_SVMHIFG:
                        write_SegC();
               //       Clear_SegC(value);             // 仅用于测试
                       //报告错误的事件
                //设置标志
               break;
               //内核电源电压监测器延迟中断
               case SYSSNIV_DLYLIFG:
               break;
               //中断电源电压监测器延迟中断
               case SYSSNIV_DLYHIFG:
               break;
               //空内存访问中断
               case SYSSNIV_VMAIFG:
               break;
               //JTAG 邮箱输入中断
               case SYSSNIV_JMBINIFG:
               break;
               //JTAG 邮箱输出中断
               case SYSSNIV_JMBOUTIFG:
               break;
               //SVMLVLRIFGSVMHVLRIFG
               case SYSSNIV_VLRLIFG:
                //清除中断标志位
                //解锁 PMM
                PMMCTL0_H=PMMPW_H;
                //清除中断标志
                PMMIFG&=~(SVMLIFG|SVMLVLRIFG);
                //锁定 PMM
                PMMCTL0_H=0;
               break;
               //SVMHVLRIFGSVMHVLRIFG
               case SYSSNIV_VLRHIFG:
                //清除中断标志位
                //解锁 PMM
                PMMCTL0_H=PMMPW_H;
                //清除中断标志
                PMMIFG&=~(SVMHIFG|SVMHVLRIFG);
                //锁定 PMM
                PMMCTL0_H=0;
               break;
        }
}
 
void UCS_config(void)
{
               PMMCTL0_H = 0xA5;
               PMMCTL0_L = 0x03;
               UCSCTL0 = UCSCTL0 | 0x1F00;
               UCSCTL1 = UCSCTL1 & 0x0000;
               UCSCTL1 = UCSCTL1 | 0x0040;
               UCSCTL2 = UCSCTL2 & 0x0000 ; // FLL 分频器
               UCSCTL2 = UCSCTL2 | 0x304F ; // 对于 20MHz MCLK 和 2.6MHz SMCLK
               UCSCTL3 = 0x0000;
 
               UCSCTL4 = UCSCTL4 & 0X0000;
               UCSCTL4 = UCSCTL4 | 0X0043;
}


答:在我的代码中(见下文),当 DVCC 达到或低于 2.7V 时,LED 会闪烁;超过 2.7V 时,LED 将一直亮着。接下来,我将介绍代码的工作方式。

当电路板初次上电时,DVCC 设置为 3.0V。然后,使用外部工作台电源将 DVCC 降低至 2.7V(或稍微更低,但高于 2.4V 限值)。当 SVMHIFG 发生高电平(SVSMHRRL 指定的电平)触发时,将进入 ISR 并手动设置一个标志。此标志会指示 main() 开始使 LED 闪烁。在您的设计中,您可以使用此标志指示是否出现电源故障。请注意,在 ISR 中读取中断矢量 SYSSNIV 时,SVMHIE 被禁用(如用户指南中的表 2-22 所述)。在我意识到这一点之前,我的代码只会检测电源电压的第一次下降。如图 2-5 所示,禁用的 SVMHIE 会阻止 SVMH 中断发生,从而阻止进入 ISR!SVMHIE 稍后将重新启用。

接下来,我将 DVCC 从 2.7V 重新增大到 3.0V。这将触发 SVMHVLRIFG,并会重新进入 ISR。此时将会打开 PMM 寄存器以进行写入访问,清除 SVMHIFG 和 SVMHVLRIFG,重新启用 SVMHIE 和 SVMHVLRIE,关闭 PMM 寄存器,并手动设置一个标志以显示 SVMH 已复位。现在,LED 停止闪烁并一直亮着。该操作可不断重复。

此外,无论是否连接了 MSP-FET,此代码都能正常工作。如有任何问题,请告诉我,我希望这有助于您快速入门。

#include "driverlib.h"

 

uint16_t status = STATUS_SUCCESS;

static volatile int isr_was_entered = 0;

 

void UCS_config(void);

void PMM_config(void);

 

void main(void) {

      //停止 WDT

   WDT_A_hold(WDT_A_BASE);

 

   //将 VCore 更改为 3 级,此函数负责处理增量步骤

   status = PMM_setVCore(PMMCOREV_3);

 

   //设置 UCS

   UCS_config();

 

   //配置 PMM SVMH 以检测 DVCC 压降,SVMH 在 2.7V 时触发

   PMM_config();

 

   //将 P1.0 (LED) 设置为输出方向

   P1DIR |= 0x01;

 

   while(1) {

 

     //如果在 2.7V 时触发 SVMH,则开始使 LED 闪烁

     if(isr_was_entered == 4) {

 

           //切换 LED

           P1OUT ^= 0x01;

           __delay_cycles(800000);

     }

 

     //如果不是,仅使 LED 常亮

     else {

 

           //当 DVCC 高于 SVMH 时打开 LED

           P1OUT |= 0x01;

     }

   }

}

 

void UCS_config(void) {

 

      UCSCTL0 = UCSCTL0 | 0x1F00;

      UCSCTL1 = UCSCTL1 & 0x0000;

      UCSCTL1 = UCSCTL1 | 0x0040;

      UCSCTL2 = UCSCTL2 & 0x0000 ; //FLL 分频器

      UCSCTL2 = UCSCTL2 | 0x304F ; //对于 20MHz MCLK 和 2.6MHz SMCLK

      UCSCTL3 = 0x0000;

      UCSCTL4 = UCSCTL4 & 0X0000;

      UCSCTL4 = UCSCTL4 | 0X0043;

}

 

void PMM_config(void) {

      uint16_t PMMRIE_backup, SVSMHCTL_backup, SVSMLCTL_backup;

 

      //检查 VCore 电平

      switch(PMMCTL0&PMMCOREV_3) {

 

            //最高 VCore 电压的设置

            case PMMCOREV_3:

 

                  //用于增加 Vcore 的代码流已被更改以便解决

                  //错误 FLASH37。

                  //请参阅勘误表以了解是否特定器件受到影响

                  //请勿更改此函数

 

                  //打开 PMM 寄存器以进行写入访问

                  HWREG8(PMM_BASE + OFS_PMMCTL0_H) = 0xA5;

 

                  //备份原始寄存器设置并禁用中断

                  PMMRIE_backup = HWREG16(PMM_BASE + OFS_PMMRIE);

                  HWREG16(PMM_BASE + OFS_PMMRIE) &= ~(SVMHVLRPE | SVSHPE | SVMLVLRPE |

                                                                        SVSLPE | SVMHVLRIE | SVMHIE |

                                                                        SVSMHDLYIE | SVMLVLRIE | SVMLIE |

                                                                        SVSMLDLYIE

                                                                        );

                  SVSMHCTL_backup = HWREG16(PMM_BASE + OFS_SVSMHCTL);

                  SVSMLCTL_backup = HWREG16(PMM_BASE + OFS_SVSMLCTL);

 

                  //清除中断标志

                  HWREG16(PMM_BASE + OFS_PMMIFG) = 0;

 

                  //根据 VCore 将 SVM 高侧设置为新电平,SVSMRRL_5 = 2.7V(典型值)

                  //请参阅 MSP430F6779 数据表中的第 71 页以了解更多信息

                  //HWREG16(PMM_BASE + OFS_SVSMHCTL) = SVMHE | SVSHE | SVSMHRRL_5;

                  HWREG16(PMM_BASE + OFS_SVSMHCTL) = SVMHE | SVSMHRRL_5;

 

                  //等到 SVM 高侧稳定

                  while((HWREG16(PMM_BASE + OFS_PMMIFG) & SVSMHDLYIFG) == 0) {

                        ;

                  }

 

                  //清除所有标志

                  HWREG16(PMM_BASE + OFS_PMMIFG) &= ~(SVMHVLRIFG | SVMHIFG | SVSMHDLYIFG |

                                                                        SVMLVLRIFG | SVMLIFG | SVSMLDLYIFG

                                                                        );

 

                  //恢复 PMM 中断使能寄存器并启用 SVM 高侧中断

                  HWREG16(PMM_BASE + OFS_PMMRIE) = PMMRIE_backup | SVMHVLRIE | SVMHIE;

 

                  //锁定 PMM 寄存器以进行写入访问

                  HWREG8(PMM_BASE + OFS_PMMCTL0_H) = 0x00;

 

                  break;

      }

}

 

#pragma vector = SYSNMI_VECTOR

__interrupt void SYSNMI_ISR(void) {

 

      //根据中断执行某项操作

      switch(SYSSNIV) {

 

            //内核电源电压监测器中断

            case SYSSNIV_SVMLIFG:

 

                  //报告错误的事件

                  //设置标志

 

            break;

 

            //输入电源电压监测器中断

            case SYSSNIV_SVMHIFG:

                  //write_SegC();

                  //Clear_SegC(value);           // 仅用于测试

 

                  //设置标志以显示 SVMH 已被触发

                  isr_was_entered = 4;

 

                  //报告错误的事件

                  //设置标志

            break;

 

            //内核电源电压监测器延迟中断

            case SYSSNIV_DLYLIFG:

 

            break;

 

            //中断电源电压监测器延迟中断

            case SYSSNIV_DLYHIFG:

 

            break;

 

            //空内存访问中断

            case SYSSNIV_VMAIFG:

 

            break;

 

            //JTAG 邮箱输入中断

            case SYSSNIV_JMBINIFG:

 

            break;

 

            //JTAG 邮箱输出中断

            case SYSSNIV_JMBOUTIFG:

 

            break;

 

            //SVMLVLRIFG

            case SYSSNIV_VLRLIFG:

 

            break;

 

            //SVMHVLRIFG

            case SYSSNIV_VLRHIFG:

 

                  //打开 PMM 寄存器以进行写入访问

                  HWREG8(PMM_BASE + OFS_PMMCTL0_H) = 0xA5;

 

                  //清除 SVMH 中断标志

                  HWREG16(PMM_BASE + OFS_PMMIFG) &= ~(SVMHIFG | SVMHVLRIFG);

 

                  //重新启用 SVMH 中断标志(必须在清除中断后完成)

                  HWREG16(PMM_BASE + OFS_PMMRIE) |= SVMHIE | SVMHVLRIE;

 

                  //锁定 PMM 寄存器以进行写入访问

                  HWREG8(PMM_BASE + OFS_PMMCTL0_H) = 0x00;

 

                  //设置标志以显示 SVMH 已复位

                  isr_was_entered = 3;

 

            break;

    }

}