【超详细教程】移植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 宏定义。

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Try out the latest C++ compiler toolset without waiting for the next update of Visual Studio

    Updated22/Apr/2016:TheNuGet packageis nowbeinguploadeddaily.Thepayloaddoesn’tch

    2021年12月23日
  • C# 字节数组截取

    C# 字节数组截取C#字节数组截取如:byte[]bt=newbyte[]{0,1,2,3,4,5,6,7,8,9};方法一截取位数规则1)截取2位长度的字节数组用BitConverter.ToInt16例如,从第2位开始截取2个字节则BitConverter.ToInt16(bt,2);2)截取4位长度的字节数组用BitConverter.ToInt32例如…

  • 真正的学懂三极管入门篇(经典)「建议收藏」

    真正的学懂三极管入门篇(经典)「建议收藏」______________________________________________________________________________________________________________________________________不要让温床称为埋葬你的坟墓!要有危机意识,忧患意识,要为明天考虑!禁忌:安于现状,不求上进,不懂得学习,不能恰当

  • 辛星解读mysql的用户管理

    辛星解读mysql的用户管理

  • java中的全局变量和局部变量_JVM中基本变量放在哪

    java中的全局变量和局部变量_JVM中基本变量放在哪正在使用NetBeans做一个稍大点的程序,刚刚学习使用,感觉程序中需要用到全局变量(其实java中是没有全局变量这个概念的)。在网上查了不少的资料,得到一点点体会:首先,java中是没有全局变量这个概念的,java程序中不能像C++那样在类外定义全局变量,因为JAVA当初出现的初衷就是为了安全性和跨平台性,所以去掉了类似C、C++中的全局变量的概念。JAVA中不应该有所谓全局变量的概念,全局变量…

  • OpenCV-Python (Sobel算子)[通俗易懂]

    OpenCV-Python (Sobel算子)[通俗易懂]Sobel算子Sobel算子的基本概念Sobel算子是一个主要用于边缘检测的离散微分算子(discretedifferentiationoperator)。它结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。在图像的任意一点使用此算子,都将会产生对应的梯度矢量或是其法矢量。原型Sobel算子依然是一种过滤器,只是其是带有方向的。在OpenCV-Pyt…

发表回复

您的电子邮箱地址不会被公开。

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