FreeRTOS在Zynq平台的双核任务创建与核间通信实践

张开发
2026/4/21 16:14:44 15 分钟阅读

分享文章

FreeRTOS在Zynq平台的双核任务创建与核间通信实践
1. FreeRTOS任务创建基础与Zynq平台特性在嵌入式系统开发中实时操作系统(RTOS)扮演着至关重要的角色。FreeRTOS作为一款轻量级、开源的RTOS内核凭借其可裁剪性和高可靠性成为资源受限嵌入式设备的首选方案。Xilinx Zynq-7000系列SoC结合了双核ARM Cortex-A9处理系统(PS)和可编程逻辑(PL)为FreeRTOS提供了强大的硬件支持平台。1.1 FreeRTOS任务管理机制FreeRTOS的任务调度采用基于优先级的抢占式机制支持时间片轮转调度。每个任务都拥有独立的栈空间和任务控制块(TCB)内核通过TCB管理任务状态。任务状态主要包括就绪态(Ready)等待被调度执行运行态(Running)当前正在执行的任务阻塞态(Blocked)等待事件或延时挂起态(Suspended)被显式挂起的任务任务创建API原型如下BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, // 任务函数指针 const char * const pcName, // 任务名称(调试用) configSTACK_DEPTH_TYPE usStackDepth, // 栈深度(以字为单位) void *pvParameters, // 任务参数 UBaseType_t uxPriority, // 任务优先级 TaskHandle_t *pxCreatedTask // 任务句柄(可选) );1.2 Zynq平台的双核架构特点Zynq-7000 SoC的PS部分包含两个ARM Cortex-A9核心每个核心具有私有32KB L1指令缓存和32KB L1数据缓存共享512KB L2缓存私有定时器和看门狗共享中断控制器(GIC)双核间通信可通过以下方式实现共享内存(OCM/DDR)软件中断(SGI)硬件信号量模块通过PL实现的定制通信接口在AMP模式下两个核心可以分别运行不同的操作系统或裸机程序实现真正的非对称多处理。这种架构特别适合将实时任务(如电机控制)和复杂应用(如用户界面)分离到不同核心执行。2. AMP系统构建与FreeRTOS任务实现2.1 AMP系统启动流程在Zynq平台上实现AMP需要特殊的启动流程核心0执行FSBL(First Stage Boot Loader)FSBL加载核心0应用和核心1应用到指定内存区域核心0通过写特定地址(0xFFFFFFF0)设置核心1的启动地址核心0执行SEV指令唤醒核心1两个核心开始并行执行各自程序关键启动代码如下// 设置核心1启动地址 Xil_Out32(CPU1STARTADR, 0x00200000); dmb(); // 内存屏障确保写入完成 sev(); // 发送事件信号唤醒核心12.2 FreeRTOS任务创建实例示例代码展示了如何创建两个任务通过队列通信// 定义任务优先级 #define mainQUEUE_RECEIVE_TASK_PRIORITY (tskIDLE_PRIORITY 2) #define mainQUEUE_SEND_TASK_PRIORITY (tskIDLE_PRIORITY 1) // 创建队列(长度为1存储uint32_t类型数据) xQueue xQueueCreate(mainQUEUE_LENGTH, sizeof(uint32_t)); // 创建接收任务 xTaskCreate(prvQueueReceiveTask, Rx, configMINIMAL_STACK_SIZE, NULL, mainQUEUE_RECEIVE_TASK_PRIORITY, NULL); // 创建发送任务 xTaskCreate(prvQueueSendTask, Tx, configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL);发送任务周期性从XADC读取温度数据并发送到队列static void prvQueueSendTask(void *pvParameters) { TickType_t xNextWakeTime xTaskGetTickCount(); uint32_t ulValueToSend; for(;;) { // 200ms周期延时 vTaskDelayUntil(xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS); // 读取XADC温度数据 ulValueToSend XAdcPs_GetAdcData(XADCInst, XADCPS_CH_TEMP); // 发送数据到队列(非阻塞) xQueueSend(xQueue, ulValueToSend, 0U); } }接收任务从队列获取数据并控制LEDstatic void prvQueueReceiveTask(void *pvParameters) { uint32_t ulReceivedValue; for(;;) { // 阻塞等待队列数据 xQueueReceive(xQueue, ulReceivedValue, portMAX_DELAY); // 如果收到特定值则点亮LED if(ulReceivedValue ulExpectedValue) { vParTestSetLED(mainTASK_LED, 1); } } }2.3 XADC配置与使用Zynq内置XADC(7系列XADC)可用于监测芯片温度和供电电压。配置流程如下void adc_config(XAdcPs *XADCInstPtr, u16 XAdcDeviceId) { XAdcPs_Config *ConfigPtr; // 查找XADC配置 ConfigPtr XAdcPs_LookupConfig(XAdcDeviceId); // 初始化XADC XAdcPs_CfgInitialize(XADCInstPtr, ConfigPtr, ConfigPtr-BaseAddress); // 设置单通道模式 XAdcPs_SetSequencerMode(XADCInstPtr, XADCPS_SEQ_MODE_SINGCHAN); // 禁用报警 XAdcPs_SetAlarmEnables(XADCInstPtr, 0x0); // 配置安全输入模式 XAdcPs_SetSeqInputMode(XADCInstPtr, XADCPS_SEQ_MODE_SAFE); // 启用温度、电压监测通道 XAdcPs_SetSeqChEnables(XADCInstPtr, XADCPS_CH_TEMP | XADCPS_CH_VCCINT | XADCPS_CH_VCCAUX | XADCPS_CH_VBRAM); }3. 核间通信与同步机制实现3.1 共享内存(OCM)通信Zynq的256KB OCM是最低延迟的共享内存资源使用前需注意必须禁用OCM的缓存属性以避免一致性问题需要明确划分各核心的内存区域建议使用内存屏障指令保证访问顺序OCM配置示例// 禁用OCM缓存(地址0xFFFF0000开始的64KB区域) Xil_SetTlbAttributes(0xFFFF0000, 0x14de2); // 核心0写入数据到共享地址 Xil_Out8(0xFFFF0000, data); // 核心1从共享地址读取数据 uint8_t received_data Xil_In8(0xFFFF0000);3.2 软件中断(SGI)同步Zynq的GIC支持16个软件生成中断(SGI)可用于核间同步定义公共中断号(0-15)接收核心配置中断处理程序发送核心触发中断中断配置代码// 核心1中断配置 XScuGic_Connect(Intc, SW_INT_ID, (Xil_ExceptionHandler)sgi_handler, (void *)Intc); XScuGic_Enable(Intc, SW_INT_ID); // 核心0触发中断 XScuGic_SoftwareIntr(Intc, SW_INT_ID, XSCUGIC_SPI_CPU1_MASK); // 中断处理程序 static void sgi_handler(void *CallBackRef) { u32 INT Xil_In32(0xF8F0010C); // 读取IAR清除中断 cpu0_data Xil_In8(SHARED_ADDR); // 读取共享数据 }3.3 内存分区与链接脚本配置确保两个核心应用不互相干扰的关键是正确配置内存布局核心0链接脚本片段MEMORY { ps7_ram_0 : ORIGIN 0x00000000, LENGTH 0x00030000 ps7_ram_1 : ORIGIN 0xFFFF0000, LENGTH 0x00010000 }核心1链接脚本片段MEMORY { ps7_ram_0 : ORIGIN 0x00100000, LENGTH 0x00030000 ps7_ram_1 : ORIGIN 0xFFFF0000, LENGTH 0x00010000 }4. 系统调试与性能优化4.1 常见问题排查核心1无法启动检查FSBL是否支持AMP模式确认CPU1STARTADR地址写入正确验证SEV指令执行核间通信数据不一致确保OCM区域缓存已禁用检查内存屏障指令使用验证地址映射一致性中断无法触发确认GIC已正确初始化检查SGI ID和CPU掩码设置验证中断处理程序注册4.2 性能优化建议减少共享资源争用为每个核心分配独立的DDR区域使用核心私有外设(如私有定时器)避免频繁的核间中断优化通信机制批量传输代替单次传输使用DMA加速大数据传输考虑无锁环形缓冲区设计实时性保障为实时任务分配更高优先级禁用核心间中断抢占监控最坏情况响应时间5. 进阶应用PL协同处理Zynq的独特优势在于PS和PL的紧密集成。通过PL可以实现硬件加速器提升处理性能创建定制外设接口构建高效的DMA引擎PL与PS协同工作示例// 初始化PL端GPIO XGpio_Initialize(Gpio, GPIO_DEVICE_ID); XGpio_SetDataDirection(Gpio, CHANNEL, 0x00); // 从PS控制PL GPIO XGpio_DiscreteWrite(Gpio, CHANNEL, led_pattern);在AMP系统中可以将PL资源分配给特定核心独占使用或通过仲裁逻辑实现共享访问。PL还可以实现硬件信号量等高级同步原语进一步提升核间通信效率。

更多文章