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.

[参考译文] MSP430FR2111:请告诉我如何将部分 FRAM 区域用作非易失性存储器。

Guru**** 2668435 points

Other Parts Discussed in Thread: MSP430FR2111, MSP-FET

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1593671/msp430fr2111-please-tell-me-how-to-use-part-of-the-fram-area-as-non-volatile-memory

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

感谢论坛上的每个人的支持。

我正在使用基于 FRAM 的 MCU MSP430FR2111 来开发应用。  
我的目标是使用 4 字节的 FRAM 作为非易失性存储器、因此我编写了以下程序代码(摘录)。  

使用 CCS 进行调试时、我确认监视变量在递增时发生变化、我认为可以按预期工作。 然而、在通过闪存对器件进行编程并运行之后、FRAM 变量保持为 0 并且没有改变。  

我不熟悉 MSP430 编程、目前无法了解导致此问题的原因。  
很抱歉抽出时间、但我非常感谢您提供的任何建议或指导。

我们省略了初始化部分、并摘录了似乎与它无法按预期运行的原因相关的部分。
即使关闭电源、我们也希望存储在 FRAM 中的变量的名称是累计_距离。 它是 4 字节的无符号长整型值。
为此、当写入并运行该源程序时、变量保持为 0 且不会递增。
但是、在使用 CCS 进行调试时、它确实会递增...

非常感谢您的合作。

 

//----------------------------------------------------------------------------------------

#include  
#include

#pragma PERSISTENT(累计距离)
uint32_t umulated_distance = 0;

易失性 uint8_t inc_flag = 0;

__interrupt void Port_1 (void);

#define MCLK_FREQ_MHz 1.           // MCLK = 1MHz

int main (void){
  WDTCTL = WDTPW | WDTHOLD;        //停止看门狗计时器
  SYSCFG0 = FRWPPW;             

  __bis_SR_register (SCG0);         //禁用 FLL
  CSCTL3 = SELREF__REFOCLK;        //将 REFO 设置为 FLL 基准源
  CSCTL1 = DCOFTRIMEN_0 | DCORSEL_0;   // DCO 范围= 1MHz
  CSCTL2 = FLLD_0 + 30;          // DCODIV = 1MHz
  __ delay_cycles (3);
  __ BIC_SR_REGISTER (SCG0);         //启用 FLL
  CSCTL4 = SELMS_DCOCLKDIV | SELA__REFOCLK;//将默认 REFO (~32768Hz) 设置为 ACLK 源、ACLK = 32768Hz
                        //默认 DCODIV 作为 MCLK 和 SMCLK 来源

  while (1)     
  {
    __ low_power_mode_3 ();  
    //  
    if (inc_flag){
      累计距离++;
      INC_FLAG = 0;
    }
  }
}

//端口 1.x 中断服务例程
pragma vector=PORT1_vector
__interrupt void Port_1 (void)
{   
  if (P1IFG 和 BIT3){
    INC_FLAG = 1;   
    P1IFG 且=~BIT3;
    __BIC_SR_REGISTER_ON_EXIT (LPM3_BITS);
  }
}

 

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

    嗨、Takashi、

    我认为问题是因为在程序开始时您正在将值初始化为 0。 每次器件启动时、这都会重置该值。

    您可以尝试执行类似这样的操作来处理此问题:

    #pragma PERSISTENT(accumulated_distance)  
    uint32_t accumulated_distance;
    
    #pragma PERSISTENT(magic_flag)
    uint32_t magic_flag;
    
    #define MAGIC_INITIALIZED 0x12345678
    
    int main(void) {
        // Check if this is first-ever run
        if (magic_flag != MAGIC_INITIALIZED) {
            accumulated_distance = 0;           // Initialize on first run only
            magic_flag = MAGIC_INITIALIZED;     // Mark as initialized
        }
        // Now accumulated_distance is guaranteed to start correctly
        // ... rest of code
    }

    此致、

    Owen

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

    亲爱的欧文·李
    感谢您的帮助、我是 Yumita。

    感谢您的答复。
    我应用了你教我的机制源代码,并在原型系统上试用。
    让它正常工作后、我连接了 MSP-FET 并在 CCS 的调试模式下检查存储器内容。 结果如附图所示、累积距离变量的值保留为 0。
    我不知道我是否检查了不正确的内存,但它似乎是机器不撒谎。
    是否有任何其他因素可能导致该值不递增?
    很抱歉出现此问题、感谢您的持续帮助。

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

    尊敬的 Yumita:

    您能否分享更新后的源代码?

    在调试期间、在建议的更改之前和之后、是观察表达式中的值仅发生变化、还是您观察到 FRAM 也在更新?

    此致、

    Owen

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

    尊敬的 Owen:

    感谢您的答复。
    我附上了源代码。 请注意、我的源代码中的注释是日语、因此文本可能会出现乱码。

    我使用闪存工程将代码写入 MCU、然后将电路板连接到评估装置以检查其运行情况。 考虑到操作流程、我认为 FRAM 变量正在正确递增、但当我从评估集中移除板并将其连接到调试器时、我认为 FRAM 的内容已清除。

    鉴于此、我认为检查写入 FRAM 的变量值是否已更改或保留的唯一方法是使用 UART 或类似器件从外部输出该变量。

    我需要向项目组报告我的发展进度。 我‑使用 FRAM μ‑配置的 MCU 无需外部非 μ V 易失性存储器、这是否正确?

    我很抱歉再次打扰您、感谢您的建议。

    此致、
    Takashi

    #include <msp430.h> 
    #include <stdint.h>
    
    #pragma PERSISTENT(accumulated_distance)
    uint32_t accumulated_distance;              // 0 初期化をしないこと
    
    #pragma  PERSISTENT(magic_flag)             // 2025.12.03 追加
    uint32_t magic_flag;
    
    #define MAGIC_INITIALIZED 0xFFFFFFF0        // 2025.12.03 追加
    
    volatile uint8_t inc_flag = 0;
    
    __interrupt void Port_1(void);
    
    #define MCLK_FREQ_MHZ 1                     // MCLK = 1MHz
    
    int main(void) {
        WDTCTL = WDTPW | WDTHOLD;               // Stop watchdog timer
        SYSCFG0 = FRWPPW;                       // FRAM書き込み保護解除
    
        __bis_SR_register(SCG0);                // Disable FLL
        CSCTL3 = SELREF__REFOCLK;               // Set REFO as FLL reference source
        CSCTL1 = DCOFTRIMEN_0 | DCORSEL_0;      // DCO Range = 1MHz
        CSCTL2 = FLLD_0 + 30;                   // DCODIV = 1MHz
        __delay_cycles(3);
        __bic_SR_register(SCG0);                // Enable FLL
        CSCTL4 = SELMS__DCOCLKDIV | SELA__REFOCLK; // set default REFO(~32768Hz) as ACLK source, ACLK = 32768Hz
                                                   // default DCODIV as MCLK and SMCLK source
    
        // ポートの初期化
        // P1.0 / A0 : アナログ入力 電池電圧計測 ADC
        P1SEL0 |= BIT0; P1SEL1 |= BIT0;
    
        // P1.1 / A1 : オープンドレイン 出力 ローサイドスイッチ
        P1DIR |= BIT1;
    
        // P1.3 / A3    : デジタル入力 走行距離パルス入力 立下り
        P1SEL0 &= ~BIT3; P1SEL1 &= ~BIT3;   // 汎用IOに設定(明示)
        P1DIR &= ~BIT3;                     // 入力方向に設定
        P1IES |= BIT3;                      // 立下りエッジで割込み
        P1IFG &= ~BIT3;                     // 割り込みフラグクリア
        P1IE |= BIT3;                       // 割り込み許可
    
        // P1.4 / A4    : 出力 DCDCコンバータEN
        P1SEL0 &= ~BIT4; P1SEL1 &= ~BIT4;   // 汎用IOに設定(明示)
        P1DIR |= BIT4;                      // 出力方向に設定
        P1OUT &= ~BIT4;                     // 初期値 Low
    
        // P1.5 / A5    : 通信モジュールのリセット
        P1SEL0 &= ~BIT5; P1SEL1 &= ~BIT5;   // 汎用IOに設定(明示)
        P1DIR |= BIT5;                      // 出力方向に設定
        P1OUT &= ~BIT5;                     // 初期値 Low
    
        // P2.0         : 出力 通信モジュールのWKUP
        P2SEL0 &= ~BIT0; P2SEL1 &= ~BIT0;   // 汎用IOに設定(明示)
        P2DIR  |= BIT0;                     // 出力方向に設定
        P2OUT  |= BIT0;                     // 初期値 High
    
        // P2.1         : 入力 データ送出用押しボタンスイッチの入力
        P2SEL0 &= ~BIT1; P2SEL1 &= ~BIT1;   // 汎用IOに設定(明示)
        P2DIR &= ~BIT1;                     // 入力方向に設定
    
        // UARTの設定
        // P1.6 = UCA0RXD, P1.7 = UCA0TXD
        P1SEL0 |= BIT6 | BIT7;              // UART機能に設定
        P1SEL1 &= ~(BIT6 | BIT7);
    
        // UARTモジュール設定
        UCA0CTLW0 = UCSWRST;                // リセット状態に保持
        UCA0CTLW0 |= UCSSEL__SMCLK;         // クロック源にSMCLKを選択
    
        // 例: SMCLK=1MHz, 9600bps
        UCA0BR0 = 104;                      // 1MHz / 9600 ≈ 104
        UCA0BR1 = 0;
        UCA0MCTLW = UCBRS0 | UCBRF0 | UCOS16; // 標準的な補正値
    
        UCA0CTLW0 &= ~UCSWRST;              // リセット解除
        // UCA0IE |= UCRXIE;                // 受信割込み許可(必要なら)
    
        // ADC
        ADCCTL0 &= ~ADCENC;                 // ADCを無効化
        ADCCTL1 |= ADCSHP | ADCSSEL_2;      // サンプルホールドパルス生成 + SMCLK選択
        ADCCTL2 |= ADCRES_2;                // 分解能10ビット(ADCRES_2)
    
        ADCMCTL0 |= ADCINCH_0;              // チャネルA0を選択
    
        ADCCTL0 |= ADCON;                   // ADCを有効化
        ADCIE |= ADCIE0;                    // ADC変換完了割り込みを許可(任意)
        
        PM5CTL0 &= ~LOCKLPM5;                   // Disable the GPIO power-on default high-impedance mode
                                                // to activate previously configured port settings
    
        // Check if this is first-ever run
        if (magic_flag != MAGIC_INITIALIZED){
            accumulated_distance = 0;           // Initialize on first run only
            magic_flag = MAGIC_INITIALIZED;
        }
    
        while(1)                                // ループ
        {
            __low_power_mode_3();           // LPM3 へ移行
            // 割り込みで起きる( MCUオン )
            if (inc_flag){
                accumulated_distance++;
                inc_flag = 0;
            }
        }
    }
    
    // Port 1.x interrupt service routine
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    {    
       if (P1IFG & BIT3){                   // P1.3 割り込み要因
            inc_flag = 1;                   // 要求を立てる
            P1IFG &= ~BIT3;                 // フラグクリア
            __bic_SR_register_on_exit(LPM3_bits);
        }
    }

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

    尊敬的 Yumita:

    [引用 userid=“491932" url="“ url="~“~/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1593671/msp430fr2111-please-tell-me-how-to-use-part-of-the-fram-area-as-non-volatile-memory/6142613

    我需要向项目组报告我的发展进度。 我‑使用 FRAM μ‑配置的 MCU 无需外部非 μ V 易失性存储器、这是否正确?

    [/报价]

    是的、您回答正确。

    我认为 MSP430 FRAM 技术–操作方法和最佳实践 可能是一份有用的文档。

    根据您之前发送的存储器屏幕截图、变量似乎存储在 RAM (0x2000 - 0x23FF) 而不是 FRAM 中。 我会检查链接器文件并确保其配置正确。 我不希望调试器连接成为清除这些值的原因。 这可能是因为它们存储在 RAM 中、在复位时被清除。

    此致、

    Owen

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

    亲爱的欧文
    感谢您的答复。
    我看了一下.map 文件。
    它看起来很奇怪,而且脱节。
    以下是.map 文件的摘录。

    您是否说源代码中的变量声明不正确?
    正如我在上一封邮件中所附、当前声明使用持久性。

    MEMORY CONFIGURATION
    
             name            origin    length      used     unused   attr    fill
    ----------------------  --------  ---------  --------  --------  ----  --------
      BSL0                  00001000   00000400  00000000  00000400  RWIX
      RAM                   00002000   00000400  000000a9  00000357  RWIX
      FRAM                  0000f100   00000e80  000003a8  00000ad8  RWIX
      JTAGSIGNATURE         0000ff80   00000004  00000004  00000000  RWIX  ffff 
    
    
    --- Omitted ----
    
    
    SECTION ALLOCATION MAP
    
     output                                  attributes/
    section   page    origin      length       input sections
    --------  ----  ----------  ----------   ----------------
    .TI.persistent 
    *          0    0000f100    00000000     UNINITIALIZED
    
    .persistent 
    *          0    0000f100    00000000     UNINITIALIZED
    
    
    --- Omitted ----
    
    
    .bss       0    00002000    00000008     UNINITIALIZED
                    00002000    00000004     (.common:accumulated_distance)
                    00002004    00000004     (.common:magic_flag)
    .bss       0    00002000    00000008     UNINITIALIZED
                      00002000    00000004     (.common:accumulated_distance)
                      00002004    00000004     (.common:magic_flag)
    

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

    亲爱的欧文
    感谢您的帮助、我是 Yumita。

    我查看了您提供的 Texas Instruments 文档“MSP430 FRAM 技术 — 操作方法和最佳实践“。
    本文档介绍了如何修改.cmd 文件、并按照添加的说明进行了操作
    .TI.noinit :{}> FRAM
    以确保即使在电源关闭时也保留变量。 但是、.map 文件中的变量地址仍然是 RAM 地址。
    当然、我也将程序源代码中的变量声明更改为
    #pragma NOINIT(累加距离)
    uint32_t umulted_distance;

    无论我如何操作、写入.map 文件的变量的存储器地址在构建后仍然是 RAM 地址。

    如何解决这个问题?

    对此造成的不便、我深表歉意、但感谢您的建议。

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

    尊敬的 Yumita:

    您的链接器文件 (.cmd) 可能有问题。

    您能和我分享一下吗?

    我认为参考 SDK 中的示例也可能是一个不错的 选择:msp430fr211x_framwrite

    我建议将您的链接器文件与本示例中的文件进行比较。 FRAM 段已正确定义。

    此致、

    Owen

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我认为问题是因为在程序开始时、您正在将值初始化为 0。 每次设备启动时、这将重置值。

    我不相信这是真的。  

    它存储在 FRAM 中、与代码一样、在编程期间设置了一个初始值。 它不是.data 或.bss 段的一部分、因此不会被 C 启动代码初始化。

    使用持久变量时的一个危险是、IDE 试图提供帮助并以静默方式启用 FRAM 写保护。 通常是一件好事,但它阻止了永久变量的改变。  

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

    向论坛上的每一位回复者:

    感谢大家在隔天所做的关于如何将 MSP430FR2111 计数器值保存到 FRAM 的大量回复。
    最初、我尝试按照手册中的说明使用#pragma PERSISTENT 和#pragma NOINIT、但这些值​​未按预期保存到 FRAM 中、并且我遇到了​​断电后这些值会消失的问题。 这些方法没有解决问题、我认为这是一个需要进一步调查的问题。
    我觉得这是许多人,而不仅仅是我,都在挣扎的一点。
    最后、我通过在链接器脚本中创建一个专用部分并将该部分分配给 FRAM 区域来解决问题。
    •已确认变量位于文件的 FRAM 区域中。
    •已使用 CCS 调试器确认递增操作。
    •已确认该值已保存并进一步增加、即使在断电和恢复电源后也是如此。
    这已经实现了我们在我们的项目中所使用的系统的核心功能:持续存储和数值的连续增量。
    再次感谢所有作出答复的人。 今后、我们希望继续改进、例如优化数据保存和编写策略。
    感谢您的合作。