diff --git a/bsp/generated/board.c b/bsp/generated/board.c index 30057ea..419022e 100644 --- a/bsp/generated/board.c +++ b/bsp/generated/board.c @@ -1,10 +1,105 @@ #include "board.h" #include "clock_config.h" +#include "core_cm7.h" +#include "fsl_common.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) { BOARD_InitPins(); BOARD_BootClockRUN(); + board_mpu_init(); } diff --git a/cmake/linker/MIMXRT1052xxxxx_flexspi_nor.ld b/cmake/linker/MIMXRT1052xxxxx_flexspi_nor.ld index a575ed8..31b6c2a 100644 --- a/cmake/linker/MIMXRT1052xxxxx_flexspi_nor.ld +++ b/cmake/linker/MIMXRT1052xxxxx_flexspi_nor.ld @@ -26,8 +26,8 @@ /* Entry Point */ ENTRY(Reset_Handler) -HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400; -STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0400; +HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x2000; +STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x1000; VECTOR_RAM_SIZE = DEFINED(__ram_vector_table__) ? 0x00000400 : 0; /* Specify the memory areas */ @@ -46,7 +46,7 @@ MEMORY SECTIONS { __NCACHE_REGION_START = ORIGIN(m_data2); - __NCACHE_REGION_SIZE = 0; + __NCACHE_REGION_SIZE = 0x2000; /* 8 KB non-cacheable for USB DMA */ .flash_config : { @@ -205,24 +205,26 @@ SECTIONS } > m_qacode __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) . = ALIGN(4); - __noncachedata_init_end__ = .; /* create a global symbol at initialized ncache data end */ - } > m_data + __noncachedata_init_end__ = .; + } > m_data2 . = __noncachedata_init_end__; .ncache : { *(NonCacheable) . = ALIGN(4); - __noncachedata_end__ = .; /* define a global symbol at ncache data end */ - } > m_data + __noncachedata_end__ = .; + } > m_data2 - __DATA_END = __NDATA_ROM + (__noncachedata_init_end__ - __noncachedata_start__); + __DATA_END = __NDATA_ROM; text_end = ORIGIN(m_text) + LENGTH(m_text); 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 */ .bss : diff --git a/cmake/linker/MIMXRT1052xxxxx_ram.ld b/cmake/linker/MIMXRT1052xxxxx_ram.ld index 6dad340..491e100 100644 --- a/cmake/linker/MIMXRT1052xxxxx_ram.ld +++ b/cmake/linker/MIMXRT1052xxxxx_ram.ld @@ -26,8 +26,8 @@ /* Entry Point */ ENTRY(Reset_Handler) -HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400; -STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0400; +HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x2000; +STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x1000; /* Specify the memory areas */ MEMORY @@ -41,8 +41,12 @@ MEMORY /* Define output 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_SIZE = 0; + __NCACHE_REGION_SIZE = 0x2000; /* 8 KB — USB ep bufs + DMA descriptors */ /* The startup code goes first into internal RAM */ .interrupts : @@ -161,24 +165,26 @@ SECTIONS } > m_data __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) . = ALIGN(4); - __noncachedata_init_end__ = .; /* create a global symbol at initialized ncache data end */ - } > m_data + __noncachedata_init_end__ = .; + } > m_data2 . = __noncachedata_init_end__; .ncache : { *(NonCacheable) . = ALIGN(4); - __noncachedata_end__ = .; /* define a global symbol at ncache data end */ - } > m_data + __noncachedata_end__ = .; + } > m_data2 - __DATA_END = __NDATA_ROM + (__noncachedata_init_end__ - __noncachedata_start__); - text_end = ORIGIN(m_text) + LENGTH(m_text); - ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data") + /* ncache sections are now in m_data2; DATA_END tracks only m_data usage */ + __DATA_END = __NDATA_ROM; + 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 */ .bss : diff --git a/firmware/test/main.c b/firmware/test/main.c index c284128..e159f28 100644 --- a/firmware/test/main.c +++ b/firmware/test/main.c @@ -1,56 +1,74 @@ #include "board.h" -#include "bsp/button.h" -#include "bsp/can.h" #include "bsp/led.h" -#include "bsp/opto.h" #include "bsp/tick.h" #include "bsp/uart_host.h" +#include "fsl_common.h" #include "log/log.h" #include "port/log_uart.h" #include #include +#include -static volatile bool g_is_in1_activated = false; -static volatile bool g_is_in2_activated = false; -static volatile bool g_is_in1_deactivated = false; -static volatile bool g_is_in2_deactivated = false; +/* -------------------------------------------------------------------------- + * Проверка non-cacheable региона + * -------------------------------------------------------------------------- + * Буфер размещён в секции 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 активирован */ - g_is_in1_activated = true; + LOG_E("NCACHE", "buf addr 0x%08lx outside ncache region [0x%08x..0x%08x)", + (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 активирован */ - g_is_in2_activated = true; + s_ncache_buf[i] = (uint8_t) (i ^ 0xA5U); } - 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 деактивирован */ - g_is_in1_deactivated = true; + uint8_t expected = (uint8_t) (i ^ 0xA5U); + + 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) - { - /* IN2 деактивирован */ - g_is_in2_deactivated = true; - } + return true; } int main(void) { - const uint16_t DELAY_MS = 5; + const uint16_t DELAY_MS = 100; const uint32_t UART_BAUDRATE = 115200; - const uint32_t CAN_BAUDRATE = 125000; board_hw_init(); - bsp_button_init(); + bsp_led_init(); bsp_tick_init(); 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()); - bsp_can_config_t can_cfg = { .bitrate = CAN_BAUDRATE }; - bsp_status_t status = bsp_can_init(&can_cfg); - if (status != BSP_OK) + if (ncache_test_run()) { - LOG_E("CAN", "CAN init failed:%d", can_cfg.bitrate); - } - - 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); + LOG_I("NCACHE", "OK addr=0x%08lx size=%u", (unsigned long) (uint32_t) s_ncache_buf, + NCACHE_TEST_BUF_SIZE); } else { - LOG_I("CAN", "CAN init OK"); + LOG_E("NCACHE", "FAIL"); } - bsp_can_frame_t rx_frame; + bsp_led_on(LED_APP); while (1) { - bsp_opto_process(); - 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_led_toggle(LED_HEARTBEAT); bsp_delay(DELAY_MS); } }