【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell目录背景:移植RT-Threadnano,并基于nano添加FinSH/shell前提及准备工作step1:添加rt-threadnano到裸机工程1.1、NanoPack安装方法一:PackInstaller安装方法二:手动安装1.2、基础工程准备1.3、开始移植rttnano到裸机工程1.4、适配RT-Threadnano1.5…

大家好,又见面了,我是你们的朋友全栈君。

目录

背景:移植RT-Thread nano,并基于  nano 添加 FinSH/shell

前提及准备工作

step1:添加rt-thread nano到裸机工程

1.1、Nano Pack 安装

方法一:Pack Installer 安装

方法二:手动安装

1.2、基础工程准备

1.3、开始移植rtt nano到裸机工程

1.4、适配 RT-Thread nano

1.5、RT-Thread Nano 配置(选配)

1.6 常见问题

step2:添加finsh到工程

2.1、添加finsh源码

2.2、实现uart驱动

2.3、修改console名称

2.4、下载验证

2.5 附录一份uart驱动供参考

2.6 常见问题


背景:移植RT-Thread nano,并基于  nano 添加 FinSH/shell

在nano上添加finsh可以有两种方法:

1、移植finsh基于device框架【这个官方文档中心有相关的文章了,链接:https://www.rt-thread.org/document/site/tutorial/nano/nano_finsh/an0033-nano-finsh/

2、移植finsh不基于device框架【本文讲解这个不基于device框架的,从头讲解,如果移植rtt nano,然后基于这个nano 再移植finsh【本文基于 rtt nano 3.1.2 /3.1.1】要移植3.1.3请至rtt官网查看,有教程。

前提及准备工作

  1. 安装了mdk
  2. 一个stm32 mdk裸机工程:要一份能运行的基本工程,如一个f103的可以跑led的裸机工程即可。(这里基于hal库做的mdk工程)
  3. 一个nano源码:我们直接从keil中下载nano的pack包
  4. 注意,本文基于 rtt nano 3.1.2 版本,3.1.1也行

step1:添加rt-thread nano到裸机工程

注意:step1 是参考了RTT文档中心的教程。

1.1、Nano Pack 安装

Nano Pack 可以通过 MDK 联网安装,也可以手动安装。下面开始介绍两种安装方式。

方法一:Pack Installer 安装

打开 MDK 软件,点击工具栏的 Pack Installer 图标:

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

点击右侧的 Pack,展开 Generic,可以找到 RealThread::RT-Thread,点击 Action 栏对应的 Install ,就可以在线安装 Nano Pack 了。另外,如果需要安装其他版本,则需要展开 RealThread::RT-Thread,进行选择。

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

方法二:手动安装

我们也可以从官网下载安装文件,RT-Thread Nano 离线安装包下载,下载结束后双击文件进行安装。

RT-Thread Nano 离线安装包下载路径:https://www.rt-thread.org/download/mdk/RealThread.RT-Thread.3.0.3.pack

1.2、基础工程准备

在开始创建 RT-Thread 小系统之前,我们需要准备一个能正常运行的裸机工程。作为示例,本文使用的是基于 STM32L475-Pandora 和 HAL 库的一个 LED 闪烁程序。程序的主要截图如下:

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

在我们的例程中主要做了系统初始化与LED闪烁功能,编译下载程序后,就可以看到 LED 闪烁了。读者可以根据自己的需要使用其他芯片,完成一个简单的类似裸机工程。

1.3、开始移植rtt nano到裸机工程

打开已经准备好的可以运行的裸机程序,将 RT-Thread 添加到工程。如下图,点击 Manage Run-Time Environment。、

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

在 Manage Rum-Time Environment 里”Software Component” 栏找到 RTOS,Variant 栏选择 RT-Thread,然后勾选 kernel,点击”OK” 就添加 RT-Thread 内核到工程了。

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

现在可以在 Project 看到 RT-Thread RTOS 已经添加进来了,展开 RTOS,可以看到添加到工程的文件:

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

 

Cortex-M 芯片内核移植代码:

context_rvds.s
cpuport.c

kernel文件

clock.c
components.c
device.c
idle.c
ipc.c
irq.c
kservice.c
mem.c
object.c
scheduler.c
thread.c
timer.c

 应用代码及配置文件:

board.c
rtconfig.h

1.4、适配 RT-Thread nano

RT-Thread 会用到了异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),以及 Systick 中断服务函数 SysTick_Handler(),所以用户代码需要保证这几个函数没有被使用,若编译提示函数重复定义,请删除自己定义的函数。

RT-Thread Nano 在 board.c 中默认完成了 systick 的配置,用户可以修改宏 RT_TICK_PER_SECOND 的值配置每秒 systick 数。

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

RT-Thread Nano 默认是使用数组作为 heap。

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

替换例程中的 delay 函数:

1). 包含 RT-Thread 的相关头文件 <rtthread.h>

2). 删除之前在裸机工程中做的系统配置(如hal初始化、时钟初始化等),这是因为RT-Thread在系统启动时已经配置完成,否则会重复配置。

3). 将 delay() 函数替换成 rt_thread_mdelay(),如 rt_thread_mdelay(500) 将延时 500ms。

下面是完成修改的代码:

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

编译程序之后下载到芯片就可以看到基于 RT-Thread 的程序运行起来了,LED 正常闪烁。

注意事项:当添加 RT-Thread 之后,裸机中的 main() 函数会自动变成 RT-Thread 系统中 main 线程 的入口函数。由于线程不能一直独占 CPU,所以此时在 main() 中使用 while(1) 时,需要有让出 CPU 的动作,比如使用 rt_thread_mdelay() 系列的函数让出 CPU。另外3.0.3版本中还没有 rt_thread_mdelay() 接口,可以使用 rt_thread_delay()

1.5、RT-Thread Nano 配置(选配)

用户可以根据自己的需要通过修改 rtconfig.h 文件里面的宏定义配置相应功能。

RT-Thread Nano 默认未开启宏 RT_USING_HEAP,故只支持静态方式创建任务及信号量。若要通过动态方式创建对象则需要在 rtconfig.h 文件里开启 RT_USING_HEAP 宏定义。

MDK 的配置向导 configuration Wizard 可以很方便的对工程进行配置,Value 一栏可以选中对应功能及修改相关值,等同于直接修改配置文件 rtconfig.h。

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

1.6 常见问题

Q1:如何升级 pack?

A:Pack 升级步骤基本如同软件包,展开 RealThread::RT-Thread 后,选择比较新的 Nano 版本,点击 Install 进行安装。如下图所示,点击红色框中的 Install 进行升级,即可将 3.1.1 版本升级到 3.1.2。

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

step2:添加finsh到工程

2.1、添加finsh源码

点击Manage Run-Environment:

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

勾选device drivers与shell,这将自动把FinSH组件的源码到工程,并自动添加 #define RTE_USING_DEVICE#define RTE_USING_FINSH 宏:

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

2.2、实现uart驱动

实现uart驱动,主要实现初始化与读写接口,并借助了device注册接口,将uart注册到系统中,使其更方便的对接shell。需要实现的函数原型如下:

rt_err_t  (*init)   (rt_device_t dev);
rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);
rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);

//外加一个注册的函数,注册一个 rt_device 的实例,方便对接 FinSH 组件。

需要添加的代码如下所示:

rt_err_t uart_init(rt_device_t dev)
{
    ...
}

rt_err_t uart_open(rt_device_t dev, rt_uint16_t oflag)
{
    return	uart_init(dev);
}

rt_size_t uart_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    ...                   
}

rt_size_t uart_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    ...
}               

struct rt_device uart_dev;
static int uart_register(void)     
{
    uart_dev.init  = uart_init;
    uart_dev.open  = uart_open;
    uart_dev.read  = uart_read;
    uart_dev.write = uart_write;
  
    rt_device_register(&uart_dev,"uart1",0);
    return 0;
}
INIT_BOARD_EXPORT(uart_register);
  • uart_init():初始化串口,包括硬件引脚的初始化与串口传输模式及波特率等的设置。
  • uart_open():打开串口,使用该接口仅仅是为了对接 FinSH,没有实际意义,直接返回串口初始化即可。
  • uart_read():读入字符,长度size。
  • uart_write():输出字符,长度size。注意输出打印时,在遇到 \n 时,就在输出 \n 之前先输出一个 \r
  • uart_register():注册函数,将uart设备注册到系统中,务必使用INIT_BOARD_EXPORT()初始化该函数。

注意:RT-Thread 系统中已有的打印均以 “\n” 结尾,而并非 “\r\n”,所以在字符输出时,需要在输出“\n”之前输出“\r”完成回车与换行,否则系统打印出来的信息将只有换行。

2.3、修改console名称

打开rtconfig.h文件:将console的名称修改为刚注册到系统中的uart名称,这样FinSH就对接到了UART端口上。如上面注册名为“uart1”,则在rtconfig.h中修改 RT_CONSOLE_DEVICE_NAME 的定义为 uart1:

#define RT_CONSOLE_DEVICE_NAME      "uart1"

2.4、下载验证

下载到开发板进行验证,移植成功

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

2.5 附录一份uart驱动供参考

static UART_HandleTypeDef UartHandle;
rt_err_t uart_init(rt_device_t dev)
{
    UartHandle.Instance = USART1;
    UartHandle.Init.BaudRate   = 115200;
    UartHandle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;
    UartHandle.Init.Mode       = UART_MODE_TX_RX;
    UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
    UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
    UartHandle.Init.StopBits   = UART_STOPBITS_1;
    UartHandle.Init.Parity     = UART_PARITY_NONE;

    if (HAL_UART_Init(&UartHandle) != HAL_OK)
    {
        while (1);
    }

    return 0;
}

rt_err_t uart_open(rt_device_t dev, rt_uint16_t oflag)
{
    return  uart_init(dev);
}

rt_size_t uart_read(rt_device_t dev,
                    rt_off_t    pos,
                    void       *buffer,
                    rt_size_t   size)
{
    while (1)
    {
        if (HAL_UART_Receive(&UartHandle, buffer, size, 20) == 0)
        {
            return size;
        }
    }
}

rt_size_t uart_write(rt_device_t dev,
                     rt_off_t    pos,
                     const void *buffer,
                     rt_size_t   size)
{
    rt_size_t i = 0;
    char a = '\r';
    const char *val = 0;    

    val = (const char *)(buffer);
    
    __HAL_UNLOCK(&UartHandle);

    for (i = 0; i < size; i++)
    {
        if (*(val + i) == '\n')
        {
            HAL_UART_Transmit(&UartHandle, (uint8_t *)&a, 1, 20);
        }
        HAL_UART_Transmit(&UartHandle, (uint8_t *)(val + i), 1, 20);
    }
    return 1;
}

struct rt_device uart_dev;
static int uart_register(void)
{
    uart_dev.init  = uart_init;
    uart_dev.open  = uart_open;
    uart_dev.read  = uart_read;
    uart_dev.write = uart_write;

    rt_device_register(&uart_dev, "uart1", 0);
    return 0;
}
INIT_BOARD_EXPORT(uart_register);

2.6 常见问题

Q1:输出打印正常,却没有打印 msh >,也不能输入。

【超详细教程】移植RT-Thread nano,并基于 nano 添加 FinSH/shell

A:这是由于FinSH 没打开,所以只有打印功能,需要在rtconfig.h中打开 #define RTE_USING_FINSH 宏定义。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/143635.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【Simulink】粒子群算法(PSO)整定PID参数(附代码和讲解)

    【Simulink】粒子群算法(PSO)整定PID参数(附代码和讲解)本文提供粒子群算法简介和一个算法举例,提供粒子群算法仿真PID的M文件代码及simulink仿真。另外,本文还提供了一种动态simulink仿真方法,可以让M文件和simulink文件之间互相交换数据,实现仿真与程序的反馈,增加了仿真的灵活度。

    2022年6月10日
    83
  • cloudsim仿真平台扩展的例子_云编程

    cloudsim仿真平台扩展的例子_云编程CloudSim3.0.3的网络编程详解—以*org.cloudbus.cloudsim.examples.network.NetworkExample1为例

    2022年10月12日
    4
  • linux重命名文件和文件夹的区别_文件夹如何重命名

    linux重命名文件和文件夹的区别_文件夹如何重命名Linux重命名文件和文件夹1.mvlinux下重命名文件或文件夹的命令mv即可以重命名,又可以移动文件或文件夹。例子:将目录A重命名为BmvAB将/a目录移动到/b下,并重命名为cmv/a/b/c例子:ubuntu@ubuntu:~/Public/a2$tree….

    2025年5月28日
    5
  • Nginx学习——Nginx简单介绍和Linux环境下的安装

    Nginx 是一个俄罗斯的哥们开发的,并将其进行了开源。Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝

    2022年2月26日
    299
  • 5个Web前端开发软件,零基础入门完全够用了!

    对于刚刚入行不久的Web前端编程小白来说,在开发工具的选择方面或许会显得有些力不从心,毕竟网络上众说纷纭,相关的开发工具也是非常之多,以至于许多小伙伴一时不知道从何下手。为了解决这个问题,今天就为大家介绍几个不错的开发工具,感兴趣的朋友可以自己尝试一下:1、Notepad++这个软件就不多说了,记事本的增强版,主要应用在Windows平台下,大部分人都应该使用过,非常轻巧灵活,运行速度快,支持多窗口切换,可编辑语言也非常多,自动补全、语法提示和检查等功能都不错,对于前端开发入门来说,可以作为一个不错的选

    2022年4月9日
    54
  • C/C++常见面试知识点总结附面试真题—-20220326更新

    C/C++常见面试知识点总结附面试真题—-20220326更新以下内容部分整理自网络,部分为自己面试的真题。第一部分:计算机基础1.C/C++内存有哪几种类型?C中,内存分为5个区:堆(malloc)、栈(如局部变量、函数参数)、程序代码区(存放二进制代码)、全局/静态存储区(全局变量、static变量)和常量存储区(常量)。此外,C++中有自由存储区(new)一说。2.堆和栈的区别?1).堆存放动态分配的对象——即那些在程序运行时分配的对象…

    2022年7月15日
    23

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号