基於STM32標準庫移植RT-Thread Nano

Acuity.發表於2020-11-05




1 前言

  RT-Thread Nano是RT-Thread(RTT)的裁剪版,相比完整版本的RT-Thread,RT-Thread Nano保留了RT-Thread的硬實時核心,保證了極少的資源消耗。“麻雀雖小五臟俱全”,RT-Thread Nano核心包含完整的作業系統功能, 執行緒管理、執行緒間同步與通訊、時鐘管理、中斷管理、記憶體管理等。執行緒通訊與標準版RT-Thread的相容,無縫支援RT-Thread應用程式。


在這裡插入圖片描述

RT-Thread Nano核心


  更多RT-Thread Nano描述,參考RT-Thread官方文件


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一個排程核心即可,複用已有的驅動、元件


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

第二步:拷貝原始碼

  • 將RT-Thread Nano原始碼拷貝到 工程原始碼目錄下,目錄內容包括:

    [1] 原始碼檔案,include、libcpu、src 資料夾,如需需finsh元件,還需新增components檔案

    [2] 配置檔案,原始碼程式碼 rtthread/bsp 資料夾下board.c rtconfig.h

在這裡插入圖片描述

工程下RT-Thread原始碼目錄

第三步:加入工程

  • 新增工程下 RT-Thread/src/ 資料夾中所有檔案到工程
  • 新增工程下 RT-Thread/libcpu/ 資料夾中相應核心的 CPU 移植檔案及上下文切換檔案cpuport.ccontext_iar.S
  • 新增 RT-Thread/ 資料夾下的板級配置檔案board.c

在這裡插入圖片描述

工程下目錄

第四步:新增標頭檔案路徑

在這裡插入圖片描述

新增RT-Thread Nano標頭檔案路徑

第五步:板級配置

  這一步主要是板級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小系統工程移植完成。

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,建立執行緒指定優先順序不能超過該值

  完整示例工程下載:點選下載

相關文章