【飞凌嵌入式】基于i.MX9352开发板M核的FreeRTOS设计例程

科技堆里的狠货 2025-06-17 阅读:9227 评论:0

嵌入式系统领域,嵌入式实时操作系统(RTOS) 的应用正日益广泛,采用RTOS能够更合理、更高效地利用CPU资源,FreeRTOS作为一款轻量级且成熟的实时操作系统内核,其核心功能完备,包括任务管理、时间管理(如延时、定时器)、同步机制(信号量、互斥锁)、进程间通信(消息队列)等等。这些特性使其能够很好地满足资源相对有限的中小型嵌入式系统的需求。

i.MX 9352作为NXP 推出的新一代轻量级边缘AI处理器,集成2个Cortex-A55核和1个Cortex-M33实时核,其架构设计充分体现了对实时性与复杂任务处理能力的兼顾。为了帮助开发者充分利用i.MX 9352 M33核的实时能力,其配套的M核SDK包提供的FreeRTOS例程分为两类,一类介绍FreeRTOS系统组件特性,如信号量、互斥量、队列等,另一类是介绍外设接口如何在FreeRTOS使用,我们分别挑选这两类下的例程进行演示。

演示平台:飞凌嵌入式OK-MX9352-C开发板

947ec1d118914d02ad1aa7e1e4e7710a~tplv-tt-origin-web:gif.jpeg?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1750406773&x-signature=8X4xOjMgo7JENGAUiQ7QpbXJQVc%3D

1、FreeRTOS-generic

飞凌嵌入式OK-MX9352-C开发板支持FreeRTOS功能特性示例代码如下:

  • freertos_event:任务事件演示例程
  • freertos_queue:队列消息实现任务间通信的演示例程
  • freertos_mutex:互斥锁使用例程
  • freertos_sem:信号量使用例程
  • freertos_swtimer:软件计数器及其回调的用法。
  • freertos_tickless:使用 LPTMR 延时唤醒或者硬件中断唤醒例程
  • freertos_generic:task、queue、swtimer、tick hook 、semaphore 组合利用演示例程。

因FreeRTOS_generic例程使用的FreeRTOS特性较多,我们重点分析此例程。

(1)软件实现

示例程序内容包括:任务创建、队列、软定时器、系统节拍时钟、信号量、异常处理。具体如下:

任务创建:

主函数创建了队列发送、接收,信号量三个任务。

// 创建队列接收任务 if(xTaskCreate(prvQueueReceiveTask,"Rx",configMINIMAL_STACK_SIZE+166,NULL,mainQUEUE_RECEIVE_TASK_PRIORITY,NULL)!=pdPASS) // 创建队列发送任务 if(xTaskCreate(prvQueueSendTask,"TX",configMINIMAL_STACK_SIZE+166, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL) !=pdPASS) // 创建信号量任务 if(xTaskCreate(prvEventSemaphoreTask,"Sem",configMINIMAL_STACK_SIZE+166,NULL,mainEVENT_SEMAPHORE_TASK_PRIORITY, NULL) != pdPASS)

队列:

队列发送任务,阻塞200ms后向队列发送数据;队列接收任务,任务阻塞读取队列,数据读取正确,则打印此时的队列接收数量。

// 队列发送任务,阻塞200ms后 向队列发送数据 static void prvQueueSendTask(void *pvParameters) { TickType_t xNextWakeTime; const uint32_t ulValueToSend = 100UL; xNextWakeTime = xTaskGetTickCount(); for (;;) { // 任务阻塞,直至200ms延时结束 vTaskDelayUntil(&xNextWakeTime, mainQUEUE_SEND_PERIOD_MS); // 向队列发送数据,阻塞时间为0表示当队列满的时候就立即返回 xQueueSend(xQueue, &ulValueToSend, 0); } } // 队列接收任务,任务阻塞读取队列,数据读取正确,则打印此时的队列接收数量。 static void prvQueueReceiveTask(void *pvParameters) { uint32_t ulReceivedValue; for (;;) { // 任务一直阻塞,知道队列内读取到数据 xQueueReceive(xQueue, &ulReceivedValue, portMAX_DELAY); // 队列数据和发送一致,队列接收数量+1 输出此时的队列接收数量 if (ulReceivedValue == 100UL) { ulCountOfItemsReceivedOnQueue++; PRINTF("Receive message counter: %d.\r\n", ulCountOfItemsReceivedOnQueue); } } }

软定时器:

设置软定时器周期1s,时间到后,调用回调函数,记录次数并串口打印。

// 创建软件定时器任务 时间为1s,周期循环 xExampleSoftwareTimer = xTimerCreate( "LEDTimer", mainSOFTWARE_TIMER_PERIOD_MS, pdTRUE, (void *)0, vExampleTimerCallback); // 启动软件定时器 xTimerStart(xExampleSoftwareTimer, 0); // 回调函数 static void vExampleTimerCallback(TimerHandle_t xTimer) { // 每1s进入一次回调函数,计数增加 ulCountOfTimerCallbackExecutions++; PRINTF("Soft timer: %d s.\r\n", ulCountOfTimerCallbackExecutions); }

系统节拍时钟:

通过设置文件 FreeRTOSConfig.h 中 configTICK_RATE_HZ 设置任务节拍中断频率, 在启动任务调度器时,系统会根据另一个变量CPU的频率configCPU_CLOCK_HZ计算对应写入节拍计数器的值,启动定时器中断。

// 设置系统时钟节拍为 1000/200=5ms #define configTICK_RATE_HZ ((TickType_t)200)

信号量:

每个系统节拍时钟中断中,调用函数vApplicationTickHook,累积500次即500*5ms=2.5s后,发送信号量。信号量任务获取信号后,计数并打印累积次数。

// 系统节拍为5ms,每个500*5ms=2.5s 释放事件信号量 void vApplicationTickHook(void) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; static uint32_t ulCount = 0; ulCount++; if (ulCount >= 500UL) { // 在中断中释放事件信号量 xSemaphoreGiveFromISR(xEventSemaphore, &xHigherPriorityTaskWoken); ulCount = 0UL; } } // 任务阻塞等待信号量,收到后,接收次数增加,并通过串口打印 static void prvEventSemaphoreTask(void *pvParameters) { for (;;) { // 任务阻塞,直到能获取信号量 if (xSemaphoreTake(xEventSemaphore, portMAX_DELAY) != pdTRUE) { PRINTF("Failed to take semaphore.\r\n"); } // 接收到信号量的次数累加 ulCountOfReceivedSemaphores++; PRINTF("Event task is running. Get semaphore :%d \r\n",ulCountOfReceivedSemaphores); } }

异常处理:

当内存分配失败、堆栈发生错误或任务空闲时,进入相应的函数,用户可添加相应的处理函数。

// 内存分配失败函数,当内存分配失败时,进入此函数 void vApplicationMallocFailedHook(void) { for (;;) ; } // 堆栈错误检查函数,当堆栈发生溢出时,进入此函数 void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { (void)pcTaskName; (void)xTask; for (;;) ; } // 空闲任务,优先级最低,没有实际意义,只是让CPU有事情做,用户可以自己添加自己的函数 void vApplicationIdleHook(void) { volatile size_t xFreeStackSpace; xFreeStackSpace = xPortGetFreeHeapSize(); if (xFreeStackSpace > 100) { } }

(2)实验现象

① 编译程序:在uboot手动加载M核程序。

② 队列:每隔200ms,队列发送任务发送数据,队列接收任务获取数据,从阻塞态到运行态,打印计数。

③ 软定时器:每隔1s,时间到达,调用回调函数,打印计数。

④ 信号量:每隔5ms,系统时钟节拍中断调用函数,超过500次后,释放信号量。信号量任务获的信号量,从阻塞态到运行态,打印计数。

2、FreeRTOS-外设

飞凌嵌入式OK-MX9352-C开发板支持外设使用FreeRTOS完成相应功能,示例代码如下:

  • freertos_uart:freertos串口演示例程
  • freertos_lpi2c_b2b:freertos I2C演示例程
  • freertos_lpspi_b2b:freertos SPI演示例程

因freertos_uart例程使用的FreeRTOS特性比较典型,我们重点分析此例程。

(1)软件实现

示例程序内容包括:串口初始化任务、串口发送任务、串口接收任务。具体如下:

串口初始化任务:

主要包含串口外设初始化,发送、接收互斥量,发送和接收事件组。串口外设初始化在裸跑串口例程中已展现,此处不再详述。

// 创建串口发送互斥量 handle->txSemaphore = xSemaphoreCreateMutex(); // 创建串口接收互斥量 handle->rxSemaphore = xSemaphoreCreateMutex(); // 创建发送事件标志组 handle->txEvent = xEventGroupCreate(); // 创建接收事件标志组 handle->rxEvent = xEventGroupCreate();

串口发送:

发送前获取信号量,启动发送流程,在中断中置位发送完成事件标志。发送任务获取到事件后,释放发送信号量。

// 1 获取发送信号量 if (pdFALSE == xSemaphoreTake(handle->txSemaphore, 0)) { return kStatus_Fail; } handle->txTransfer.data = (uint8_t *)buffer; handle->txTransfer.dataSize = (uint32_t)length; // 2 阻塞式发送 status = UART_TransferSendNonBlocking(handle->base, handle->t_state, &handle->txTransfer); if (status != kStatus_Success) { (void)xSemaphoreGive(handle->txSemaphore); return kStatus_Fail; } // 3 等待发送完成的事件 ev = xEventGroupWaitBits(handle->txEvent, RTOS_UART_COMPLETE, pdTRUE, pdFALSE, portMAX_DELAY);// 等待并判断多个事件位 if ((ev & RTOS_UART_COMPLETE) == 0U) { retval = kStatus_Fail; } // 4 发送完成,释放发送信号量 if (pdFALSE == xSemaphoreGive(handle->txSemaphore)) // 释放信号量 { retval = kStatus_Fail; }

串口接收:

接收前获取信号量,调用串口接收函数,在中断中置位获取事件标志。接收任务获取到事件后,释放接收信号量。

// 1获取接收信号量 if (pdFALSE == xSemaphoreTake(handle->rxSemaphore, portMAX_DELAY)) { return kStatus_Fail; } handle->rxTransfer.data = buffer; handle->rxTransfer.dataSize = (uint32_t)length; // 2 串口接收函数 status = UART_TransferReceiveNonBlocking(handle->base, handle->t_state, &handle->rxTransfer, &n); if (status != kStatus_Success) { (void)xSemaphoreGive(handle->rxSemaphore); return kStatus_Fail; } // 3 获取接收事件 ev = xEventGroupWaitBits(handle->rxEvent,RTOS_UART_COMPLETE | RTOS_UART_RING_BUFFER_OVERRUN | RTOS_UART_HARDWARE_BUFFER_OVERRUN, pdTRUE, pdFALSE, portMAX_DELAY); // 等待并判断接收完成事件位 // 3.1 硬件接收错误 if ((ev & RTOS_UART_HARDWARE_BUFFER_OVERRUN) != 0U) { UART_TransferAbortReceive(handle->base, handle->t_state); (void)xEventGroupClearBits(handle->rxEvent, RTOS_UART_COMPLETE); // 将接收完成的事件位清零, retval = kStatus_UART_RxHardwareOverrun; local_received = 0; } // 3.2 接收缓冲区过载错误 else if ((ev & RTOS_UART_RING_BUFFER_OVERRUN) != 0U) { UART_TransferAbortReceive(handle->base, handle->t_state); (void)xEventGroupClearBits(handle->rxEvent, RTOS_UART_COMPLETE); // 将接收完成的事件位清零, retval = kStatus_UART_RxRingBufferOverrun; local_received = 0; } // 3.3 接收完成 else if ((ev & RTOS_UART_COMPLETE) != 0U) { retval = kStatus_Success; local_received = length; } else { retval = kStatus_UART_Error; local_received = 0; } // 4 释放接收信号量 if (pdFALSE == xSemaphoreGive(handle->rxSemaphore)) { retval = kStatus_Fail; }

(2)实验现象

① 编译程序,在uboot手动加载M核程序。

② 装置上电后,串口打印程序信息,此时通过键盘输入4个字符,M核调试串口将回显,重复输入和回显字符,证明程序运行成功。

4353b0d8f34c483480f70cc3b602e913~tplv-tt-origin-web:gif.jpeg?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1750406773&x-signature=DnmR9MNzFFyT684zNG2BqZrJdN8%3D


以上就是在飞凌嵌入式i.MX 9352开发板M核上软件设计FreeRTOS的例程演示,希望能够对各位工程师朋友有所帮助。

热门文章
  • 在中超联赛赛场北京成都球迷高呼:北京加油,成都雄起

    在中超联赛赛场北京成都球迷高呼:北京加油,成都雄起
      9月14日晚,中超联赛成都蓉城对北京国安的比赛在成都凤凰山体育场举行。首都文明办工作人员到现场力促两地球迷的友好互动,引导球迷文明观赛。   开赛前,两地球迷早早来到赛场,成都球迷在赛场通道为等待入场的北京球迷拉歌拍照。一边是北京球迷激昂的歌声,一边是身穿“雄起”“成都”等字样球衣的成都球迷,画面和谐温馨。首都文明办给两地球迷代表赠送了“向北京榜样学习”宣传品,呼吁两地球迷在场上是对手,在场下是朋友。合影留念时,成都球迷高喊“北京加油”,北京球迷高喊“成都雄起”。...
  • 防风防寒!北京今天晴朗伴大风寒意十足 周末将迎小幅升温

    防风防寒!北京今天晴朗伴大风寒意十足 周末将迎小幅升温
      中国天气网讯 今天(12月27日),北京天气晴间多云,最高气温2℃,白天北风劲吹,阵风可达六至七级,风寒效应明显。本周末,北京仍以晴为主,风力不大,气温将有小幅上升。   昨天,北京晴冷在线,气温继续下跌,南郊观象台最高气温仅有2.6℃,加上风力较大,体感十分寒冷。   北京市气象台预计,今天白天晴间多云,北风三四级(阵风六七级),最高气温2℃;夜间晴间多云,北风二三级间四级,最低气温零下7℃。   明后两天,北京仍以晴为主,风力不大,最高气温将略升至5℃,最低气温...
  • 新手如何开始跑步?

    新手如何开始跑步?
    大家好,我是小贝~ 有喜欢我的分享的可以给我点个关哟~多多互动吧~🫰 跑步是最简单的运动之一。人类进化30万年,跑步是基因自带的能力。可以说天生人人都会跑,人人都可以跑。 所以,很多平时不跑步的人,想入门跑步,建议从以下4个方面开始 一、跑步一定要穿跑鞋! 10年前我跑步穿平时的休闲鞋跑了2周,跟腱受伤!因为休闲鞋没有缓震效果;对膝盖和跟腱的损害较大。 专业跑鞋鞋底有缓震设计,能减少跑步时对膝盖和脚踝的冲击力。保护膝盖和脚踝不容易受伤。 二、注意跑步频率和强度。 1、频率...
  • 西南地区持续阴雨天气 华北黄淮等地大气扩散条件逐步转差

    西南地区持续阴雨天气 华北黄淮等地大气扩散条件逐步转差
      摘要:   国内方面,昨日,全国降水整体较弱;内蒙古、东北地区等地出现大风降温天气。未来三天,青藏高原及云南、四川、贵州等地多阴雨天气,关注局地强降雨或持续降雨可能引发的次生灾害。   全球方面,昨日,欧洲东部美国东南部等地出现强降雨。未来三天,飓风“米尔顿”继续影响美国东南部等地;强冷空气影响中亚等地;欧洲大部大范围降水降温。   一、国内天气情况   1.实况   全国降水整体较弱 内蒙古东北地区等地出现大风降温天气   昨日8时至今日6时,全国降水整体较...
  • 大雾黄色预警:京津冀等8省市部分地区有大雾 局地强浓雾

    大雾黄色预警:京津冀等8省市部分地区有大雾 局地强浓雾
      据报道10月14日电据中央气象台网站消息,预计10月14日早晨至上午,河北中南部、北京、天津西部、山东西部、山西中东部、陕西北部、河南东北部和南部部分地区、湖北中部等地有大雾天气,其中,河北中南部、北京西部、山西中部、陕西北部、湖北中部等地的部分地区有能见度低于500米的浓雾,局地有不足200米的强浓雾。中央气象台14日6时继续发布大雾黄色预警。   此外,14日,华北中南部、黄淮中西部、汾渭平原等地大气扩散条件较差,有轻至中度霾,其中,北京南部、河北西部沿山部分地区有...