基于GD32的RT-Thread移植(邪修版)
准备源码,配置工程
仅供有移植RTOS基础的人参考借鉴。
添加源码
直接用CubeMX生成的RT-Thread_Nano源码,复制到自己的GD32F303工程内里。
GD32有的芯片是M4架构,注意替换libcpu中的文件。
把RTT源码添加进keil工程
添加头文件
修改部分.c/.h
注释掉几个中断
注释掉GD32的SVC_Handler、PendSV_Handler(void)、SysTick_Handler(void)、HardFault_Handler(void),因为这些函数RT-Thread已经帮我们实现好了。
如:SysTick_Handler
void SysTick_Handler(void)
{rt_interrupt_enter();rt_tick_increase();rt_interrupt_leave();
}
根据板子重新实现特定函数
修改board.c中的rt_hw_board_init。如果需要使用RT-Thread的shell命令行调试工具,还需要修改uart_init(void)、rt_hw_console_output、rt_hw_console_getchar这几个函数
rt_hw_board_init:
这个作用主要就是初始化时钟,关键是要开启SysTick中断。
/*** This function will initial your board.*/
void rt_hw_board_init(void)
{/* * 1: OS Tick Configuration* Enable the hardware timer and call the rt_os_tick_callback function* periodically with the frequency RT_TICK_PER_SECOND. */delay_init(120); /* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INITrt_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
}
uart_init(void)、rt_hw_console_output
// 定义使用的USART端口和引脚
#define CONSOLE_USART USART0static int uart_init(void)
{/* TODO: Please modify the UART port number according to your needs */usart_init(115200); return 0;
}
INIT_BOARD_EXPORT(uart_init);void rt_hw_console_output(const char *str)
{rt_size_t i = 0;rt_size_t size = rt_strlen(str);char a = '\r'; // 换行前添加回车for (i = 0; i < size; i++){// 遇到换行符时先发送回车if (*(str + i) == '\n'){// 等待发送缓冲区为空while (usart_flag_get(CONSOLE_USART, USART_FLAG_TBE) == RESET);usart_data_transmit(CONSOLE_USART, a);}// 发送当前字符while (usart_flag_get(CONSOLE_USART, USART_FLAG_TBE) == RESET);usart_data_transmit(CONSOLE_USART, *(str + i));}// 等待最后一个字符发送完成while (usart_flag_get(CONSOLE_USART, USART_FLAG_TC) == RESET);
}
同时增加一个USART0_IRQHandler
// 接收缓存:-1表示无数据(int类型避免符号警告)
static volatile int usart_rx_buf = -1;
static volatile rt_bool_t usart_rx_ready = RT_FALSE;/*** 串口中断处理函数:接收数据并缓存*/
void USART0_IRQHandler(void)
{rt_interrupt_enter();// 处理接收非空状态(使用状态标志宏USART_FLAG_RBNE)if (usart_flag_get(CONSOLE_USART, USART_FLAG_RBNE) == SET){// 读取接收数据并缓存usart_rx_buf = (int)(usart_data_receive(CONSOLE_USART) & 0xFF);usart_rx_ready = RT_TRUE;// 清除状态标志(读取数据后硬件自动清除,保险起见)usart_flag_clear(CONSOLE_USART, USART_FLAG_RBNE);}rt_interrupt_leave();
}/*** 控制台输入函数:供FinSH调用*/
char rt_hw_console_getchar(void)
{int ch = -1;// 等待中断接收数据while (usart_rx_ready != RT_TRUE){rt_thread_mdelay(1);}// 读取缓存数据ch = usart_rx_buf;usart_rx_ready = RT_FALSE;usart_rx_buf = -1;return (char)ch;
}
board.c参考代码
/** Copyright (c) 2006-2019, RT-Thread Development Team** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2021-05-24 the first version*/#include <rthw.h>
#include <rtthread.h>//#include "main.h"
#include "delay.h"
#include "usart.h" #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
/** Please modify RT_HEAP_SIZE if you enable RT_USING_HEAP* the RT_HEAP_SIZE max value = (sram size - ZI size), 1024 means 1024 bytes*/
#define RT_HEAP_SIZE (15*1024)
static rt_uint8_t rt_heap[RT_HEAP_SIZE];RT_WEAK void *rt_heap_begin_get(void)
{return rt_heap;
}RT_WEAK void *rt_heap_end_get(void)
{return rt_heap + RT_HEAP_SIZE;
}
#endifvoid SysTick_Handler(void)
{rt_interrupt_enter();rt_tick_increase();rt_interrupt_leave();
}#ifdef RT_USING_FINSH
#include <finsh.h>
static void reboot(uint8_t argc, char **argv)
{rt_hw_cpu_reset();
}
MSH_CMD_EXPORT(reboot, Reboot System);
#endif /* RT_USING_FINSH *//*** This function will initial your board.*/
void rt_hw_board_init(void)
{/* * 1: OS Tick Configuration* Enable the hardware timer and call the rt_os_tick_callback function* periodically with the frequency RT_TICK_PER_SECOND. */delay_init(120); /* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INITrt_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
}#ifdef RT_USING_CONSOLE// 定义使用的USART端口和引脚
#define CONSOLE_USART USART0static int uart_init(void)
{/* TODO: Please modify the UART port number according to your needs */usart_init(115200); return 0;
}
INIT_BOARD_EXPORT(uart_init);void rt_hw_console_output(const char *str)
{rt_size_t i = 0;rt_size_t size = rt_strlen(str);char a = '\r'; // 换行前添加回车for (i = 0; i < size; i++){// 遇到换行符时先发送回车if (*(str + i) == '\n'){// 等待发送缓冲区为空while (usart_flag_get(CONSOLE_USART, USART_FLAG_TBE) == RESET);usart_data_transmit(CONSOLE_USART, a);}// 发送当前字符while (usart_flag_get(CONSOLE_USART, USART_FLAG_TBE) == RESET);usart_data_transmit(CONSOLE_USART, *(str + i));}// 等待最后一个字符发送完成while (usart_flag_get(CONSOLE_USART, USART_FLAG_TC) == RESET);
}
#endif#ifdef RT_USING_FINSH// 接收缓存:-1表示无数据(int类型避免符号警告)
static volatile int usart_rx_buf = -1;
static volatile rt_bool_t usart_rx_ready = RT_FALSE;/*** 串口中断处理函数:接收数据并缓存*/
void USART0_IRQHandler(void)
{rt_interrupt_enter();// 处理接收非空状态(使用状态标志宏USART_FLAG_RBNE)if (usart_flag_get(CONSOLE_USART, USART_FLAG_RBNE) == SET){// 读取接收数据并缓存usart_rx_buf = (int)(usart_data_receive(CONSOLE_USART) & 0xFF);usart_rx_ready = RT_TRUE;// 清除状态标志(读取数据后硬件自动清除,保险起见)usart_flag_clear(CONSOLE_USART, USART_FLAG_RBNE);}rt_interrupt_leave();
}/*** 控制台输入函数:供FinSH调用*/
char rt_hw_console_getchar(void)
{int ch = -1;// 等待中断接收数据while (usart_rx_ready != RT_TRUE){rt_thread_mdelay(1);}// 读取缓存数据ch = usart_rx_buf;usart_rx_ready = RT_FALSE;usart_rx_buf = -1;return (char)ch;
}#endif
main示例代码
/************************************************
* WKS Mini GD32开发板
* 串口通信 实验
************************************************/#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"#include <rthw.h>
#include "rtthread.h"
#include <stdio.h>/* 定义线程控制块 */
static rt_thread_t led1_thread = RT_NULL;static void led1_thread_entry(void *parameter)
{while (1){gpio_togglepin(GPIOA, GPIO_PIN_8);rt_thread_delay(500); /* 延时500个tick */
// printf("hello \r\n");}
}int main(void)
{ delay_init(120); //初始化延时函数 usart_init(115200); //初始化串口LED_Init(); //初始化LEDled1_thread = /* 线程控制块指针 */rt_thread_create("led1", /* 线程名字 */led1_thread_entry, /* 线程入口函数 */RT_NULL, /* 线程入口函数参数 */128, /* 线程栈大小 */20, /* 线程的优先级 */20); /* 线程时间片 *//* 启动线程,开启调度 */rt_thread_startup(led1_thread);while(1){rt_thread_delay(100);}
}
shell命令行启动成功,led按预期点亮。