【GD32L233C-START评测】2、rtthread + finsh 组件的移植
[复制链接]
本帖最后由 emmnn 于 2022-1-29 11:10 编辑
前言
距离上次发帖也有两个多星期的时间了,这两天刚回到家,休息了两天,又想起了评测的事,就拿出板子继续玩了。目前还没完全确定要使用这块板子做什么东西,但是为了方便后续的开发及调试工作,就决定先把操作系统移植上去。今天断断续续整了一天(在家里没办法完全静下心来),终于移植好并成功运行了点灯的demo(最终演示效果如下)。
看完了演示视频,下面就开始介绍rtthread的移植过程吧。
一、RT-Thread简介
RT-Thread,一款开源的嵌入式实时操作系统,作为一款优秀的国产操作系统,因其有着可裁剪,内存资源占用小,被广泛地应用在家电,消费电子等领域。关于RT-Thread的介绍这里不再多讲,感兴趣的可以去看他们的官方文档(RT-Thread)。RT-Thread共分为三个版本,分别为标准,nano和smart版本,今天主要介绍的是RT-Thread Nano的移植(RT-Thread下载地址),目前该版本官方更新维护到3.1.5,移植也是以这个版本为准。
下载完成后,我们可以得到一个压缩包,解压后,目录结构如下:
二、RT-Thread移植
介绍完RT-Thread,接下来就可以开始移植工作了。首先先把内核源码和CPU移植文件添加到我们的项目工程中。
这里需要注意的一点是,因为GD32L233C基于Cortex-M23,所以libcpu我们需要选择对应的文件添加。
将src和libcpu这两个文件中的相关内容添加到我们的工程后,接下来我们需要将板级配置文件board.c和rtconfig.h这两个文件也添加到工程中去。
这里因为GD32E230k这款芯片跟GD32L233C同属Cortex-M23,因此我们选择到对应目录下将这两个文件拷贝到工程中。
最后,为了方便后续开发调试,这里选择将finsh组件也移植上去(没这个需求的朋友可以跳过此处)。
同样也是将components/finsh路径下的.c文件添加到工程中 ,最后添加后的工程文件如下:
还有比较重要的一步,添加头文件路径。
内核源码文件都添加后,基本工作也都完成了,接下来我们需要修改配置文件board.c和rtconfig.h,使OS能够适配我们的开发板。
rtconfig.h文件配置如下(关于这个配置文件的介绍,注释讲的挺详细的,这里就不罗嗦了,看不懂的自行百度了):
/* RT-Thread config file */
#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__
// <<< Use Configuration Wizard in Context Menu >>>
// <h>Basic Configuration
// <o>Maximal level of thread priority <8-256>
// <i>Default: 32
#define RT_THREAD_PRIORITY_MAX 32
// <o>OS tick per second
// <i>Default: 1000 (1ms)
#define RT_TICK_PER_SECOND 1000
// <o>Alignment size for CPU architecture data access
// <i>Default: 4
#define RT_ALIGN_SIZE 4
// <o>the max length of object name<2-16>
// <i>Default: 8
#define RT_NAME_MAX 16
// <c1>Using RT-Thread components initialization
// <i>Using RT-Thread components initialization
#define RT_USING_COMPONENTS_INIT
// </c>
#define RT_USING_USER_MAIN
// <o>the stack size of main thread<1-4086>
// <i>Default: 512
#define RT_MAIN_THREAD_STACK_SIZE 1024
// </h>
// <h>Debug Configuration
// <c1>enable kernel debug configuration
// <i>Default: enable kernel debug configuration
//#define RT_DEBUG
// </c>
// <o>enable components initialization debug configuration<0-1>
// <i>Default: 0
#define RT_DEBUG_INIT 0
// <c1>thread stack over flow detect
// <i> Diable Thread stack over flow detect
//#define RT_USING_OVERFLOW_CHECK
// </c>
// </h>
// <h>Hook Configuration
// <c1>using hook
// <i>using hook
//#define RT_USING_HOOK
// </c>
// <c1>using idle hook
// <i>using idle hook
//#define RT_USING_IDLE_HOOK
// </c>
// </h>
// <e>Software timers Configuration
// <i> Enables user timers
#define RT_USING_TIMER_SOFT 0
#if RT_USING_TIMER_SOFT == 0
#undef RT_USING_TIMER_SOFT
#endif
// <o>The priority level of timer thread <0-31>
// <i>Default: 4
#define RT_TIMER_THREAD_PRIO 4
// <o>The stack size of timer thread <0-8192>
// <i>Default: 512
#define RT_TIMER_THREAD_STACK_SIZE 512
// </e>
// <h>IPC(Inter-process communication) Configuration
// <c1>Using Semaphore
// <i>Using Semaphore
#define RT_USING_SEMAPHORE
// </c>
// <c1>Using Mutex
// <i>Using Mutex
//#define RT_USING_MUTEX
// </c>
// <c1>Using Event
// <i>Using Event
//#define RT_USING_EVENT
// </c>
// <c1>Using MailBox
// <i>Using MailBox
#define RT_USING_MAILBOX
// </c>
// <c1>Using Message Queue
// <i>Using Message Queue
//#define RT_USING_MESSAGEQUEUE
// </c>
// </h>
// <h>Memory Management Configuration
// <c1>Dynamic Heap Management
// <i>Dynamic Heap Management
//#define RT_USING_HEAP
// </c>
// <c1>using small memory
// <i>using small memory
#define RT_USING_SMALL_MEM
// </c>
// <c1>using tiny size of memory
// <i>using tiny size of memory
//#define RT_USING_TINY_SIZE
// </c>
// </h>
// <h>Console Configuration
// <c1>Using console
// <i>Using console
#define RT_USING_CONSOLE
// </c>
// <o>the buffer size of console <1-1024>
// <i>the buffer size of console
// <i>Default: 128 (128Byte)
#define RT_CONSOLEBUF_SIZE 128
// </h>
// <h>FinSH Configuration
// <c1>include finsh config
// <i>Select this choice if you using FinSH
#include "finsh_config.h"
// </c>
// </h>
// <h>Device Configuration
// <c1>using device framework
// <i>using device framework
//#define RT_USING_DEVICE
// </c>
// </h>
// <<< end of configuration section >>>
#endif
board.c,这个文件主要是用来配置系统时钟以及OS_TICK(也就是系统心跳)的,一些外设的初始化工作也可以丢到这里面来做。
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2009-01-05 Bernard first implementation
*/
#include <stdint.h>
#include <rthw.h>
#include <rtthread.h>
#include "gd32l23x.h"
#include "usart.h"
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler */
/* User can add his own implementation to report the HAL error return state */
while (1)
{
}
/* USER CODE END Error_Handler */
}
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
/* setup systick timer for 1000Hz interrupts */
if(SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND)) {
/* capture error */
while(1) {
}
}
/* configure the systick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x00U);
#if 0
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
NVIC_SetPriority(SysTick_IRQn, 0);
#endif
}
/**
* This is the timer interrupt service routine.
*
*/
void SysTick_Handler(void)
{
/* enter interrupt */
rt_interrupt_enter();
rt_tick_increase();
/* leave interrupt */
rt_interrupt_leave();
}
/**
* This function will initial GD32 board.
*/
void rt_hw_board_init(void)
{
#if 0 //TODO:中断向量表,后续新增bootloader功能,在这里更改
/* NVIC Configuration */
#define NVIC_VTOR_MASK 0x3FFFFF80
#ifdef VECT_TAB_RAM
/* Set the Vector Table base location at 0x10000000 */
SCB->VTOR = (0x10000000 & NVIC_VTOR_MASK);
#else /* VECT_TAB_FLASH */
/* Set the Vector Table base location at 0x08000000 */
SCB->VTOR = (0x08000000 & NVIC_VTOR_MASK);
#endif
#endif
SystemClock_Config();
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init((void*)HEAP_BEGIN, (void*)HEAP_END);
#endif
usartInit(DEBUG_COM_PER, DEBUG_COM_BAUD);
}
void rt_hw_console_output(const char *str)
{
rt_size_t i = 0, size = 0;
char a = '\r';
size = rt_strlen(str);
for (i = 0; i < size; i++)
{
if (*(str + i) == '\n')
{
usart_data_transmit(DEBUG_COM_PER, (uint32_t )a);
while((usart_flag_get(DEBUG_COM_PER, USART_FLAG_TC) == RESET));
}
usart_data_transmit(DEBUG_COM_PER, (uint32_t)*(str + i));
while((usart_flag_get(DEBUG_COM_PER, USART_FLAG_TC) == RESET));
}
}
char rt_hw_console_getchar(void)
{
/* the initial value of ch must < 0 */
int ch = -1;
if (usart_flag_get(DEBUG_COM_PER, USART_FLAG_RBNE) != RESET)
{
ch = usart_data_receive(DEBUG_COM_PER);
}
else
{
rt_thread_mdelay(10);
}
return ch;
}
其中,rt_hw_console_output和rt_hw_console_getchar这两个函数,分别用来做系统的串口输出处理和tshell 指令输入的获取的,SystemClock_Config则是系统时钟初始化。
到这里,我们可以先尝试编译下工程,会看到有报错问题。
这几个重复定义的,我们直接注释掉即可,因为这几个中断以及被RT-Thread接管了,一般情况下不用再去理会。
再次编译,正常情况下是不会再报错了。最后就是写个demo验证下移植的成果。
static struct rt_thread led_thread;
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_led_thread_stack[512];
static void led_thread_entry(void * para);
static rt_uint8_t led_thread_priority = 5;
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
// PRO_LOG(LOG_DEBUG, "Entry %s. \r\n", __func__);
led_init();
/* led thread */
rt_thread_init(&led_thread,
"led_thread",
led_thread_entry,
RT_NULL,
&rt_led_thread_stack,
sizeof(rt_led_thread_stack),
led_thread_priority,
1000);
rt_thread_startup(&led_thread);
}
static void led_thread_entry(void * para)
{
PRO_LOG(LOG_DEBUG, "Entry %s. \r\n", __func__);
while(1)
{
LED1_TOGGLE();
LED2_TOGGLE();
rt_thread_delay(1000);
}
}
这里的演示结果就是开头的视频,再打开串口看看
Finsh组件也能正常使用。
总结
至此,RT-Thread的移植工作已完成(工程源码见附件),后续有时间再分享其他内容给大家。如果所发内容有什么错误或者大家有什么其他的见解,也欢迎大家在评论区指出,谢谢!
|