0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

飞凌嵌入式 2025-06-13 16:14 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

嵌入式系统领域,嵌入式实时操作系统(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次后,释放信号量。信号量任务获的信号量,从阻塞态到运行态,打印计数。

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

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的例程演示,希望能够对各位工程师朋友有所帮助。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • ARM
    ARM
    +关注

    关注

    134

    文章

    9349

    浏览量

    377318
  • 嵌入式
    +关注

    关注

    5149

    文章

    19655

    浏览量

    317314
  • NXP
    NXP
    +关注

    关注

    61

    文章

    1347

    浏览量

    189273
  • FreeRTOS
    +关注

    关注

    12

    文章

    492

    浏览量

    64297
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    i.MX9352开发板试用】+机械臂游戏3—游戏源代码(开源)原创首发

    i.MX9352开发板试用】+机械臂游戏 3游戏操纵杆控制四自由度机械臂(开源)原创首发 -
    的头像 发表于 07-26 11:28 1387次阅读

    5分钟学会网络服务搭建,i.MX9352 + Linux 6.1实战示例

    本文将以嵌入式OK-MX9352-C开发板(搭载了在工业物联网领域广泛应用的NXP i.MX9352
    的头像 发表于 05-30 11:08 1683次阅读
    5分钟学会网络服务搭建,<b class='flag-5'>飞</b><b class='flag-5'>凌</b><b class='flag-5'>i.MX9352</b> + Linux 6.1实战示例

    嵌入式率先推出NXP i.MX6UL开发板

    6UltraLite处理器的OKMX6UL开发板,并于3月8日正式发布!嵌入式i.MX6UL核心
    发表于 03-12 15:11

    嵌入式 NXP i.MX6UL开发板

    嵌入式 NXP i.MX6UL开发板试用报告发布在哪里呢?
    发表于 01-15 15:10

    全球首发搭载i.MX 9352处理器的核心

    嵌入式正式全球首发搭载i.MX 9352处理器的FET-MX9352-C核心!​A
    发表于 12-28 10:27

    i.MX9352开发板试用】+ 开箱报告

    很幸运的这次成为了i.MX9352开发板的试用者,今天收到快递开始拆箱,做个简单的点评吧。 拆开后还是很惊艳的,板子设计的很精良,而且从元器件上也能看得出
    发表于 06-05 16:41

    i.MX 9352新品开发板强势来袭:高效安全的智能化升级,就用它!

    为了让更多设备实现高能效、高安全性和智能化升级,恩智浦推出了全新的 i.MX 93x系列处理器 。恩智浦金牌合作伙伴之一,嵌入式技术有限公司在i
    的头像 发表于 02-02 10:40 1346次阅读

    【精选直播】嵌入式:NXP i.MX 9352处理器的I3C接口详解

    直播简介 为了让更多设备实现高能效、高安全性和智能化升级,NXP推出了全新的i.MX 93x系列处理器。作为NXP的重要合作伙伴,嵌入式i.M
    的头像 发表于 05-16 09:35 1616次阅读

    首发!嵌入式i.MX9系列核心重磅发布

    嵌入式正式全球首发搭载i.MX 9352处理器的FET-MX9352-C核心
    的头像 发表于 12-28 14:37 1542次阅读
    首发!<b class='flag-5'>飞</b><b class='flag-5'>凌</b><b class='flag-5'>嵌入式</b><b class='flag-5'>i.MX</b>9系列核心<b class='flag-5'>板</b>重磅发布

    嵌入式技术帖——i.MX9352的GPIO怎么用?

    让我们一起走近i.MX9352处理器,深入了解这位i.MX系列新成员的GPIO该如何操作,以及它与前辈i.MX6ULL处理器又有哪些异同。
    的头像 发表于 05-16 15:07 1423次阅读
    <b class='flag-5'>飞</b><b class='flag-5'>凌</b><b class='flag-5'>嵌入式</b>技术帖——<b class='flag-5'>i.MX9352</b>的GPIO怎么用?

    嵌入式i.MX9352开发板,让通信安全又稳定

    嵌入式OK-MX9352-C开发板特意增加了接口防护电路设计,除了作为设计参考之外,还可以保障使用过程中的安全和稳定。
    的头像 发表于 08-11 14:09 967次阅读
    <b class='flag-5'>飞</b><b class='flag-5'>凌</b><b class='flag-5'>嵌入式</b><b class='flag-5'>i.MX9352</b><b class='flag-5'>开发板</b>,让通信安全又稳定

    OK-MX9352-C开发板 产品资料发布记录-20230206

    嵌入式OK-MX9352-C开发板产品资料发布记录-(20230206版)后续会有版本更新,请持续关注。
    发表于 02-13 09:04 9次下载

    3.1s启动!嵌入式i.MX93开发板部署LVGL,打造更高效的GUI

    近期,嵌入式为基于NXP i.MX93系列处理器打造的OK-MX9352-C开发板成功移植了
    的头像 发表于 01-16 11:52 754次阅读
    3.1s启动!<b class='flag-5'>飞</b><b class='flag-5'>凌</b><b class='flag-5'>嵌入式</b><b class='flag-5'>i.MX</b>93<b class='flag-5'>开发板</b>部署LVGL,打造更高效的GUI

    「2025恩智浦创新技术峰会」嵌入式亮相上海首站

    ,展示其在低成本人工智能、工业物联网等领域的创新成果。此次峰会,嵌入式带来了基于恩智浦i.MX95xx、i.MX9352
    的头像 发表于 05-15 13:38 676次阅读
    「2025恩智浦创新技术峰会」<b class='flag-5'>飞</b><b class='flag-5'>凌</b><b class='flag-5'>嵌入式</b>亮相上海首站

    5分钟学会网络服务搭建!i.MX9352开发板 + Linux 6.1实战示例

    本文就将以嵌入式OK-MX9352-C开发板(搭载了在工业物联网领域广泛应用的NXP i.MX935
    的头像 发表于 06-13 16:42 662次阅读
    5分钟学会网络服务搭建!<b class='flag-5'>飞</b><b class='flag-5'>凌</b><b class='flag-5'>i.MX9352</b><b class='flag-5'>开发板</b> + Linux 6.1实战示例