Cortex-M4F MCU 启动中关键部分的内存屏障

Memory barriers for critical sections in Cortex-M4F MCU startup

简介: 我设计了一个具有 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"); 在两个 [= 之间27=]asm volatile ("isb 0xF":::"memory"); 一个常见有用的实现?这些指示意味着什么?我不确定是否正确遵循 "GoTo Implementation" 路径以结束这些语句!

我想提前感谢大家抽出宝贵时间,希望这个问题对以后的其他人有所帮助!

Do any of this memory barriers make sense?

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

Is wrapping a asm volatile ("dmb 0xF":::"memory"); between two asm volatile ("isb 0xF":::"memory"); a common useful implementation? What would those instructions mean?

isb : 到目前为止,它会刷新缓冲区并获取指令。

dmb : 至此完成所有内存访问。

isb : 在dmb之后,它确保新的上下文已经加载。

这是保护代码免受 procesor/compiler 重新排序、延迟等影响的有用且非常安全(和防御性)的方法。

此外,这个临界区正在禁用中断以将其提升为最高优先级任务,因此任何人都无法中断这部分代码。当然,保护临界区的正确方法。