# MPU config created

This commit is contained in:
Dmitry Akimov 2026-04-02 13:09:20 +03:00
parent 8cd4f20f14
commit 832a542db4
4 changed files with 174 additions and 121 deletions

View file

@ -1,10 +1,105 @@
#include "board.h" #include "board.h"
#include "clock_config.h" #include "clock_config.h"
#include "core_cm7.h"
#include "fsl_common.h"
#include "pin_mux.h" #include "pin_mux.h"
/* Non-cacheable region boundaries — exported by linker script */
extern uint32_t __NCACHE_REGION_START[];
extern uint32_t __NCACHE_REGION_SIZE[];
/*! @brief Конфигурация MPU: регионы памяти, атрибуты кэширования.
*
* Должна вызываться до включения D-Cache/I-Cache.
* Конкретный набор регионов определяется макросами времени сборки:
* - XIP_EXTERNAL_FLASH добавляет cacheable RO регион для FlexSPI NOR
* - BOARD_MPU_SDRAM добавляет cacheable RW регион для SDRAM 32 MB
*
* После возврата MPU включён, D-Cache и I-Cache включены.
*/
static void board_mpu_init(void)
{
uint32_t nc_start = (uint32_t) __NCACHE_REGION_START;
uint32_t nc_size = (uint32_t) __NCACHE_REGION_SIZE;
volatile uint32_t i = 0U;
if ((SCB->CCR & SCB_CCR_IC_Msk) != 0U)
{
SCB_DisableICache();
}
if ((SCB->CCR & SCB_CCR_DC_Msk) != 0U)
{
SCB_DisableDCache();
}
ARM_MPU_Disable();
/* Region 0: deny-all, Strongly Ordered — errata 1013783-B workaround. */
MPU->RBAR = ARM_MPU_RBAR(0U, 0x00000000U);
MPU->RASR = ARM_MPU_RASR(1U, ARM_MPU_AP_NONE, 0U, 0U, 0U, 0U, 0U, ARM_MPU_REGION_SIZE_4GB);
/* Region 1: Device, 0x80000000, 512 MB. */
MPU->RBAR = ARM_MPU_RBAR(1U, 0x80000000U);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_FULL, 2U, 0U, 0U, 0U, 0U, ARM_MPU_REGION_SIZE_512MB);
/* Region 2: Device, 0x60000000, 512 MB. */
MPU->RBAR = ARM_MPU_RBAR(2U, 0x60000000U);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_FULL, 2U, 0U, 0U, 0U, 0U, ARM_MPU_REGION_SIZE_512MB);
#if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1)
/* Region 3: Normal WB, RO, XIP — overrides Region 2 for Flash 64 MB. */
MPU->RBAR = ARM_MPU_RBAR(3U, 0x60000000U);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_RO, 0U, 0U, 1U, 1U, 0U, ARM_MPU_REGION_SIZE_64MB);
#endif
/* Region 4: Device, 0x00000000, 1 GB. */
MPU->RBAR = ARM_MPU_RBAR(4U, 0x00000000U);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_FULL, 2U, 0U, 0U, 0U, 0U, ARM_MPU_REGION_SIZE_1GB);
/* Region 5: Normal WB, ITCM 128 KB — overrides Region 4. */
MPU->RBAR = ARM_MPU_RBAR(5U, 0x00000000U);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_FULL, 0U, 0U, 1U, 1U, 0U, ARM_MPU_REGION_SIZE_128KB);
/* Region 6: Normal WB, DTCM 128 KB. */
MPU->RBAR = ARM_MPU_RBAR(6U, 0x20000000U);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_FULL, 0U, 0U, 1U, 1U, 0U, ARM_MPU_REGION_SIZE_128KB);
/* Region 7: Normal WB, OCRAM 256 KB. */
MPU->RBAR = ARM_MPU_RBAR(7U, 0x20200000U);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_FULL, 0U, 0U, 1U, 1U, 0U, ARM_MPU_REGION_SIZE_256KB);
#if defined(BOARD_MPU_SDRAM) && (BOARD_MPU_SDRAM == 1)
/* Region 8: Normal WB, SDRAM 32 MB — overrides Region 1. */
MPU->RBAR = ARM_MPU_RBAR(8U, 0x80000000U);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_FULL, 0U, 0U, 1U, 1U, 0U, ARM_MPU_REGION_SIZE_32MB);
#endif
/* Region 9: Non-cacheable OCRAM — overrides Region 7 for USB DMA. */
while ((nc_size >> i) > 1U)
{
i++;
}
if (i != 0U)
{
MPU->RBAR = ARM_MPU_RBAR(9U, nc_start);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_FULL, 1U, 0U, 0U, 0U, 0U, i - 1U);
}
/* Region 10: Device, peripherals 0x40000000, 4 MB. */
MPU->RBAR = ARM_MPU_RBAR(10U, 0x40000000U);
MPU->RASR = ARM_MPU_RASR(0U, ARM_MPU_AP_FULL, 2U, 0U, 0U, 0U, 0U, ARM_MPU_REGION_SIZE_4MB);
ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);
SCB_EnableDCache();
SCB_EnableICache();
}
void board_hw_init(void) void board_hw_init(void)
{ {
BOARD_InitPins(); BOARD_InitPins();
BOARD_BootClockRUN(); BOARD_BootClockRUN();
board_mpu_init();
} }

View file

@ -26,8 +26,8 @@
/* Entry Point */ /* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400; HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x2000;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0400; STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x1000;
VECTOR_RAM_SIZE = DEFINED(__ram_vector_table__) ? 0x00000400 : 0; VECTOR_RAM_SIZE = DEFINED(__ram_vector_table__) ? 0x00000400 : 0;
/* Specify the memory areas */ /* Specify the memory areas */
@ -46,7 +46,7 @@ MEMORY
SECTIONS SECTIONS
{ {
__NCACHE_REGION_START = ORIGIN(m_data2); __NCACHE_REGION_START = ORIGIN(m_data2);
__NCACHE_REGION_SIZE = 0; __NCACHE_REGION_SIZE = 0x2000; /* 8 KB non-cacheable for USB DMA */
.flash_config : .flash_config :
{ {
@ -205,24 +205,26 @@ SECTIONS
} > m_qacode } > m_qacode
__NDATA_ROM = __ram_function_flash_start + (__ram_function_end__ - __ram_function_start__); __NDATA_ROM = __ram_function_flash_start + (__ram_function_end__ - __ram_function_start__);
.ncache.init : AT(__NDATA_ROM) .ncache.init :
{ {
__noncachedata_start__ = .; /* create a global symbol at ncache data start */ . = ALIGN(32);
__noncachedata_start__ = .;
*(NonCacheable.init) *(NonCacheable.init)
. = ALIGN(4); . = ALIGN(4);
__noncachedata_init_end__ = .; /* create a global symbol at initialized ncache data end */ __noncachedata_init_end__ = .;
} > m_data } > m_data2
. = __noncachedata_init_end__; . = __noncachedata_init_end__;
.ncache : .ncache :
{ {
*(NonCacheable) *(NonCacheable)
. = ALIGN(4); . = ALIGN(4);
__noncachedata_end__ = .; /* define a global symbol at ncache data end */ __noncachedata_end__ = .;
} > m_data } > m_data2
__DATA_END = __NDATA_ROM + (__noncachedata_init_end__ - __noncachedata_start__); __DATA_END = __NDATA_ROM;
text_end = ORIGIN(m_text) + LENGTH(m_text); text_end = ORIGIN(m_text) + LENGTH(m_text);
ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data") ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data")
ASSERT((__noncachedata_end__ - ORIGIN(m_data2)) <= LENGTH(m_data2), "m_data2 ncache overflow")
/* Uninitialized data section */ /* Uninitialized data section */
.bss : .bss :

View file

@ -26,8 +26,8 @@
/* Entry Point */ /* Entry Point */
ENTRY(Reset_Handler) ENTRY(Reset_Handler)
HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400; HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x2000;
STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0400; STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x1000;
/* Specify the memory areas */ /* Specify the memory areas */
MEMORY MEMORY
@ -41,8 +41,12 @@ MEMORY
/* Define output sections */ /* Define output sections */
SECTIONS SECTIONS
{ {
/* Non-cacheable region carved from the start of m_data2 (SRAM_OC).
* USB DMA descriptors and endpoint buffers must be placed here via
* __attribute__((section("NonCacheable"))) to avoid CM7 D-Cache coherency issues.
* Size must be power-of-2 and >= 32 bytes for MPU region validity (ARM errata). */
__NCACHE_REGION_START = ORIGIN(m_data2); __NCACHE_REGION_START = ORIGIN(m_data2);
__NCACHE_REGION_SIZE = 0; __NCACHE_REGION_SIZE = 0x2000; /* 8 KB — USB ep bufs + DMA descriptors */
/* The startup code goes first into internal RAM */ /* The startup code goes first into internal RAM */
.interrupts : .interrupts :
@ -161,24 +165,26 @@ SECTIONS
} > m_data } > m_data
__NDATA_ROM = __DATA_ROM + (__data_end__ - __data_start__); __NDATA_ROM = __DATA_ROM + (__data_end__ - __data_start__);
.ncache.init : AT(__NDATA_ROM) .ncache.init :
{ {
__noncachedata_start__ = .; /* create a global symbol at ncache data start */ . = ALIGN(32);
__noncachedata_start__ = .;
*(NonCacheable.init) *(NonCacheable.init)
. = ALIGN(4); . = ALIGN(4);
__noncachedata_init_end__ = .; /* create a global symbol at initialized ncache data end */ __noncachedata_init_end__ = .;
} > m_data } > m_data2
. = __noncachedata_init_end__; . = __noncachedata_init_end__;
.ncache : .ncache :
{ {
*(NonCacheable) *(NonCacheable)
. = ALIGN(4); . = ALIGN(4);
__noncachedata_end__ = .; /* define a global symbol at ncache data end */ __noncachedata_end__ = .;
} > m_data } > m_data2
__DATA_END = __NDATA_ROM + (__noncachedata_init_end__ - __noncachedata_start__); /* ncache sections are now in m_data2; DATA_END tracks only m_data usage */
text_end = ORIGIN(m_text) + LENGTH(m_text); __DATA_END = __NDATA_ROM;
ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data") ASSERT(__DATA_END <= (ORIGIN(m_text) + LENGTH(m_text)), "region m_text overflowed")
ASSERT((__noncachedata_end__ - ORIGIN(m_data2)) <= LENGTH(m_data2), "m_data2 ncache overflow")
/* Uninitialized data section */ /* Uninitialized data section */
.bss : .bss :

View file

@ -1,56 +1,74 @@
#include "board.h" #include "board.h"
#include "bsp/button.h"
#include "bsp/can.h"
#include "bsp/led.h" #include "bsp/led.h"
#include "bsp/opto.h"
#include "bsp/tick.h" #include "bsp/tick.h"
#include "bsp/uart_host.h" #include "bsp/uart_host.h"
#include "fsl_common.h"
#include "log/log.h" #include "log/log.h"
#include "port/log_uart.h" #include "port/log_uart.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
static volatile bool g_is_in1_activated = false; /* --------------------------------------------------------------------------
static volatile bool g_is_in2_activated = false; * Проверка non-cacheable региона
static volatile bool g_is_in1_deactivated = false; * --------------------------------------------------------------------------
static volatile bool g_is_in2_deactivated = false; * Буфер размещён в секции NonCacheable OCRAM @ 0x20200000.
* MPU Region 9 настраивает эту область как Normal non-cacheable,
* поэтому записи CPU сразу видны DMA без SCB_CleanDCache().
* -------------------------------------------------------------------------- */
static void on_opto_change(bsp_opto_ch_t ch, bsp_opto_state_t state) #define NCACHE_TEST_BUF_SIZE 64U
#define NCACHE_REGION_BASE 0x20200000U
#define NCACHE_REGION_END 0x20202000U /* 8 KB — размер из линкер-скрипта */
AT_NONCACHEABLE_SECTION_ALIGN(static uint8_t s_ncache_buf[NCACHE_TEST_BUF_SIZE], 4U);
static bool ncache_test_run(void)
{ {
if (ch == BSP_OPTO_CH_IN1 && state == BSP_OPTO_STATE_ACTIVE) uint32_t buf_addr = (uint32_t) s_ncache_buf;
/* Проверяем что буфер физически лежит в ожидаемом ncache регионе */
if (buf_addr < NCACHE_REGION_BASE || buf_addr >= NCACHE_REGION_END)
{ {
/* IN1 активирован */ LOG_E("NCACHE", "buf addr 0x%08lx outside ncache region [0x%08x..0x%08x)",
g_is_in1_activated = true; (unsigned long) buf_addr, NCACHE_REGION_BASE, NCACHE_REGION_END);
return false;
} }
if (ch == BSP_OPTO_CH_IN2 && state == BSP_OPTO_STATE_ACTIVE) /* Записываем паттерн */
for (uint32_t i = 0U; i < NCACHE_TEST_BUF_SIZE; i++)
{ {
/* IN2 активирован */ s_ncache_buf[i] = (uint8_t) (i ^ 0xA5U);
g_is_in2_activated = true;
} }
if (ch == BSP_OPTO_CH_IN1 && state == BSP_OPTO_STATE_INACTIVE) /* Для non-cacheable памяти flush не нужен — данные уже когерентны.
* Вызываем CleanDCache чтобы убедиться что он не ломает данные. */
SCB_CleanDCache();
/* Читаем обратно и сравниваем */
for (uint32_t i = 0U; i < NCACHE_TEST_BUF_SIZE; i++)
{ {
/* IN1 деактивирован */ uint8_t expected = (uint8_t) (i ^ 0xA5U);
g_is_in1_deactivated = true;
if (s_ncache_buf[i] != expected)
{
LOG_E("NCACHE", "mismatch at [%lu]: got 0x%02x expected 0x%02x", (unsigned long) i,
s_ncache_buf[i], expected);
return false;
}
} }
if (ch == BSP_OPTO_CH_IN2 && state == BSP_OPTO_STATE_INACTIVE) return true;
{
/* IN2 деактивирован */
g_is_in2_deactivated = true;
}
} }
int main(void) int main(void)
{ {
const uint16_t DELAY_MS = 5; const uint16_t DELAY_MS = 100;
const uint32_t UART_BAUDRATE = 115200; const uint32_t UART_BAUDRATE = 115200;
const uint32_t CAN_BAUDRATE = 125000;
board_hw_init(); board_hw_init();
bsp_button_init();
bsp_led_init(); bsp_led_init();
bsp_tick_init(); bsp_tick_init();
bsp_uart_host_init(UART_BAUDRATE); bsp_uart_host_init(UART_BAUDRATE);
@ -58,89 +76,21 @@ int main(void)
LOG_I("BOOT", "firmware_test started, tick=%lu", (unsigned long) bsp_tick_get_ms()); LOG_I("BOOT", "firmware_test started, tick=%lu", (unsigned long) bsp_tick_get_ms());
bsp_can_config_t can_cfg = { .bitrate = CAN_BAUDRATE }; if (ncache_test_run())
bsp_status_t status = bsp_can_init(&can_cfg);
if (status != BSP_OK)
{ {
LOG_E("CAN", "CAN init failed:%d", can_cfg.bitrate); LOG_I("NCACHE", "OK addr=0x%08lx size=%u", (unsigned long) (uint32_t) s_ncache_buf,
} NCACHE_TEST_BUF_SIZE);
bsp_opto_config_t opto_cfg = {
.callbacks = { on_opto_change, on_opto_change, NULL },
.modes = { BSP_OPTO_MODE_LEVEL, BSP_OPTO_MODE_LEVEL, BSP_OPTO_MODE_LEVEL },
.edges = { BSP_OPTO_EDGE_RISING, BSP_OPTO_EDGE_RISING, BSP_OPTO_EDGE_RISING },
.rs_as_gpio = false,
.debounce_ms = DELAY_MS,
};
bsp_opto_init(&opto_cfg);
bsp_led_on(LED_APP);
status = bsp_can_accept_all();
if (status != BSP_OK)
{
LOG_E("CAN", "CAN init failed:%d", can_cfg.bitrate);
} }
else else
{ {
LOG_I("CAN", "CAN init OK"); LOG_E("NCACHE", "FAIL");
} }
bsp_can_frame_t rx_frame; bsp_led_on(LED_APP);
while (1) while (1)
{ {
bsp_opto_process(); bsp_led_toggle(LED_HEARTBEAT);
bsp_button_poll();
if (bsp_button_get_event_pressed(BSP_BUTTON_1))
{
LOG_D("BUTTON", "B1 was pressed");
}
if (bsp_button_get_event_released(BSP_BUTTON_1))
{
LOG_D("BUTTON", "B1 was released");
}
if (bsp_button_get_event_pressed(BSP_BUTTON_2))
{
LOG_D("BUTTON", "B2 was pressed");
}
if (bsp_button_get_event_released(BSP_BUTTON_2))
{
LOG_D("BUTTON", "B2 was released");
}
if (bsp_can_receive(&rx_frame, 0) == BSP_OK)
{
LOG_D("CAN", "RX: ID=0x%08X, DATA=%02X %02X %02X %02X", rx_frame.id, rx_frame.data[0],
rx_frame.data[1], rx_frame.data[2], rx_frame.data[3]);
}
// Контроль включения
if (g_is_in1_activated)
{
g_is_in1_activated = false;
LOG_D("INPUT", "CH1: ACTIVE!");
}
if (g_is_in2_activated)
{
g_is_in2_activated = false;
LOG_D("INPUT", "CH2: ACTIVE!");
}
// Контроль выключения
if (g_is_in1_deactivated)
{
g_is_in1_deactivated = false;
LOG_D("INPUT", "CH1: DISABLED!");
}
if (g_is_in2_deactivated)
{
g_is_in2_deactivated = false;
LOG_D("INPUT", "CH2: DISABLED!");
}
bsp_delay(DELAY_MS); bsp_delay(DELAY_MS);
} }
} }