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.

[参考译文] MSP430FR2422:了解 LPM3.5以及如何通过 FRAM 保存/恢复变量

Guru**** 661510 points
Other Parts Discussed in Thread: MSP430FR2422, MSP-FET
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1188319/msp430fr2422-understanding-lpm3-5-and-how-to-save-restore-variables-via-fram

器件型号:MSP430FR2422
主题中讨论的其他器件: MSP-FET

您好!

我想详细了解一下 MSP430的较新 FRAM 系列、并决定使用 MSP430FR2422……

我的项目如下所示:
LoRa 模块(SX1278)通过 SPI (SPI 模式下的 UCA0)连接到 MSP430FR2422。 MSP430由 DCO (1MHz)提供时钟、RTC 由 VLO (10kHz)提供时钟。 未连接外部晶振。
一切都应该依靠电池运行数月。 主电源为3节带有 LDO 的 AAA 电池。  
因此、我决定使用低功耗模式3.5 (LPM3.5)、并且我目前每10秒唤醒一次 MSP430、使用 RTC 进行测试、以发送6字节的 LoRa 数据包。
稍后、这10秒当然会设置为更高的周期时间。

在 LPM3.5模式下、我测得的功耗为200nA (0.2uA)、这是一种奇妙的结果。  
通过 RTC 中断的唤醒也运行良好。
LoRa 接收器成功接收来自 MSP430的6个字节的数据包(在10秒内)。

问题是、只有第一个数据包的数据是正确的。  
第2个数据包中的数据不正确。 这些对我来说是完全随机的。
 
我知道 LPM3.5中的 RAM 内容丢失

在 LoRa 数据包(6字节有效载荷)内、有一个计数器应该对已经发送的数据包进行计数。
LPM3.5之后、MSP430FR2422复位、计数器值丢失或在重新启动后重新初始化...
还有一个固定的、唯一的器件 ID。  
这在重新启动后也是完全错误的。  

一般而言、我现在问自己如何正确地"保存"计数器值(变量/char 数组)。
现在有几个问题:

1.在切换到 LPM3.5 (RAM -> FRAM)之前、是否必须将整个 RAM 内容写入 FRAM? 之后、唤醒/复位后、是否从 FRAM (FRAM-RAM)恢复 RAM 内容? 或者、如果我只备份与我真正相关的数据、这是否足够? 我是否可以使用(简单)例程来备份整个 RAM?
另一个注意事项:如果我的应用仅使用200字节的 RAM、那么我只能将其存储在 FRAM 中、对吧? 或者在唤醒后以某种方式损坏 RAM 内容。


2.如果我在 CCS 下将带有#pragma PERSISTENT (x)的字符变量/数组存储在 FRAM 中、则这些变量/数组已经存储在 FRAM 中、不再需要保存、对吧? 在从 LPM3.5复位/唤醒后、计数器值不应该被复位?

3.在 CCS 11下、我使用 MSP-FET 进行调试。 到目前为止、这种方法一直很好、但 LPM3.5不能。 这是正常的还是某个位置缺少设置? 不采用 RTC ISR 中的断点。 他们看不到应用程序也会重新启动。 if 语句中用于查询中断矢量状态(决定唤醒或冷启动)的断点也不会被采用。

如果有任何提示或建议、我将不胜感激!
我自己不能再去了...

我将在这里用主例程布置 main.c。
您可能会立即发现错误。

我使用了 CCS 中未经修改的自动生成文件作为链接器文件。
(可能仍需要对此进行调整以使 FRAM 正常工作?)

非常感谢、致以最诚挚的问候
Stefan

#include "msp430.h"
#include "stdint.h"
#include "SX1278.h"

#define FIXED_PACKET_LENGTH     (6)
#define SENSOR_ID               (0x34)

// function prototypes
void initGpio(void);

#pragma PERSISTENT(LoRaPacketCount)
unsigned long LoRaPacketCount = 0;
#pragma PERSISTENT(SensorNodeID)
unsigned char SensorNodeID = SENSOR_ID;

#pragma PERSISTENT(LoRa_packet)
volatile unsigned char LoRa_packet[FIXED_PACKET_LENGTH] = {0x34, 0xFF, 0xFF, 0x00, 0x00, 0x00};          // payload of the lora packet

int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;               // Stop WDT
    initGpio();                             // Configure GPIO

    // disabling the SVS (Supply Voltage Supervisor) --> not needed
    PMMCTL0_H = PMMPW_H;
    PMMCTL0_L &= ~SVSHE;

    // First determine whether we are coming out of an LPMx.5 or a regular RESET.
    if (SYSRSTIV == SYSRSTIV_LPM5WU)        // When woken up from LPM3.5, reinit
    {
        // If MCU wakes up from LPM3.5, re-init and then return to LPM3.5 again.
        LoRaPacketCount++;               
        LoRa_packet[0] = SENSOR_ID;      // unique SensorNode ID
        LoRa_packet[1] = 0xFF;           // DS1820 temp (LSB)
        LoRa_packet[2] = 0xFF;           // DS1820 temp (MSB)
        LoRa_packet[3] = (uint8_t)(LoRaPacketCount & 0x000000FF);           // 24bit counter (LSB)
        LoRa_packet[4] = (uint8_t)((LoRaPacketCount & 0x0000FF00) >> 8);    // 24bit counter
        LoRa_packet[5] = (uint8_t)((LoRaPacketCount & 0x00FF0000) >> 16);   // 24bit counter (MSB)

        // send the packet via LoRa Module
        SX1278_sendData(&LoRa_packet[0]);
        SX1278_sleep();
        __enable_interrupt();               // The RTC interrupt should trigger now...
    }
    else
    {
        // Device powered up from a cold start.
        // It configures the device and puts the device into LPM3.5

        P2OUT |= BIT0;                            // NSS high
        __delay_cycles(75);                       // Wait for SX1278 to initialize

        init_SX1278(FIXED_PACKET_LENGTH);
        // send the packet via LoRa Module
        SX1278_sendData(&LoRa_packet[0]);
        SX1278_sleep();

        // Configure RTC
        // Interrupt and reset happen every 1024/10000 * 100 = 10 sec.
        RTCMOD = 100-1;
        RTCCTL = RTCSS__VLOCLK | RTCSR |RTCPS__1024;
        RTCCTL |= RTCIE;
    }

    // Enter LPM3.5 mode with interrupts enabled. Note that this operation does
    // not return. The LPM3.5 will exit through a RESET event, resulting in a
    // re-start of the code.

    PMMCTL0_H = PMMPW_H;                    // Open PMM Registers for write
    PMMCTL0_L |= PMMREGOFF;                 // and set PMMREGOFF

    // It is recommended to turn off the LPM3.5 switch to avoid unnecessary leakage (see user guide page 88)
    // set LPM5SW = 0 in the PM5CTL0 register
    PM5CTL0 &= ~LPM5SW;

    __bis_SR_register(LPM3_bits | GIE);
    __no_operation();

    return 0;
}

void initGpio(void)
{
    // caution: there are pullup resistors for the I2C funtionality (SDL, SDA)
    // keep in mind to leave the Port Pins high to reduce current consumption
    // port configuration will be remaining in low power states
    P1DIR = 0xFF; P2DIR = 0xFF;
    P1REN = 0xFF; P2REN = 0xFF;
    P1OUT = 0xFF; P2OUT = 0xFF;

    // --- SPI configuration (SX1278 is connected at UCA0) ---
    // MOSI = P1.4
    // MISO = P1.5
    // SCLK = P1.6
    // CSn  = P2.0 (chip enabled is controlled manually by GPIO)
    P1SEL0 |= BIT4 | BIT5 | BIT6;             // set 3-SPI pin as second function

    UCA0CTLW0 |= UCSWRST;                     // **Put state machine in reset**
    UCA0CTLW0 |= UCMST|UCSYNC|UCMSB;   // 3-pin, 8-bit SPI master
                                              // Clock polarity high, MSB
    UCA0CTLW0 |= UCSSEL__SMCLK;               // SMCLK
    UCA0BR0 = 0x02;                           // SMCLK / 2 = 500kHz, fBitClock = fBRCLK/UCBRx
    UCA0BR1 = 0;                              //
    UCA0MCTLW = 0;                            // No modulation
    UCA0CTLW0 &= ~UCSWRST;                    // **Initialize USCI state machine**
    // --- end of SPI configuration ---

    // Disable the GPIO power-on default high-impedance mode
    // to activate previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;
}

#pragma vector = RTC_VECTOR
__interrupt void RTC_ISR(void)
{
    switch(__even_in_range(RTCIV, RTCIV_RTCIF))
    {
        case RTCIV_NONE : break;            // No interrupt pending
        case RTCIV_RTCIF:                   // RTC Overflow
            break;
        default:          break;
    }
}

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

    persistent()将数据放入(程序) FRAM 中,但不会删除写保护。 要对其进行写入(包括"+")、您需要关闭 WP、如下所示:

    >SYSCFG0 = FRWPPW | DFWP; // PFWP = 0以写入使能程序 FRAM

    要重新打开它、请使用类似的东西

    >SYSCFG0 = FRWPPW | DFWP | PFWP; // PFWP = 1.

    (您可能可以使用 FRWPOA 和链接器.map 文件进行更精细的操作、但我建议您"开始小程序"。)

    [参考用户指南(SLAU445I)表1-29]

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

    您好!

    另请查看 FRAM 实用程序中的 Compute Through Power Loss (CTPL)库。 它是针对这种情况而设计的、如果应用程序被关闭而不是针对 LPM3.5唤醒完成的完全复位、则可以恢复应用程序、从而帮助您处理应用程序。  

    另外请记住响应时间、因为从 LPM3.5唤醒需要一些时间。