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.

[参考译文] 编译器/MSP430FR58471:使用 MSP430-GCC 从 RAM 执行函数的方法

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/793228/compiler-msp430fr58471-methods-for-executing-functions-from-ram-with-msp430-gcc

器件型号:MSP430FR58471

工具/软件:TI C/C++编译器

您好!

我正在尝试实现一个权变措施、此权变措施要求从 RAM 中执行一个函数(特别是 msp430fr58471勘误表中的 PMM32)、并且遇到了一些问题。 我搜索过这个论坛、并看到了很多示例、以了解如何在 IAR 和 CCS 上执行此操作、但我正在使用 MSP430-GCC、它似乎不支持我到目前为止看到的方法。  

作为参考、我尝试从 RAM 调用的函数的内容:

FRCTL0 = FRCTLPW;
GCCTL0 &=~(FRPWR|FRLPMPWR);
_ bis_SR_register (LPM3_bits | GIE); 

我尝试过的内容:

  1. 使用__attribute ((section(".data")))、该属性应将我的代码存储在闪存中、但从 RAM 执行。  
  2. 使用32字节 RAM 范围在链接器文件中创建我自己的段、我使用">RAM at>FLASH 语法声明了该范围、并再次使用 section 属性。
  3. 使用内联汇编跳转至包含与上述命令等效的编译二进制数据的 const char 数组。

所有这些方法都会产生不一致的结果。 请提供任何帮助。

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

    请允许我花一些时间来了解这一点。 我会尽快回来。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Robert、

    很抱歉耽误你的回答。 我在内部咨询、发现在使用 GCC 时、没有更好的方法来解决这一问题。 在 IAR/CCS 中、借助 TI 编译器、工具会使用预定义属性自动处理此问题、但 MSP430 GCC 无法很好地处理此问题。

    建议您首先在执行时将这些代码手动复制到 RAM、然后将 PC 设置到 RAM 位置以执行 RAM 代码。
    或者、您可能希望尝试使用 CCS、因为它是一款免费的许可工具、支持几乎所有的 TI 嵌入式处理器产品。

    如果您有更新、请告诉我。

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

    您好、Harry、

    感谢您的观看。 幸运的是、自这篇文章以来、我学到了很多东西、并且能够成功地实现从 RAM 运行的函数。 当我有更多的空闲时间时、我会回来详细解释我学到的知识、希望其他人能从我的斗争中受益。

    现在可以说我能够通过实现该功能

    /* lpm_from_ram -在进入 LPMx 之前从 RAM 禁用 FRAM
    *
    *勘误表 PMM32描述的变通办法,以防止意外
    的*代码执行。 此函数必须放置在".data"段
    中、*以便存储在闪存中、但从 RAM 执行。
    //
    void __attribute (((section (".data"))) lpm_from_ram (unsigned short SR_reg_bits){
    FRCTL0 = FRCTLPW + NWAITS_1; //解锁 fram 寄存器
    GCCTL0 &=~(FRPWR|FRLPMPWR); //关闭 fram 控制器
    __bis_SR_register (SR_reg_bits); //输入要设置
    的 SR 寄存器位} 

    我在最初尝试这种方法时偶然发现了自己制造的陷阱、这导致我发布了问题。

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

    这是一些非常简单的代码、因此您需要执行的操作完全可以用汇编语言完成。 直列式。

    基本流程是在栈上为代码分配空间(将在 RAM 中)、复制代码、将其称为子例程、返回时清理堆栈并退出。 类似如下:

    ;注意寄存器 R12-R15可以随意使用而不保存
    ;;它们之前的内容。
    #include 
    
    requlength、rend-ramstart
    .text
    .func ramexe
    ramexe:
    sub#length、R1;保留栈空间
    movR1、R13;设置复制
    mov#ramstart、r14
    mov#length、r15
    loop:MOV@r14+、@r13;复制代码
    add#2、r13
    sub#2、r15
    jnz
    ;
    添加栈
    
    
    启动函数 rr1;rrrrrrrr1 rrrrrrrrrrrr1调用 rrrrrrrrr1
    MOV#FRCTLPW、&FRCTL0
    和#~(FRPWR|FRLPMPWR)、&GCCTL0
    bis#(LPM3_bits|GIE)、R2
    命令
    建议:
    .endfunc
    .end
    

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

    slaa103.pdf (闪存自编程技术)对这种方法进行了更详细的描述。 它似乎已从 TI 网站消失、但仍然可以找到。

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

    下面是我初始尝试失败的原因的快速细分。 希望这对其他人有所帮助。 我将按时间顺序浏览我尝试过的项目列表。

    • 使用32字节 RAM 范围在链接器文件中创建我自己的段、我使用">RAM at>FLASH 语法声明了该范围、并再次使用 section 属性。

    之所以失败、是因为即使我正确定义了链接器文件条目、但我没有意识到默认情况下只有".data"段被 C 启动代码识别为需要复制。 我通过仔细检查 MSP430 gcc 的汇编输出来验证了这一点。 这可能是由于某些硬编码默认值(可疑)、也可能是因为我不知道需要执行其他一些步骤来触发从闪存到 RAM 的复制。  

    • 使用__attribute ((section(".data")))、该属性应将我的代码存储在闪存中、但从 RAM 执行。  

    这一步骤本来应该起作用,但我遇到了两个问题。 第一个问题是、我未能从上一步中删除在链接器文件中定义的特殊 RAM 段、并且我正在运行的一些用于重置堆栈指针的特殊代码将其分配到该段中的某个位置、但我未能删除。 另一个原因是盲目使用器件勘误解决方法说明中的 FRCTL0密码分配行。 我无法意识到这会导致访问时间故障、因为我的 fram 控制器等待状态设置被删除、并且我的时钟速度太高、无法进入等待状态。 有些人可能感兴趣的是、将 MSP 器件置于更高的温度会使这些访问时间故障的发生速度更快。

    • 使用内联汇编跳转至(并从其中返回) const char 数组、该数组包含与上述命令等效的编译二进制数据。

    这一个有很多缺陷:

    1. 我不应该使用 const char 数组。 这显然会将阵列分配给闪存而不是 RAM。  
    2. 我没有考虑可变长度汇编指令、因此我稍后存储的 PC 值跳转到错误的指令。
    3. 我不能确保我正在使用的某些寄存器当时没有被其他代码使用。

    在返回到上面发布的较简单的 C 语言代码之前、我最终使用了这种方法。 如果有人想了解、我将包含相关代码。

    /* RAM 功能作为阵列存在。 它是与以下指令等效的二进
    
    
    制文件:* FRCTL0 = FRCTLPW + NWAITS_1;* GCCTL0 &=~(FRPWR|FRLPMPWR);
    *__bis_SR_register (LPM3_bits | GIE);
    * asm ("bra R6");
    *
    char lpm_from 0x40、0x20、0xbram = 0x20、0x20、0x20
    0x01、0xb2、0xf0、0xf9、0xff、
    0x44、0x01、0x32、0xd0、0xd8、 0x00、0x03、0x43、0xc0、0x06
    };
    
    (笑声)
    main(){...
    
    LPM_From_ram();
    ...
    }
    
    /* PMM32勘误解决方法;在 RAM 中执行操作时禁用 FRAM 控制器后调用 lpm 模式。
    *请非常小心您在这里使用的寄存器! 覆盖当前正在使用的文件会产生不可预测的结果。
    *此函数在使用包含代码的数组地址进行设置后跳转到 r14。
    *它将 R6设置为最后一个字节代码分支指令使用的返回地址。
    *为了保持字节偏移距离恒定、使用了一个寄存器进行寄存器添加(请注意变量 asm 指令长度)
    */
    void lpm_from_ram (void){
    asm ("mov #lpm_from_ram_binary、r14");
    asm ("mov #4、r7");
    asm ("mov PC、 r6");
    asm ("add r7、r6");
    asm ("bra r14");
    } 

      

      

    当我意识到我的初始错误后、只需使用".data"的 section 属性就可以实现最合理的方法、也是最不复杂的方法。 尽管如此、这仍然是一个有趣的学习过程。

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

    非常感谢您分享!

    此致、
    哈里