当前位置: 首页 > article >正文

FreeRTOS在RISC-V上的第一个main.c:从创建任务到理解Hook函数的完整流程

FreeRTOS在RISC-V上的第一个main.c从创建任务到理解Hook函数的完整流程当你在RISC-V平台上第一次打开main.c文件准备编写FreeRTOS应用时可能会被那些看似神秘的函数和配置选项所困扰。这篇文章将带你从零开始逐步构建一个完整的FreeRTOS应用并深入理解那些关键但容易被忽视的Hook函数。1. 环境准备与硬件初始化在开始编写main.c之前我们需要确保开发环境已经正确设置。对于RISC-V平台通常需要安装RISC-V工具链如SiFive提供的工具链配置好开发板的支持包准备好FreeRTOS的RISC-V移植层代码prvSetupHardware()函数是main.c中第一个需要关注的函数。它负责初始化硬件平台为FreeRTOS的运行做好准备。一个典型的实现可能如下static void prvSetupHardware(void) { /* 禁用中断确保初始化过程不被中断 */ portDISABLE_INTERRUPTS(); /* 初始化系统时钟 */ SystemClock_Config(); /* 初始化调试串口 */ DebugConsole_Init(); /* 其他必要的外设初始化 */ // ... }注意硬件初始化阶段应避免调用任何FreeRTOS API因为此时调度器尚未启动。2. 任务创建与管理FreeRTOS的核心是多任务管理。在main函数中我们通常会创建初始任务然后启动调度器。让我们看一个创建两个简单任务的例子static void vTask1(void *pvParameters) { while(1) { printf(Task 1 running\n); vTaskDelay(pdMS_TO_TICKS(500)); } } static void vTask2(void *pvParameters) { while(1) { printf(Task 2 running\n); vTaskDelay(pdMS_TO_TICKS(1000)); } } void AppTaskCreate(void) { xTaskCreate(vTask1, Task1, configMINIMAL_STACK_SIZE, NULL, 2, NULL); xTaskCreate(vTask2, Task2, configMINIMAL_STACK_SIZE, NULL, 1, NULL); }任务创建时需要考虑的几个关键参数参数说明典型值任务函数任务执行的函数指针-任务名称用于调试的字符串不超过configMAX_TASK_NAME_LEN堆栈大小以字(word)为单位根据任务需求调整参数传递给任务的指针NULL或自定义结构体指针优先级数值越大优先级越高1到configMAX_PRIORITIES-13. 调度器启动与系统运行创建任务后我们需要启动FreeRTOS调度器这是通过vTaskStartScheduler()函数实现的。这个函数永远不会返回除非发生严重错误因为它会开始执行任务调度。int main(void) { prvSetupHardware(); AppTaskCreate(); /* 启动调度器 - 永不返回 */ vTaskStartScheduler(); /* 如果调度器返回说明发生了严重错误 */ for(;;); return 0; }调度器启动后FreeRTOS会做以下几件事创建空闲任务优先级为0如果启用了软件定时器会创建定时器服务任务开始根据优先级调度用户创建的任务处理任务切换、延时等核心功能4. 深入理解Hook函数Hook函数是FreeRTOS提供的一种回调机制允许用户在特定事件发生时插入自定义代码。这些函数在调试和系统监控中非常有用。4.1 栈溢出检测钩子栈溢出是嵌入式系统中常见的问题。FreeRTOS提供了两种栈溢出检测方法通过configCHECK_FOR_STACK_OVERFLOW配置当检测到溢出时会调用vApplicationStackOverflowHook。void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { printf(!!! Stack overflow detected in task %s !!!\n, pcTaskName); /* 这里可以添加更多调试信息或安全处理 */ for(;;); /* 进入死循环防止进一步破坏 */ }4.2 内存分配失败钩子当动态内存分配失败时如创建任务、队列等会调用vApplicationMallocFailedHook。这对于内存受限的系统特别重要。void vApplicationMallocFailedHook(void) { printf(!!! Memory allocation failed !!!\n); /* 可能的处理方式 * 1. 记录错误 * 2. 尝试释放一些内存 * 3. 安全地重启系统 */ }4.3 空闲任务钩子空闲任务钩子vApplicationIdleHook会在系统没有其他任务运行时被调用。它可以用于低功耗模式处理系统状态监控后台维护任务void vApplicationIdleHook(void) { static uint32_t idleCount 0; idleCount; /* 每1000次空闲循环打印一次信息 */ if((idleCount % 1000) 0) { printf(System idle count: %lu, free heap: %u\n, idleCount, xPortGetFreeHeapSize()); } /* 可以在这里进入低功耗模式 */ // __WFI(); }4.4 时钟节拍钩子时钟节拍钩子vApplicationTickHook在每个系统时钟中断时被调用。它可以用于高精度定时实时性能监控时间敏感的操作void vApplicationTickHook(void) { static uint32_t tickCount 0; tickCount; /* 示例每1000个tick执行一次操作 */ if((tickCount % 1000) 0) { /* 执行周期性操作 */ } }重要提示所有Hook函数都运行在中断上下文中应该保持简短避免调用可能导致阻塞的API。5. FreeRTOSConfig.h关键配置虽然main.c是应用的入口但FreeRTOS的行为很大程度上由FreeRTOSConfig.h中的配置决定。以下是一些关键配置项/* 内核配置 */ #define configUSE_PREEMPTION 1 /* 使用抢占式调度 */ #define configUSE_TIME_SLICING 1 /* 启用时间片轮转 */ #define configUSE_IDLE_HOOK 0 /* 是否使用空闲钩子 */ #define configUSE_TICK_HOOK 0 /* 是否使用时钟节拍钩子 */ #define configCPU_CLOCK_HZ (16000000) /* CPU时钟频率 */ #define configTICK_RATE_HZ (1000) /* 系统时钟频率(Hz) */ /* 内存配置 */ #define configTOTAL_HEAP_SIZE ((size_t)(20 * 1024)) /* 堆大小 */ #define configAPPLICATION_ALLOCATED_HEAP 0 /* 堆由编译器分配 */ /* 钩子函数配置 */ #define configUSE_MALLOC_FAILED_HOOK 1 /* 内存分配失败钩子 */ #define configCHECK_FOR_STACK_OVERFLOW 2 /* 栈溢出检测级别 */ /* 任务限制 */ #define configMAX_PRIORITIES (7) /* 最大优先级数 */ #define configMINIMAL_STACK_SIZE ((uint16_t)128) /* 空闲任务栈大小 */6. 调试技巧与最佳实践在开发FreeRTOS应用时以下调试技巧可能会很有帮助使用任务状态查询void PrintTaskInfo(void) { TaskStatus_t *pxTaskStatusArray; volatile UBaseType_t uxArraySize, x; uxArraySize uxTaskGetNumberOfTasks(); pxTaskStatusArray pvPortMalloc(uxArraySize * sizeof(TaskStatus_t)); if(pxTaskStatusArray ! NULL) { uxArraySize uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, NULL); printf(Task Info:\n); for(x 0; x uxArraySize; x) { printf(Task: %s, Priority: %lu, Stack High Water Mark: %lu\n, pxTaskStatusArray[x].pcTaskName, pxTaskStatusArray[x].uxCurrentPriority, pxTaskStatusArray[x].usStackHighWaterMark); } vPortFree(pxTaskStatusArray); } }监控堆使用情况void CheckHeapUsage(void) { printf(Free heap: %u, Minimum ever free: %u\n, xPortGetFreeHeapSize(), xPortGetMinimumEverFreeHeapSize()); }使用断言 FreeRTOS提供了一个可配置的断言宏configASSERT在开发阶段应该充分利用它#define configASSERT(x) if((x) 0) { \ printf(Assert failed: %s, line %d\n, __FILE__, __LINE__); \ taskDISABLE_INTERRUPTS(); \ for(;;); \ }合理设置栈大小 通过uxTaskGetStackHighWaterMark()函数可以检测任务栈的实际使用情况帮助优化栈大小设置。在实际项目中我发现最容易出错的地方往往是任务优先级设置和栈大小配置。一个实用的建议是在开发初期为每个任务设置比实际需要更大的栈空间然后通过高水位标记函数优化调整。

相关文章:

FreeRTOS在RISC-V上的第一个main.c:从创建任务到理解Hook函数的完整流程

FreeRTOS在RISC-V上的第一个main.c:从创建任务到理解Hook函数的完整流程 当你在RISC-V平台上第一次打开main.c文件准备编写FreeRTOS应用时,可能会被那些看似神秘的函数和配置选项所困扰。这篇文章将带你从零开始,逐步构建一个完整的FreeRTOS应…...

BGA虚焊别头疼!从焊膏印刷到回流焊曲线,一份保姆级的SMT工艺避坑指南

BGA虚焊别头疼!从焊膏印刷到回流焊曲线,一份保姆级的SMT工艺避坑指南 在SMT产线上,BGA虚焊问题就像个幽灵,时不时冒出来折腾工程师。上周产线刚报修一批主板,X光下那些不规则焊点像极了抽象派画作——可惜客户要的是工…...

深度解密网易云音乐NCM格式:技术原理与实战应用指南

深度解密网易云音乐NCM格式:技术原理与实战应用指南 【免费下载链接】ncmdump ncmdump - 网易云音乐NCM转换 项目地址: https://gitcode.com/gh_mirrors/ncmdu/ncmdump 你是否曾在网易云音乐下载了心爱的歌曲,却发现只能在官方客户端播放&#xf…...

告别编译报错:解决Windows下QGC源码编译中C2220等常见错误的实战记录

告别编译报错:解决Windows下QGC源码编译中C2220等常见错误的实战记录 当你满怀期待地克隆完QGroundControl源码,配置好Visual Studio和Qt环境,却在编译阶段遭遇红色错误提示时,那种挫败感我深有体会。特别是看到QGCTileCacheWork…...

正点原子阿尔法开发板uboot编译避坑指南:从源码到SD卡启动的完整流程

正点原子阿尔法开发板uboot编译全流程实战:从环境搭建到SD卡启动的深度解析 第一次接触正点原子阿尔法开发板时,最令人头疼的莫过于uboot的编译和烧录过程。那些看似简单的命令背后,隐藏着无数新手容易踩中的"暗坑"——从文件格式的…...

NemoClaw资源导航:从Awesome列表构建到高效使用指南

1. 项目概述:一个为“NemoClaw”而生的资源宝库 如果你正在寻找一个关于“NemoClaw”的、经过筛选和整理的高质量资源集合,那么你很可能已经听说过或者正在寻找 VoltAgent/awesome-nemoclaw 这个项目。在开源世界里,以 awesome- 为前缀的…...

告别龟速!实测字节跳动Rust镜像源rsproxy.cn,安装rust和cargo快到飞起

Rust开发者福音:字节跳动镜像源rsproxy.cn全实测与避坑指南 上周深夜两点,我盯着终端里以KB/s为单位缓慢爬升的Rust安装进度条,第5次按下了CtrlC。作为一门以"零成本抽象"著称的语言,Rust的安装体验却让国内开发者付出了…...

HX711终极指南:如何用24位ADC打造专业级电子秤系统

HX711终极指南:如何用24位ADC打造专业级电子秤系统 【免费下载链接】HX711 An Arduino library to interface the Avia Semiconductor HX711 24-Bit Analog-to-Digital Converter (ADC) for Weight Scales. 项目地址: https://gitcode.com/gh_mirrors/hx/HX711 …...

解锁智能告警管理:Keep开源AIOps平台从零到生产实战指南

解锁智能告警管理:Keep开源AIOps平台从零到生产实战指南 【免费下载链接】keep The open-source AIOps and alert management platform 项目地址: https://gitcode.com/GitHub_Trending/kee/keep 在当今复杂的云原生环境中,运维团队每天都要面对海…...

别再用重启就丢数据的流量统计了!OpenWrt上nlbwmon的持久化配置与性能优化全攻略

OpenWrt高级流量监控:nlbwmon持久化配置与性能优化实战 每次重启路由器后流量统计归零?图表加载慢到怀疑人生?这些问题困扰着许多OpenWrt用户。本文将带你深入解决nlbwmon的两大核心痛点——数据持久化和界面响应速度,打造一个真正…...

基于SpringBoot的B2C生鲜电商平台毕设源码

博主介绍:✌ 专注于Java,python,✌关注✌私信我✌具体的问题,我会尽力帮助你。一、研究目的本研究旨在构建一个基于Spring Boot与Vue框架的B2C生鲜电商平台以解决当前生鲜电商领域存在的核心问题包括供应链管理效率低下导致的商品损耗率居高不下用户端体…...

别再只调包了!用PyTorch和DGL从零实现一个GCN层(附Cora节点分类实战代码)

从零构建图卷积网络:PyTorch与DGL实战中的底层逻辑拆解 当你第一次调用g.update_all()时,是否好奇过DGL框架背后究竟发生了什么?那些看似简单的消息传递和聚合操作,实际上隐藏着图卷积网络最精妙的设计思想。本文将带你深入GCN的数…...

【机器学习】Stacking模型融合:从原理到实战的进阶指南

1. 为什么需要Stacking模型融合? 当你用单一模型处理复杂数据时,经常会遇到这样的困境:线性回归对非线性关系束手无策,决策树容易过拟合,神经网络需要大量调参。我在去年参加Kaggle房价预测比赛时就深有体会——当时用…...

SAP-ABAP:ABAP Development Tools(ADT)安装配置学习分享教程(四篇连载)第四篇:ADT连接故障排查与环境迁移教程

ABAP Development Tools(ADT)安装配置学习分享教程(四篇连载) 第四篇:ADT连接故障排查与环境迁移教程 ADT连不上SAP后端?刚刚还好好的系统突然报错了?换了新电脑要重建整个开发环境&#xff1f…...

利用大模型分歧优化NLP标注

In this blogpost I’d like to talk about large language models. There’s a bunch of hype, sure, but there’s also an opportunity to revisit one of my favourite machine learning techniques: disagreement. 在本文中,我想讨论大语言模型。虽然存在大量炒…...

开发者个人网站搭建指南:从静态站点生成器到部署实战

1. 项目概述:一个为开发者量身定制的“数字家园” 在代码的海洋里泡久了,我们开发者总会遇到一个不大不小的痛点:如何高效、优雅地展示自己的技术栈、项目作品和个人思考?GitHub的README.md固然是标配,但它更像一份静态…...

如何让老款Mac重获新生:OpenCore Legacy Patcher完整指南

如何让老款Mac重获新生:OpenCore Legacy Patcher完整指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 还在为苹果官方停止支持的老款Mac无法升…...

Simulink模块搭建跟踪误差不归零?可能是隐藏的信号延迟在捣鬼(附S函数解法)

Simulink隐性信号延迟:从图形化建模到S函数的高精度控制实践 在控制系统仿真领域,Simulink作为行业标准工具链的核心组件,其图形化建模方式极大降低了算法验证的门槛。但当工程师从功能实现进阶到性能优化阶段时,常常会遇到一个令…...

挖掘MCU硬件加速潜力:以R80515的Double DPTR和MDU为例,在Keil C51中开启性能外挂

挖掘MCU硬件加速潜力:R80515双DPTR与MDU在Keil C51中的实战优化 当你在Keil C51环境下为资源受限的8051架构编写代码时,是否曾为缓慢的数据搬运和复杂的数学运算而头疼?现代增强型8051内核如R80515通过硬件加速单元提供了突破性能瓶颈的可能…...

【Sora 2×AE工作流革命】:20年特效总监亲授无缝整合5大黄金法则,错过再等三年?

更多请点击: https://intelliparadigm.com 第一章:Sora 2AE工作流革命的底层逻辑与行业拐点 Sora 2AE(Advanced Encoding)并非简单升级,而是将扩散模型时序建模能力与自适应编码器深度耦合的范式重构。其核心突破在于…...

影刀RPA高阶架构:告别“连点器”思维,内置原生指纹浏览器重塑全域店群防封底座

大家好,我是林焱,一名专注电商底层业务逻辑与企业级 RPA 自动化架构定制的独立开发者。 在技术社区和各大电商交流群里,我经常会遇到使用影刀 RPA 的开发者提出这样一个痛点:“林大,我用影刀写了一套逻辑非常严密的自…...

【Sora 2 × Gaussian Splatting融合实战指南】:20年CV专家亲授3大跨模态生成瓶颈突破法

更多请点击: https://intelliparadigm.com 第一章:Sora 2 Gaussian Splatting融合的技术演进与范式跃迁 Sora 2 与 Gaussian Splatting 的深度耦合,标志着生成式视频建模从隐式神经表征迈向显式可微几何渲染的关键转折。二者并非简单串联&a…...

Cadence AMS Designer 保姆级教程:手把手教你搞定数模混合仿真(含Verilog模块导入避坑指南)

Cadence AMS Designer 保姆级教程:手把手教你搞定数模混合仿真(含Verilog模块导入避坑指南) 数模混合仿真一直是芯片设计中的关键环节,尤其对于刚接触Cadence环境的新手工程师或在校学生来说,从零开始搭建混合仿真环境…...

一天怎么完成论文初稿

写论文这件事,从选题到完稿,哪一步都能卡掉你半条命。我身边不少读研读博的同学,白天泡实验室做实验,晚上挤时间写论文,熬了一两个月出初稿,结果格式不对、文献零散,还要和同门改来改去&#xf…...

科研人狂喜!AI生成的位图可以转矢量图了

今天给大家分享我最近挖到的宝藏科研工具:MedPeer「图片创作」——国内领先的垂直领域AI科研绘图工具,刚好解决我们科研人最头疼的几个痛点。尤其是它的人工绘图转换服务,简直是帮我解决了大麻烦,必须给大家捋捋明白。我们科研人绘…...

5分钟掌握HunterPie:解决《怪物猎人:世界》战斗信息盲区的终极指南

5分钟掌握HunterPie:解决《怪物猎人:世界》战斗信息盲区的终极指南 【免费下载链接】HunterPie-legacy A complete, modern and clean overlay with Discord Rich Presence integration for Monster Hunter: World. 项目地址: https://gitcode.com/gh_…...

ArcGIS符号库“隐身”之谜:从DAO组件缺失到完整恢复的实战指南

1. 当符号选择器突然"罢工":一个GISer的崩溃瞬间 那天早上我正赶着完成客户的地图项目,准备给水系图层换个漂亮的蓝色符号。像往常一样双击图层打开属性窗口,点击Symbol Selector准备挑选样式时,整个人瞬间僵住了——本…...

CompressO终极指南:免费开源视频图片压缩工具完整使用教程

CompressO终极指南:免费开源视频图片压缩工具完整使用教程 【免费下载链接】compressO Convert any video/image into a tiny size. 100% free & open-source. Available for Mac, Windows & Linux. 项目地址: https://gitcode.com/gh_mirrors/co/compres…...

STM32F4上跑FreeType:手把手教你为嵌入式GUI添加矢量字体(附源码)

STM32F4实战:FreeType矢量字体移植与GUI深度优化指南 1. 嵌入式矢量字体技术选型与原理 在资源受限的嵌入式环境中实现矢量字体渲染,本质上是一场内存效率与视觉质量的博弈。FreeType作为行业标准的字体引擎,其核心优势在于采用二次贝塞尔曲…...

保姆级教程:用Winbox给ROS配置一线多拨,实测200M宽带叠加效果(附避坑指南)

家庭网络优化实战:Winbox配置多拨提升宽带利用率 家里装了200M宽带,但下载大文件时总觉得速度没跑满?多人同时在线看4K视频就开始卡顿?其实通过简单的路由器配置,你完全有可能突破运营商单线限制,让宽带利用…...