#include "sys_drv_init.h" #include "gpio.h" #include "usart.h" #include "app_rtc/app_rtc.h" #include "gd32h7xx.h" #include "can.h" #include "adc_temp.h" #include "nandflash_exmc_MT29F4G08.h" #include "exflash_spi4_gd25qxx.h" #include "flash_external_data.h" #include "adc_spi3_insuVolt.h" #include "adc_spi5_batVoltCurr.h" #include "fm24cl16.h" #include "tim/app_tim.h" #include "main.h" //#include /** * @brief 使能 Cortex-M7 指令/数据缓存 * @note 先失效 D-Cache,再开启 D-Cache,避免历史脏数据影响 */ static void cache_enable(void) { SCB_EnableICache(); SCB_DisableDCache(); SCB_InvalidateDCache(); SCB_EnableDCache(); } /** * @brief 配置 NVIC 优先级分组 * @note FreeRTOS 建议使用 PRE4_SUB0(4 位抢占优先级 + 0 位子优先级) */ static void nvic_configuration(void) { /* 统一中断优先级配置入口(参考 CCU601E_D 的 NVIC_Priority_Config 思路) */ nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0); /* ENET IRQ 内会调用 xSemaphoreGiveFromISR,优先级必须 >= configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(5) */ #ifdef USE_ENET0 nvic_irq_enable(ENET0_IRQn, 6U, 0U); #endif #ifdef USE_ENET1 nvic_irq_enable(ENET1_IRQn, 6U, 0U); #endif /* USART/UART 中断优先级统一配置 */ nvic_irq_enable(USART0_IRQn, 3U, 1U); nvic_irq_enable(USART2_IRQn, 3U, 2U); nvic_irq_enable(UART3_IRQn, 3U, 0U); nvic_irq_enable(UART4_IRQn, 2U, 0U); nvic_irq_enable(USART5_IRQn, 1U, 0U); nvic_irq_enable(UART6_IRQn, 0U, 0U); nvic_irq_enable(UART7_IRQn, 3U, 7U); /* ADC DMA 中断优先级统一配置 */ nvic_irq_enable(DMA1_Channel0_IRQn, 6U, 0U); /* CAN 中断优先级统一配置 */ nvic_irq_enable(CAN0_Message_IRQn, 0U, 0U); nvic_irq_enable(CAN1_Message_IRQn, 0U, 0U); nvic_irq_enable(CAN2_Message_IRQn, 0U, 0U); /* CAN error/busoff/warning IRQs (some CAN configs may route events here) */ nvic_irq_enable(CAN0_Busoff_IRQn, 0U, 0U); nvic_irq_enable(CAN0_Error_IRQn, 0U, 0U); nvic_irq_enable(CAN0_TEC_IRQn, 0U, 0U); nvic_irq_enable(CAN0_REC_IRQn, 0U, 0U); nvic_irq_enable(CAN1_Busoff_IRQn, 0U, 0U); nvic_irq_enable(CAN1_Error_IRQn, 0U, 0U); nvic_irq_enable(CAN1_TEC_IRQn, 0U, 0U); nvic_irq_enable(CAN1_REC_IRQn, 0U, 0U); nvic_irq_enable(CAN2_Busoff_IRQn, 0U, 0U); nvic_irq_enable(CAN2_Error_IRQn, 0U, 0U); nvic_irq_enable(CAN2_TEC_IRQn, 0U, 0U); nvic_irq_enable(CAN2_REC_IRQn, 0U, 0U); nvic_irq_enable(TIMER7_UP_IRQn, 5U, 0U); } /** * @brief 配置 MPU(Memory Protection Unit)区域属性 * * 详细说明: * 1) 该函数主要用于给“被 DMA 与 CPU 同时访问”的内存区域设置合适的属性, * 避免 D-Cache 引入的数据一致性问题(CPU 看到旧数据、DMA 写入不可见等)。 * * 2) 当前配置了两块 16KB 区域(均位于 SRAM3): * - 区域0:0x30000000 ~ 0x30003FFF * 典型用于 DMA 描述符、ETH Rx/Tx 缓冲等需要强一致性的内存。 * - 区域1:0x30004000 ~ 0x30007FFF * 典型用于 lwIP heap(pbuf/memp 等运行期内存)。 * * 3) 两个区域都设置为 Non-Cacheable(不可缓存): * - 目的:让 CPU 每次都从实际内存读取,保证与 DMA 读写一致。 * - 代价:这部分区域访问速度会比 Cacheable 区域慢,但稳定性更高。 * * 4) 该函数应在外设初始化前执行(当前在 v_sys_hardware_init() 早期调用), * 这样后续网络/DMA模块在运行时就使用了正确的内存属性。 * * 5) 结论:此函数是“网络与 DMA 稳定运行”的基础配置,尤其在 Cortex-M7 * 启用 D-Cache 场景下必不可少。 */ void mpu_config(void) { mpu_region_init_struct mpu_init_struct; mpu_region_struct_para_init(&mpu_init_struct); /* disable MPU */ ARM_MPU_SetRegion(0U, 0U); /* 区域0:DMA描述符/收发缓冲区(非缓存,避免 DMA 与 Cache 不一致) */ mpu_init_struct.region_base_address = 0x30000000; mpu_init_struct.region_size = MPU_REGION_SIZE_16KB; mpu_init_struct.access_permission = MPU_AP_FULL_ACCESS; mpu_init_struct.access_bufferable = MPU_ACCESS_BUFFERABLE; mpu_init_struct.access_cacheable = MPU_ACCESS_NON_CACHEABLE; mpu_init_struct.access_shareable = MPU_ACCESS_NON_SHAREABLE; mpu_init_struct.region_number = MPU_REGION_NUMBER0; mpu_init_struct.subregion_disable = MPU_SUBREGION_ENABLE; mpu_init_struct.instruction_exec = MPU_INSTRUCTION_EXEC_PERMIT; mpu_init_struct.tex_type = MPU_TEX_TYPE0; mpu_region_config(&mpu_init_struct); mpu_region_enable(); /* 区域1:lwIP heap(非缓存 + shareable,便于总线主设备协同访问) */ mpu_init_struct.region_base_address = 0x30004000; mpu_init_struct.region_size = MPU_REGION_SIZE_16KB; mpu_init_struct.access_permission = MPU_AP_FULL_ACCESS; mpu_init_struct.access_bufferable = MPU_ACCESS_NON_BUFFERABLE; mpu_init_struct.access_cacheable = MPU_ACCESS_NON_CACHEABLE; mpu_init_struct.access_shareable = MPU_ACCESS_SHAREABLE; mpu_init_struct.region_number = MPU_REGION_NUMBER1; mpu_init_struct.subregion_disable = MPU_SUBREGION_ENABLE; mpu_init_struct.instruction_exec = MPU_INSTRUCTION_EXEC_PERMIT; mpu_init_struct.tex_type = MPU_TEX_TYPE1; mpu_region_config(&mpu_init_struct); mpu_region_enable(); /* enable MPU */ ARM_MPU_Enable(MPU_MODE_PRIV_DEFAULT); } /** * @brief 系统硬件初始化总入口 * @note 按“基础系统 -> 通信/IO -> 业务外设”顺序初始化 */ void v_sys_hardware_init(void) { /* 基础系统配置 */ nvic_configuration(); mpu_config(); cache_enable(); /* 基础外设 */ /* 先初始化关键DO输出,避免上电过程继电器抖动/误动作 */ v_outpin_config(); v_rtc_init(); v_inpin_config(); /* 通信外设 */ v_usart_init_all(); /* EEPROM(FM24CL16) I2C1 初始化 */ eeprom_driver_init(); /* SPI Flash 驱动初始化(统一封装接口) */ (void)v_flash_dataflash_init(); /* CAN init moved into hardware stage to avoid first-frame loss after power-on. */ v_can_interface_init(); /* 1ms hardware timer interrupt for periodic software counters. */ v_app_tim_init(); /* 以太网与 lwIP 须在 FreeRTOS 调度器启动后初始化(见 app_os_init), * 否则 enet_system_setup() 失败会死在 while(1),运行灯也不会亮。 */ /* 采样与电源相关外设 */ adc_spi3_insuVolt_init(); adc_spi5_batVoltCurr_init(); v_temp_config(); // v_4g_config(); /* 可选外设(按需启用) exmc_nandflash_init(); lwip_system_init(); */ }