RT-Thread内核移植

 

记录代码移植过程,成功一步记录一步

第一步:建立裸机程序

使用STM32CubeMx建立一个裸机程序

RT-Thread内核移植_第1张图片

生成MDK5工程

第二步:参考0-bare-metal完成board.c、board.h文件

RT-Thread内核移植_第2张图片

在Drivers组下添加board.c、board.h文件

RT-Thread内核移植_第3张图片 添加board.c文件

实现board.c里面关于关于时钟配置、串口初始化、GPIO初始化等函数

void bsp_uart_init(void) 
{ 
    MX_USART1_UART_Init(); 
}
 
void bsp_uart_send(char c) 
{ 
    while ((__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) == RESET)); 
    huart1.Instance->DR = c; 
} 
void bsp_led_init(void) 
{ 
    MX_GPIO_Init(); 
} 
void bsp_led_on(void) 
{ 
    HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin, GPIO_PIN_RESET); 
} 
void bsp_led_off(void) 
{ 
    HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin, GPIO_PIN_SET); 
}
void rt_hw_board_init() 
{ 
    /* HAL_Init() function is called at the beginning of program after reset and     before     *    the clock configuration. */ 
        HAL_Init(); 
    /* Clock Config: 
      * System Clock : 80M  
      * HCLK : 80M 
      * PCLK1 : 80M 
      * PCLK2 : 80M 
      * SDMMC1 : 48M 
      * USART1 : PCLK2 */ 
     SystemClock_Config(); 
     bsp_led_init(); 
     bsp_uart_init(); 
}

void SystemClock_Config(void)

void _Error_Handler(char *file, int line)

以上两个函数采用cubemx工具生成的函数,main函数和例程中一样

现象:

RT-Thread内核移植_第4张图片

第三步:添加RT-Thread源码

拷贝RT-Thread源代码到工程路径下,当然也可以不移动,就是指定路径的时候长一点,没关系

添加两个新组一个叫做kernel,防止内核代码,另一个叫做CROTEX-M3放置平台相关代码,我用的是STM32F103ZET6使用的是crotex-m3内核。

添加相关文件到对应的组下面,添加完如图,对了还有一个rtconfig.h文件,用于配置和裁剪内核。

RT-Thread内核移植_第5张图片

RT-Thread内核移植_第6张图片

RT-Thread内核移植_第7张图片

RT-Thread内核移植_第8张图片

添加代码之后别忘了添加头文件,rtconfig.h文件放在了工程的根目录之下,别忘了添加头文件。

在编译之后有了有符号重定义,注释掉原有的函数

在编译之后有了有符号重定义,注释掉原有的函数
//void HardFault_Handler(void) 
//{ 
// /* USER CODE BEGIN HardFault_IRQn 0 */ 
// /* USER CODE END HardFault_IRQn 0 */ 
// while (1) 
// { 
// /* USER CODE BEGIN W1_HardFault_IRQn 0 */ 
// /* USER CODE END W1_HardFault_IRQn 0 */ 
// } 
// /* USER CODE BEGIN HardFault_IRQn 1 */ 
// /* USER CODE END HardFault_IRQn 1 */ //}
 
//void PendSV_Handler(void) 
//{ 
// /* USER CODE BEGIN PendSV_IRQn 0 */ 
// /* USER CODE END PendSV_IRQn 0 */ 
// /* USER CODE BEGIN PendSV_IRQn 1 */ 
// /* USER CODE END PendSV_IRQn 1 */ 
//} 

编译下载正常运行

第四步:console移植,实现控制台输出功能

实现函数

void rt_hw_console_output(const char *str) 
{ 
    RT_ASSERT(str != RT_NULL); 
    while (*str != '\0') 
    { 
        if (*str == '\n') 
        { 
            bsp_uart_send('\r'); 
        } 
        bsp_uart_send(*str++); 
    } 
}

这个函数主要是实现bsp_usart_send,此函数在第二步已经实现。

接下来修改SysTick_Handler函数

/** * @brief This function handles System tick timer. */ 
void SysTick_Handler(void) 
{ 
    rt_interrupt_enter(); 
    rt_tick_increase(); 
    rt_interrupt_leave(); 
}

注意包含rtthread.h头文件

修改main函数如下

int main(void) 
{ 
    while (1) 
    { 
        /* USER CODE END WHILE */ 
        /* USER CODE BEGIN 3 */ 
        rt_kprintf("led on\n"); 
        rt_thread_delay(RT_TICK_PER_SECOND); 
        rt_kprintf("led off\n"); 
        rt_thread_delay(RT_TICK_PER_SECOND); 
        } 
    /* USER CODE END 3 */ 
}

编译下载输出如图

RT-Thread内核移植_第9张图片

第五步:内存堆配置,实现动态内存管理功能

在rt_config.h中添加宏

//#define RT_USING_NOHEAP 
#define RT_USING_SMALL_MEM 
#define RT_USING_HEAP

注意:注释掉RT_USING_NOHEAP,如果有的话

在rt_hw_board_init函数中添加动态内存管理初始化函数

void rt_hw_board_init() 
{ 
    static uint8_t heap_buf[10 * 1024];
    ……….
    rt_system_heap_init(heap_buf, heap_buf + sizeof(heap_buf) - 1); 
}

在main函数中初始化一个线程函数

#define THREAD_PRIORITY 25 
#define THREAD_STACK_SIZE 512 
#define THREAD_TIMESLICE 5 
void test_thread_entry(void *parameter)
{ 
    while (1) 
    { 
        rt_kprintf("enter test thread\n"); 
        rt_thread_delay(RT_TICK_PER_SECOND); 
    }
} 
/** * @brief The application entry point. * * @retval None */ 
int main(void)
{ 
    rt_thread_t tid; 
    tid = rt_thread_create("test", 
                            test_thread_entry, 
                            RT_NULL, 
                            THREAD_STACK_SIZE, 
                            THREAD_PRIORITY, 
                            THREAD_TIMESLICE); 
    if (tid != RT_NULL) 
    { 
        rt_thread_startup(tid); 
        return 0; 
    }
    else 
    { 
        return -1; 
    } 
}

编译下载,输出如图

RT-Thread内核移植_第10张图片

第六步:实现Finsh Shell功能

将components组件文件夹下的drivers和finsh文件添加到工程

新建finsh组和DeviceDrivers组,添加文件

RT-Thread内核移植_第11张图片

 

在前几步添加文件的时候在Kernel组莫名少添加了device.c文件在调试的时候浪费很长时间,

在官方的1-basic的rt-thread\src文件下也没有,感受到来自NPC的调戏。

添加代码之后先修改board.c文件里的rt_hw_board_init函数,

/** * This function will initial STM32 board. */ 
void rt_hw_board_init() 
{ 
    static uint8_t heap_buf[10 * 1024]; 
    /* HAL_Init() function is called at the beginning of program after reset and before     *   the clock configuration. */ 
    HAL_Init(); 
    /* Clock Config: 
     * System Clock : 80M 
     * HCLK : 80M 
     * PCLK1 : 80M 
     * PCLK2 : 80M 
     * SDMMC1 : 48M 
     * USART1 : PCLK2 
    */ 
    SystemClock_Config(); 
    /* Configure the Systick interrupt time */ 
    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / RT_TICK_PER_SECOND); 
    /* Configure the Systick */ 
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); 
    /* SysTick_IRQn interrupt configuration */ 
    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); 
    //bsp_led_init(); 
    stm32_hw_usart_init(); 
 
#ifdef RT_USING_CONSOLE 
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME); 
#endif #ifdef RT_USING_HEAP 
    rt_system_heap_init(heap_buf, heap_buf + sizeof(heap_buf) - 1); 
#endif
#ifdef RT_USING_COMPONENTS_INIT 
    rt_components_board_init(); 
#endif
}

stm32_hw_usart_init();

用来初始化并注册串口

屏蔽掉board.c文件里面串口初始化函数、串口发送函数、控制台输出函数,工作交给drv_usart.c。

接下来修改rtconfig.h中的宏定义

添加#define BSP_USING_UART1

添加后rtconfig.h如下

#ifndef RT_CONFIG_H__ 
#define RT_CONFIG_H__ 
/* Automatically generated file; DO NOT EDIT. */ 
/* RT-Thread Configuration */ 
/* RT-Thread Kernel */ 
#define RT_NAME_MAX 8
#define RT_ALIGN_SIZE 4 
#define RT_THREAD_PRIORITY_32 
#define RT_THREAD_PRIORITY_MAX 32 
#define RT_TICK_PER_SECOND 1000 
#define RT_USING_OVERFLOW_CHECK 
#define RT_USING_HOOK 
#define RT_IDEL_HOOK_LIST_SIZE 4 
#define IDLE_THREAD_STACK_SIZE 256 
#define RT_DEBUG 
/* Inter-Thread communication */ 
#define RT_USING_SEMAPHORE 
#define RT_USING_MUTEX 
#define RT_USING_EVENT 
#define RT_USING_MAILBOX 
#define RT_USING_MESSAGEQUEUE 
/* Memory Management */ 
//#define RT_USING_NOHEAP 
#define RT_USING_SMALL_MEM 
#define RT_USING_HEAP 
/* Kernel Device Object */ 
#define RT_USING_DEVICE 
#define RT_USING_CONSOLE 
#define RT_CONSOLEBUF_SIZE 128 
#define RT_CONSOLE_DEVICE_NAME "uart1" 
/* RT-Thread Components */ 
#define RT_USING_COMPONENTS_INIT 
#define RT_USING_USER_MAIN 
#define RT_MAIN_THREAD_STACK_SIZE 2048 
#define RT_MAIN_THREAD_PRIORITY 10 
/* C++ features */ 
/* Command shell */ 
#define RT_USING_FINSH 
#define FINSH_THREAD_NAME "tshell" 
#define FINSH_USING_HISTORY 
#define FINSH_HISTORY_LINES 5 
#define FINSH_USING_SYMTAB 
#define FINSH_USING_DESCRIPTION 
#define FINSH_THREAD_PRIORITY 20 
#define FINSH_THREAD_STACK_SIZE 4096 
#define FINSH_CMD_SIZE 80 
#define FINSH_USING_MSH 
#define FINSH_USING_MSH_DEFAULT 
#define FINSH_ARG_MAX 10 
/* Device virtual file system */ 
/* Device Drivers */ 
#define RT_USING_DEVICE_IPC 
#define RT_PIPE_BUFSZ 512 
#define RT_USING_SERIAL 
/* Env config */ 
#define SYS_PKGS_DOWNLOAD_ACCELERATE 
#define BSP_USING_UART1 
#endif 

之前mian函数中的初始化函数去掉

编译下载如图

RT-Thread内核移植_第12张图片

出了问题,finsh没有跑起来,没有msh>,重启、没有、重启、还没有

调试了很久还是不行,之后经大神指点在rtdef.h文件如图位置添加了RT_USED

RT-Thread内核移植_第13张图片

编译下载,还是没有,不过这次是因为串口接收引脚模式配置错误,修改之后编译下载运行,

RT-Thread内核移植_第14张图片

成功运行,但是为什么要加RT_USED,还是不知道。

以上

对了,这种移植模式值得吐槽,希望以后官方可以更加人性化一点

这里可以下载移植好的程序

https://www.rt-thread.org/qa/forum.php?mod=viewthread&tid=7794&page=1&extra=#pid37101

你可能感兴趣的:(RT-Thread)