【问题标题】:Memory barriers for critical sections in Cortex-M4F MCU startupCortex-M4F MCU 启动中关键部分的内存屏障
【发布时间】:2018-12-02 23:31:33
【问题描述】:

简介:我设计了一个具有ATSAME54N20A 32 位ARM® Cortex®-M4F MCU 的嵌入式系统。该板将很快组装并准备好进行编程,因此我正在设置我的编程环境。我选择了一个简单的解决方案,其中仅存在必要的最少 C 编写文件,因为虽然这是一个耗时的过程,但它有助于我理解系统的工作原理。选择的编译器是带有以下参数的 GCC:

"...\arm-none-eabi-gcc.exe"  -x c -mthumb -O1 -ffunction-sections -mlong-calls -g3 -Wall -mcpu=cortex-m4 -c -std=gnu99 main.c -o main.o

...

"...\arm-none-eabi-gcc.exe" weak_handlers.o main.o SEGGER_RTT.o SEGGER_RTT_printf.o SEGGER_RTT_Syscalls_GCC.o -mthumb -Wl,-Map="app.map" -Wl,--start-group -lm  -Wl,--end-group -Wl,--gc-sections -mcpu=cortex-m4 -T flash.ld -o app.elf

问题:我用来比较我的代码的参考编程项目(Atmel Studio LEDflasher example)使用如下关键部分:(出现在 hri_nvmctrl_e54.h 第 944 行)

NVMCTRL_CRITICAL_SECTION_ENTER();
((Nvmctrl *)hw)->CTRLA.reg |= NVMCTRL_CTRLA_RWS(mask);
NVMCTRL_CRITICAL_SECTION_LEAVE();

我不明白。我尝试跟踪这些函数实现以查看它们在做什么,并最终得到以下代码:

// ==============================================================================================
// Enter critical section.
// ==============================================================================================
// Get primask
register uint32_t __regPriMask         __asm__("primask");
uint32_t volatile *atomic = __regPriMask;
// Disable IRQ interrupts by setting the I-bit in the CPSR.
// Can only be executed in Privileged modes.
__asm__ volatile ("cpsid i" : : : "memory");
// Memory barrier
do {\
        __asm__ volatile ("isb 0xF":::"memory");
        __asm__ volatile ("dmb 0xF":::"memory");
        __asm__ volatile ("isb 0xF":::"memory");
} while (0U);


// ==============================================================================================
// 25.8.1 Control A
// ==============================================================================================
// NVMCTRL->     offset: CTRLA
// 0x41004000U           0x00000000U  
(*(volatile uint32_t*)0x41004000U) = 0x01000400U;


// ==============================================================================================
// Leave critical section.
// ==============================================================================================
// Memory barrier
do {\
        __asm__ volatile ("isb 0xF":::"memory");
        __asm__ volatile ("dmb 0xF":::"memory");
        __asm__ volatile ("isb 0xF":::"memory");
} while (0U);
// Set primask
  __regPriMask = &atomic;

这些记忆障碍是否有意义?正在包装 a asm volatile ("dmb 0xF":::"memory"); 在两个 asm volatile ("isb 0xF ":::"memory"); 一个常见的有用实现?这些指示是什么意思?我不确定是否正确遵循了“GoTo Implementation”路径以结束这些语句!

我要提前感谢大家的时间,并希望这个问题在未来对其他人有所帮助!

【问题讨论】:

    标签: c assembly arm inline-assembly memory-barriers


    【解决方案1】:

    这些记忆障碍是否有意义?

    在我看来,是的。如果有缓存、中断、优化、加载延迟等,内存屏障可能是必须的。

    正在包装一个 asm volatile ("dmb 0xF":::"memory");在两个 asm volatile 之间(“isb 0xF”:::“memory”);一个常见的有用实现?这些说明是什么意思?

    isb:它刷新缓冲区并获取指令。

    dmb :它完成了到目前为止所有的内存访问。

    isb:在dmb之后,保证新的上下文已经加载完毕。

    这是一种有用且非常安全(且具有防御性)的方法,可以保护代码免受处理器/编译器重新排序、延迟等的影响。

    此外,这个关键区域正在禁用中断以将其提升为最高优先级的任务,因此没有人能够中断这部分代码。绝对是保护关键区域的正确方法。

    【讨论】:

    • 非常感谢您的回答!
    • 每当我点击支持按钮时,StackOverflow 都会警告我:“感谢您的反馈!声望低于 15 的人的投票会被记录下来,但不要更改公开显示的帖子得分。”不过不要担心,因为我会记得尽快为您的答案投票,或者在 Stack EE 社区中搜索您。我想借此机会询问是否有必要为每个相邻的寄存器更改离开和进入关键部分,或者是否可以将寄存器写入包装在单个关键区域中!
    • 完成!!获得 15 声望。
    猜你喜欢
    • 2020-11-12
    • 1970-01-01
    • 1970-01-01
    • 2019-09-15
    • 2012-05-27
    • 2016-06-19
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    相关资源
    最近更新 更多