一、 前言
前面已经对芯片的外设,资源进行了熟悉,同时试用了基本外设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操作系统,并创建了两个线程,以及调试信息输出。文章是调试完成后在写的,整个过程中也还是遇到很多问题的,没有想象的那么顺利,有兴趣的小伙伴也可以试一下。
---------------------
作者:夜声
链接:https://bbs.21ic.com/icview-3305422-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。