K210 FreeRTOS SDK启动分析

2024-04-03 14:32
文章标签 分析 sdk 启动 freertos k210

本文主要是介绍K210 FreeRTOS SDK启动分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、目的

最近在开始使用K210 FreeRTOS SDK进行应用开发,但是在使用过程发现程序的行为和预期不一致,怀疑这个官方提供的FreeRTOS SDK适配的不是很完整,故本着学习的目的跟着代码分析一下启动过程。

二、必备知识

对freertos有一些基本了解,了解滴答时钟(tick)、任务、任务优先级、空闲任务等基本概念;知道如何配置freertos一些选项,通过修改FreeRTOSConfig.h进行配置。

diff --git a/lib/freertos/conf/FreeRTOSConfig.h b/lib/freertos/conf/FreeRTOSConfig.h
index dac0af6..14fd619 100755
--- a/lib/freertos/conf/FreeRTOSConfig.h
+++ b/lib/freertos/conf/FreeRTOSConfig.h
@@ -59,14 +59,14 @@/* clock */#define configCPU_CLOCK_HZ                                     uxPortGetCPUClock()#define configTICK_CLOCK_HZ                                    ( configCPU_CLOCK_HZ / 50 )
-#define configTICK_RATE_HZ                                     ( ( TickType_t ) 100 )
+#define configTICK_RATE_HZ                                     ( ( TickType_t ) 1000 )/* multithreading */#define configUSE_NEWLIB_REENTRANT                             1#define configUSE_PREEMPTION                                   1#define configUSE_PORT_OPTIMISED_TASK_SELECTION        0
-#define configMAX_PRIORITIES                                   ( 5 )
+#define configMAX_PRIORITIES                                   ( 16 )#define configMAX_TASK_NAME_LEN                                        ( 16 )#define configUSE_TRACE_FACILITY                               1#define configUSE_16_BIT_TICKS                                 0
@@ -108,9 +108,9 @@ enum#define configMAX_CO_ROUTINE_PRIORITIES                        ( 2 )/* Software timer definitions. */
-#define configUSE_TIMERS                                               0
-#define configTIMER_TASK_PRIORITY                              ( 0 )
-#define configTIMER_QUEUE_LENGTH                               2
+#define configUSE_TIMERS                                               1
+#define configTIMER_TASK_PRIORITY                              ( configMAX_PRIORITIES - 1 )
+#define configTIMER_QUEUE_LENGTH                               8#define configTIMER_TASK_STACK_DEPTH                   ( configMINIMAL_STACK_SIZE )

 其中configTICK_RATE_HZ设置tick频率,此处修改为1000Hz,即1ms;configMAX_PRIORITIES设置系统支持的最多优先级,值越大,优先级越高,创建任务时可以配置的最大优先级为configMAX_PRIORITIES -1;configUSE_TIMERS配置系统软件定时器,即rtos实现的软件定时器,一般情况下其优先级需要设置为最大,即configMAX_PRIORITIES -1;

三、启动分析

根据教程,我们是从src/hello_world/main.c程序开始熟悉sdk的调用。

#include <stdio.h>                                                              int main() {                                                                    printf("Hello K210!!!\n");                                                  while (1);                                                                  
}   

此处有个疑问,谁调用了main?rtos是否已经启动了?

针对以上疑问,我们做了这样一个尝试。

#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"static void task_0(void *args) {while (1) {printf("task 0 is polling\n");vTaskDelay(1000 / portTICK_PERIOD_MS);}vTaskDelete(NULL);
}static void task_1(void *args) {while (1) {printf("task 1 is polling\n");vTaskDelay(1000 / portTICK_PERIOD_MS);}vTaskDelete(NULL);
}int main() {printf("Hello K210!!!\n");xTaskCreateAtProcessor(0, task_0, "task0", 1024, NULL, 5, NULL);xTaskCreateAtProcessor(0, task_1, "task1", 1024, NULL, 5, NULL);while (1) {printf("main is polling\n");vTaskDelay(2000 / portTICK_PERIOD_MS);}
}

我们在core 0上面创建了两个任务,并且在mian函数里面也有循环打印。通过编译烧写验证后,确认rtos已经正常工作。

我们知道freertos是通过vTaskStartScheduler接口调用开启多任务调度的,我们跟踪源码lib/freertos/os_entry.c

/* Copyright 2018 Canaan Inc.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**     http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
#include "FreeRTOS.h"
#include "core_sync.h"
#include "kernel/device_priv.h"
#include "task.h"
#include <clint.h>
#include <encoding.h>
#include <fpioa.h>
#include <stdio.h>
#include <stdlib.h>typedef struct
{int (*user_main)(int, char **);int ret;
} main_thunk_param_t;extern void __libc_init_array(void);
extern void __libc_fini_array(void);static StaticTask_t s_idle_task[portNUM_PROCESSORS];
static StackType_t s_idle_task_stack[portNUM_PROCESSORS][configMINIMAL_STACK_SIZE];
static StaticTask_t s_timer_task[portNUM_PROCESSORS];
static StackType_t s_timer_task_stack[portNUM_PROCESSORS][configMINIMAL_STACK_SIZE];void start_scheduler(int core_id);int __attribute__((weak)) configure_fpioa()
{return 0;
}static void main_thunk(void *p)
{/* Register finalization function */atexit(__libc_fini_array);/* Init libc array for C++ */__libc_init_array();install_hal();install_drivers();configure_fpioa();main_thunk_param_t *param = (main_thunk_param_t *)p;param->ret = param->user_main(0, 0);
}static void os_entry_core1()
{clear_csr(mie, MIP_MTIP);clint_ipi_enable();set_csr(mstatus, MSTATUS_MIE);vTaskStartScheduler();
}int os_entry(int (*user_main)(int, char **))
{clear_csr(mie, MIP_MTIP);clint_ipi_enable();set_csr(mstatus, MSTATUS_MIE);TaskHandle_t mainTask;main_thunk_param_t param = {};param.user_main = user_main;if (xTaskCreate(main_thunk, "Core 0 Main", configMAIN_TASK_STACK_SIZE, &param, configMAIN_TASK_PRIORITY, &mainTask) != pdPASS){return -1;}core_sync_awaken((uintptr_t)os_entry_core1);vTaskStartScheduler();return param.ret;
}void vApplicationIdleHook(void)
{
}void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
{UBaseType_t uxPsrId = uxPortGetProcessorId();/* Pass out a pointer to the StaticTask_t structure in which the Idle task'sstate will be stored. */*ppxIdleTaskTCBBuffer = &s_idle_task[uxPsrId];/* Pass out the array that will be used as the Idle task's stack. */*ppxIdleTaskStackBuffer = s_idle_task_stack[uxPsrId];/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.Note that, as the array is necessarily of type StackType_t,configMINIMAL_STACK_SIZE is specified in words, not bytes. */*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize)
{UBaseType_t uxPsrId = uxPortGetProcessorId();/* Pass out a pointer to the StaticTask_t structure in which the Idle task'sstate will be stored. */*ppxTimerTaskTCBBuffer = &s_timer_task[uxPsrId];/* Pass out the array that will be used as the Idle task's stack. */*ppxTimerTaskStackBuffer = s_timer_task_stack[uxPsrId];/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.Note that, as the array is necessarily of type StackType_t,configMINIMAL_STACK_SIZE is specified in words, not bytes. */*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
{configASSERT(!"Stackoverflow !");
}

我们看到os_entry这个函数里面调用了vTaskStartScheduler,并且在调用之前,创建了一个main_thunk任务并且同时调用core_sync_awaken((uintptr_t)os_entry_core1);这个os_entry_core1内部又调用了vTaskStartScheduler,开启了core 1的多任务调度。main_thunk任务内部执行了一些系统初始化操作(hal/drivers/fpioa),然后执行user_main函数,这个函数就是os_entry函数的入参,我们继续跟踪,发现lib/bsp/entry_user.c这个里面的_init_bsp调用了os_entry(main),此处的main即src/hello_world/main.c里面main函数,另外通过汇编代码跟踪,我们发现lib/bsp/crt.S这个里面调用了_init_bsp。

至此我们完成了整个系统rtos的启动过程。

这篇关于K210 FreeRTOS SDK启动分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/873167

相关文章

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

SpringBoot项目启动后自动加载系统配置的多种实现方式

《SpringBoot项目启动后自动加载系统配置的多种实现方式》:本文主要介绍SpringBoot项目启动后自动加载系统配置的多种实现方式,并通过代码示例讲解的非常详细,对大家的学习或工作有一定的... 目录1. 使用 CommandLineRunner实现方式:2. 使用 ApplicationRunne

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结

bat脚本启动git bash窗口,并执行命令方式

《bat脚本启动gitbash窗口,并执行命令方式》本文介绍了如何在Windows服务器上使用cmd启动jar包时出现乱码的问题,并提供了解决方法——使用GitBash窗口启动并设置编码,通过编写s... 目录一、简介二、使用说明2.1 start.BAT脚本2.2 参数说明2.3 效果总结一、简介某些情

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit

python-nmap实现python利用nmap进行扫描分析

《python-nmap实现python利用nmap进行扫描分析》Nmap是一个非常用的网络/端口扫描工具,如果想将nmap集成进你的工具里,可以使用python-nmap这个python库,它提供了... 目录前言python-nmap的基本使用PortScanner扫描PortScannerAsync异