打印
[应用相关]

基于STM32标准库移植RT-Thread Nano

[复制链接]
955|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tfqi|  楼主 | 2021-7-7 12:12 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
1 前言
  RT-Thread Nano是RT-Thread(RTT)的裁剪版,相比完整版本的RT-Thread,RT-Thread Nano保留了RT-Thread的硬实时内核,保证了极少的资源消耗。“麻雀虽小五脏俱全”,RT-Thread Nano内核包含完整的操作系统功能, 线程管理、线程间同步与通信、时钟管理、中断管理、内存管理等。线程通信与标准版RT-Thread的兼容,无缝支持RT-Thread应用程序。




RT-Thread Nano内核


使用特权

评论回复
沙发
tfqi|  楼主 | 2021-7-7 12:13 | 只看该作者
2 什么时候使用RT-Thread Nano
  标准版RT-Thread包含了内核、设备驱动、第三方组件、packages等等,而且这些几乎都是开源的,通过“堆积木”的方式即可快速搭建一个基本项目小系统工程,但是带来的代价之一是增加资源(RAM、ROM)的消耗,一些资源比较紧张的CPU则需外扩RAM和ROM。RT-Thread Nano最大特点之一是“资源占用小”,基于资源不足的考虑,RT-Thread Nano是一个优异的选择。


  使用RT-Thread Nano的场景参考建议:

  • 资源有限

RAM、ROM资源有限,而项目任务量比较多,必须使用RTOS,此时考虑使用RT-Thread Nano

  • 只需一个调度内核

只需一个调度内核,不需设备管理、第三方组件等外部资源,直接使用RT-Thread Nano,省去裁剪标准RTT时间

  • 复用已有的设备驱动、组件

公司已存在一套出货量巨大的、稳定的设备驱动、组件,不需要使用RTT设备驱动和组件,此时建议使用RT-Thread Nano一个调度内核即可,复用已有的驱动、组件


使用特权

评论回复
板凳
tfqi|  楼主 | 2021-7-7 12:13 | 只看该作者
3 STM32标准库移植
  RT-Thread Nano移植非常简单,RT-Thread Nano已经支持常用CPU,相关启动文件已经提供,移植步骤也给出详细的描述文档,可以参考官方移植教程。对于Keil MDK的下移植,RT-Thread Nano 已集成在其IDE中,可以直接在 IDE 中进行下载添加,十分便捷,而且与使用何种库没有太多关系。本文主要描述IAR下的STM32标准库移植(其实差异也很小很小!)。


第一步:准备IAR工程和RT-Thread Nano源码

  • 准备一个可以正常使用的裸机代码IAR工程
  • 下载RT-Thread Nano代码,RT-Thread Nano




使用特权

评论回复
地板
tfqi|  楼主 | 2021-7-7 12:14 | 只看该作者
第二步:拷贝源码

将RT-Thread Nano源码拷贝到 工程源码目录下,目录内容包括:

[1] 源码文件,include、libcpu、src 文件夹,如需需finsh组件,还需添加components文件

[2] 配置文件,源码代码 rtthread/bsp 文件夹下board.c 与 rtconfig.h



工程下RT-Thread源码目录


使用特权

评论回复
5
tfqi|  楼主 | 2021-7-7 12:15 | 只看该作者
第三步:加入工程

  • 添加工程下 RT-Thread/src/ 文件夹中所有文件到工程
  • 添加工程下 RT-Thread/libcpu/ 文件夹中相应内核的 CPU 移植文件及上下文切换文件cpuport.c和 context_iar.S
  • 添加 RT-Thread/ 文件夹下的板级配置文件board.c




工程下目录


使用特权

评论回复
6
tfqi|  楼主 | 2021-7-7 12:15 | 只看该作者

第四步:添加头文件路径

添加RT-Thread Nano头文件路径

使用特权

评论回复
7
tfqi|  楼主 | 2021-7-7 12:16 | 只看该作者
第五步:板级配置

  这一步主要是板级CPU相关信息配置,源码文件位于board.c。我直接拷贝现有的STM32的工程board.c文件,几乎不用修改。


  • RT-Thread Nano 已实现异常处理函数 HardFault_Handler和悬挂处理函数 PendSV_Handler,如原工程已实现这两者中断函数,应屏蔽掉,避免编译报错
  • 中断向量,如果存在BootLoader,需先设置中断偏移地址;如没有则不需配置


void rt_hw_board_init()
{
          /* 配置中断向量表偏偏移地址 */
          NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x400);
         
    /* System Clock Update */
    SystemCoreClockUpdate();

    /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);

    /* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}



  • 时钟配置,调用SystemCoreClockUpdate配置CPU主时钟
  • 添加系统时钟节拍


/* 滴答定时器配置 */
static uint32_t _SysTick_Config(rt_uint32_t ticks)
{
    if ((ticks - 1) > 0xFFFFFF)
    {
        return 1;
    }

    _SYSTICK_LOAD = ticks - 1;
    _SYSTICK_PRI = 0xFF;
    _SYSTICK_VAL  = 0;
    _SYSTICK_CTRL = 0x07;  

    return 0;
}

/* 时钟节拍中断函数 */
void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}



  至此,一个基本的RT-Thread Nano小系统工程移植完成。


使用特权

评论回复
8
tfqi|  楼主 | 2021-7-7 12:17 | 只看该作者
4 应用实例

  main函数为RT-Thread Nano的主线程,我们再创建于一个led线程。


void GPIO_Configuration(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;       
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;               
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
}

static void led_thread_entry(void* parameter)
{
        GPIO_Configuration();
    for (;;)
    {
                  GPIO_SetBits(GPIOB, GPIO_Pin_0);
                rt_thread_mdelay(500);
        GPIO_ResetBits(GPIOB, GPIO_Pin_0);
                rt_thread_mdelay(500);
    }
}

void led_thread_init(void)
{
          static rt_uint8_t s_led_stack[256];
          static struct rt_thread led_thread;
    rt_err_t result;

    result = rt_thread_init(&led_thread,
                            "led",
                            led_thread_entry,
                            RT_NULL,
                            (rt_uint8_t*)&s_led_stack[0],
                            sizeof(s_led_stack),
                            7,
                            5);
    if (result == RT_EOK)
    {
        rt_thread_startup(&led_thread);
    }
}





注意:

  • main线程默认堆栈大小为512字节,如main线程任务量比较大,需调堆栈大小,否则导致线程堆栈溢出
  • RT-Thread Nano默认配置不支持动态线程,因此采用静态方式创建线程
  • RT-Thread Nano线程优先级默认最低为8,创建线程指定优先级不能超过该值



使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

56

主题

3317

帖子

4

粉丝