本帖最后由 夜声 于 2023-5-29 20:01 编辑
一、 前言前面已经对芯片的外设,资源进行了熟悉,同时试用了基本外设ADC,查看了芯片手册,本款芯片支持Lin总线,但是是软件的,没太多心思弄,想做一点特别一点的,支持一款RTOS吧,通过查找芯片手册有4K的RAM和32K的Flash,理论上是可以运行一款精简的RTOS,本次选择的是RT-Thread Nano进行测试,并创建多线程进行运行。 二、 RT-Thread Nano简介RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。 在资源足够的情况下可移植finsh组件,如下为RT-Thread软件框图: RT-Thread Nano 支持可裁剪,通过rtconfig.h进行,在本次使用过程中也会用到,需要裁剪一些功能。 同时最关心的就是RT-Thread Nano的使用资源情况了,对 RAM 与 ROM 的开销非常小,在支持 semaphore 和 mailbox 特性,并运行两个线程 (main 线程 + idle 线程) 情况下,ROM 和 RAM 依然保持着极小的尺寸,RAM 占用约 1K 左右,ROM 占用 4K 左右,但实际可能不止,接下来就开始RT-Thread的移植。
三、 RT-Thread Nano移植准备工作: 下载好RT-Thread Nano版本的源码,或者使用keil中下好RT-Thread实时操作系统的支持包(这种方式方便使用)。 准备好基础工程,本次使用的是SYSTEM的例程,因为在移植过程中需要使用systick时钟,同时systick的程序支持串口和LED方便验证移植是否成功。 移植过程: 1. 添加RT-Thread Nano源码
2. 添加心跳配置,在Board.c文件中,首先需要在源码board.c中添加#include "ac7802x.h"头文件,在board.c中需要使用systick的配置。以下为RT-Thread操作系统的心跳配置。
3. 在systick_Handler中添加心跳回调函数rt_os_tick_callback();
4. RTOS裁剪,由于芯片资源比较少,需要对RTOS进行裁剪。点击rtconfig.h进行配置,选择Configuration Wizard
在Memory Management Configuation中关闭动态内存池管理
其他按需求配置即可,总的配置文件如下: /* RT-Thread config file */
#ifndef __RTTHREAD_CFG_H__ #define __RTTHREAD_CFG_H__
// <<< Use Configuration Wizard in Context Menu>>>
// <h>Basic Configuration // <o>Maximal level of thread priority <8-256> // <i>Default:32 #define RT_THREAD_PRIORITY_MAX 32 // <o>OS tick per second // <i>Default:1000 (1ms) #define RT_TICK_PER_SECOND 1000 // <o>Alignment size for CPU architecture data access // <i>Default:4 #define RT_ALIGN_SIZE 4 // <o>the max length of object name<2-16> // <i>Default:8 #define RT_NAME_MAX 8 // <c1>Using RT-Thread components initialization // <i>Using RT-Threadcomponents initialization #define RT_USING_COMPONENTS_INIT // </c>
#define RT_USING_USER_MAIN
// <o>the stack size of main thread<1-4086> // <i>Default:512 #define RT_MAIN_THREAD_STACK_SIZE 256
// </h>
// <h>Debug Configuration // <c1>enable kernel debug configuration // <i>Default:enable kernel debug configuration //#define RT_DEBUG // </c> // <o>enable components initialization debugconfiguration<0-1> // <i>Default:0 #define RT_DEBUG_INIT 0 // <c1>thread stack over flow detect // <i> DiableThread stack over flow detect //#define RT_USING_OVERFLOW_CHECK // </c> // </h>
// <h>Hook Configuration // <c1>using hook // <i>usinghook //#define RT_USING_HOOK // </c> // <c1>using idle hook // <i>using idlehook //#define RT_USING_IDLE_HOOK // </c> // </h>
// <e>Software timers Configuration // <i> Enables user timers #define RT_USING_TIMER_SOFT 0 #if RT_USING_TIMER_SOFT == 0 #undefRT_USING_TIMER_SOFT #endif // <o>The priority level of timer thread <0-31> // <i>Default:4 #define RT_TIMER_THREAD_PRIO 4 // <o>The stack size of timer thread <0-8192> // <i>Default:512 #define RT_TIMER_THREAD_STACK_SIZE 512 // </e>
// <h>IPC(Inter-process communication) Configuration // <c1>Using Semaphore // <i>UsingSemaphore #define RT_USING_SEMAPHORE // </c> // <c1>Using Mutex // <i>UsingMutex //#define RT_USING_MUTEX // </c> // <c1>Using Event // <i>UsingEvent //#define RT_USING_EVENT // </c> // <c1>Using MailBox // <i>UsingMailBox #define RT_USING_MAILBOX // </c> // <c1>Using Message Queue // <i>UsingMessage Queue //#define RT_USING_MESSAGEQUEUE // </c> // </h>
// <h>Memory Management Configuration // <c1>Memory Pool Management // <i>MemoryPool Management //#define RT_USING_MEMPOOL // </c> // <c1>Dynamic Heap Management(Algorithm: smallmemory ) // <i>DynamicHeap Management //#define RT_USING_HEAP //#define RT_USING_SMALL_MEM // </c> // <c1>using tiny size of memory // <i>usingtiny size of memory //#define RT_USING_TINY_SIZE // </c> // </h>
// <h>Console Configuration // <c1>Using console // <i>Usingconsole //#define RT_USING_CONSOLE // </c> // <o>the buffer size of console <1-1024> // <i>thebuffer size of console // <i>Default:128 (128Byte) #define RT_CONSOLEBUF_SIZE 256 // </h>
// <h>FinSH Configuration // <c1>include finsh config // <i>Selectthis choice if you using FinSH //#include "finsh_config.h" // </c> // </h>
// <h>Device Configuration // <c1>using device framework // <i>usingdevice framework //#define RT_USING_DEVICE // </c> // </h>
// <<< end of configuration section >>>
#endif 到这里移植工作完成,可以先进行编译,看是否出现错误之类的问题,或者内存不够等问题。经过调整过后,编译的文件的大小调整在了芯片的内存的范围内,如下所示:
四、 程序设计这里主要进行验证程序的设计,首先main.c中添加#include <rtthread.h>头文件,在主函数中创建两个线程,线程1和线程2,线程1主要是LED1 200MS翻转,并且打印调试信息,线程2为LED2 400MS翻转,并且打印调试信息。如下所示: struct rt_thread thread1; struct rt_thread thread2;
char thread1_stack[512]; char thread2_stack[512];
void thread1_entry(void*param) {
while (1) {
LED1_TOGGLE; printf("thread1 is running\r\n"); rt_thread_mdelay(200); }
}
void thread2_entry(void*param) {
while (1) {
LED2_TOGGLE; printf("thread2is running\r\n"); rt_thread_mdelay(400); }
}
void thread1_init(void) {
rt_err_t fd=rt_thread_init(&thread1,"thread1",&thread1_entry,0,&thread1_stack[0],sizeof(thread1_stack),10,10); if(fd < 0) { printf("thread1 init is fail \r\n"); } else { printf("thread1init is success \r\n"); } rt_thread_startup(&thread1); } void thread2_init(void) {
rt_err_t fd=rt_thread_init(&thread2,"thread2",&thread2_entry,0,&thread2_stack[0],sizeof(thread2_stack),10,10); if(fd < 0) { printf("thread2 init is fail \r\n"); } else { printf("thread2init is success \r\n"); } rt_thread_startup(&thread2); } int main(void) { InitDebug(); GPIO_LedInit();/*! led 初始化*/ thread1_init(); thread2_init(); } 编译下载,可以看到调试信息,线程1和线程2创建成功信息,线程1打印两次,线程2打印一次。如下所示
五、 总结本次在较小资源的芯片上实现了RT-Thread操作系统,并创建了两个线程,以及调试信息输出。文章是调试完成后在写的,整个过程中也还是遇到很多问题的,没有想象的那么顺利,有兴趣的小伙伴也可以试一下。
|