Барьеры памяти для критических секций при запуске MCU Cortex-M4F
ВВЕДЕНИЕ: Я разработал встраиваемую систему с 32-битным микроконтроллером ARM® Cortex®-M4F ATSAME54N20A. Скоро плата будет собрана и готова к программированию, поэтому я настраивал свою среду программирования. Я выбрал простое решение, в котором присутствуют только минимально необходимые 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), используются критические разделы, подобные следующим: (присутствует в 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;
Есть ли какой-либо из этих барьеров памяти имеет смысл? Оборачивает asm volatile ("dmb 0xF"::: "memory"); между двумя asm volatile ("isb 0xF"::: "memory"); общая полезная реализация? Что бы означали эти инструкции? Я не уверен, что путь "Реализация GoTo" был соблюден правильно, чтобы в конечном итоге с этими утверждениями!
Я хотел бы заранее поблагодарить всех за ваше время и надеюсь, что этот вопрос поможет другим в будущем!
1 ответ
Есть ли какой-либо из этих барьеров памяти имеет смысл?
В моих глазах да. При наличии кешей, прерываний, оптимизаций, задержек загрузки и т. Д. Может потребоваться блокировка памяти.
Оборачивает asm volatile ("dmb 0xF":::"memory"); между двумя asm volatile ("isb 0xF":::"memory"); общая полезная реализация? Что бы означали эти инструкции?
isb
: он очищает буферы и извлекает инструкции до сих пор.
dmb
: он завершает весь доступ к памяти до сих пор.
isb
: после dmb
, это гарантирует, что новый контекст был загружен.
Это полезный и очень безопасный (и оборонительный) способ защиты кода от переупорядочения процессора / компилятора, задержек и т. Д.
Кроме того, эта критическая область отключает прерывания, чтобы повысить их приоритетность, поэтому никто не сможет прервать эту часть кода. Определенно, правильный способ защитить критический регион.