|
本帖最后由 sunsili 于 2021-9-1 17:49 编辑
避免弯路:教你RT-Thread完美移植!
之前我发过多篇移植RT-Thread到新唐单片机的帖子,不过都是能满足要求,但是还不够完美,本次帖子,完美解决之前的不完美。
该帖基于最新版的RT-Thread Nano 3.1.5版本。
为了体现帖子的完美性,这次我从头开始说关键点。
创建MDK工程
第一步,基于RTE创建工程,应选择下图的选项
第二步,工程应至少包含以下4个基本库文件
第三步,工程的配置
因为我们可以不使用printf,所以我们可以不包含MicroLIB,甚至我们不用在工程配置里包含STD标准库的头文件进来。
因为BSP的标准库基于AC5编写,所以我们这里最好选择AC5,如果选择AC6,应在警告设置AC5-like ,否则编译会因为打印几百个警告而变慢。
第四步,rtconfig.h配置
第五步,按照#error设定的4个部分配置时钟和硬件初始化,串口初始化,串口输出,串口输入。
RT-Thread移植正式开始
时钟初始化,我们可以找到一个厂家提供的模板,复制SYS_Init();并在其中完善滴答定时器的启动与配置。
打开board.c添加系统初始化代码
- void SYS_Init(void)
- {
- /*---------------------------------------------------------------------------------------------------------*/
- /* Init System Clock */
- /*---------------------------------------------------------------------------------------------------------*/
- /* Unlock protected registers */
- SYS_UnlockReg();
- /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */
- PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);
- /* Enable HIRC clock (Internal RC 48 MHz) */
- CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);
- /* Wait for HIRC clock ready */
- CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);
- /* Set core clock as 51MHz from PLL */
- CLK_SetCoreClock(FREQ_51MHZ);
- /* System Tick Configuration */
- CLK_EnableSysTick(CLK_CLKSEL0_STCLKSEL_HCLK,SystemCoreClock / RT_TICK_PER_SECOND);
- /* Enable UART clock */
- CLK_EnableModuleClock(UART0_MODULE);
- /* Select UART clock source from HIRC */
- CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
- /* Update System Core Clock */
- /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */
- SystemCoreClockUpdate();
- /* Set GPB multi-function pins for UART0 RXD and TXD */
- SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk)) | \
- (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);
- /* Lock protected registers */
- SYS_LockReg();
- }
- CLK_EnableSysTick这个滴答时钟中断使能与配置函数,可以设置滴答定时器的时钟源,重载值,并使能其中断。
- 然后就要完成滴答定时器中断的内容:
- /* systick 中断服务例程 */
- void SysTick_Handler(void)
- {
- rt_os_tick_callback();
- }
复制代码
其中内部的回调函数,rtt的board.c已经帮我们完成,只需要添加以上代码段即可,也可修改回调函数的名字为中断入口。
将系统初始化代码填入#error "TODO 1: OS Tick Configuration."后面,并注释掉该行,确保编译时候不再报错提示该位置。
串口初始化,按如下代码进行初始化
- static int uart_init(void)
- {
- //#error "TODO 2: Enable the hardware uart and config baudrate."
- /* Reset UART0 */
- SYS_ResetModule(UART0_RST);
- /* Configure UART0 and set UART0 baud rate */
- UART_Open(UART0, 115200);
- return 0;
- }
- 串口输出功能
- 之前我用了printf实现这部分,但是有个缺点就是要启用MicroLIB,这样就增加了代码存储空间,其实可以使用STD标准库函数实现如下所示,串口写入函数一共三个参数,第一个选用的串口名,第二个是要发送的字符串地址,这里因为类型不同进行了转换,也可以不转换而修改该预设函数的参数类型。第三个是要发送的字符串长度,我们这里用rt的库函数计算一下传入的长度,这样就做到了一个函数一行就搞定了串口打印的映射。
- void rt_hw_console_output(const char *str)
- {
- //#error "TODO 3: Output the string 'str' through the uart."
- UART_Write(UART0,(uint8_t *)str,rt_strlen(str));
- }
复制代码
串口输入功能
串口输入功能的配置在finsh_port.c
我们完善该弱函数的内容即可,注释掉error提示行。我实现的方法如下:这里是参考了重定向文件里的方法
朋友们,按照这个方法,全部使用BSP提供的库函数就完成了,程序也变的更加友好可读,占用资源更少。
另外注意,在启用了滴答定时器中断后,我们再用CLK_SysTickDelay(1000);延时就会卡住了,这时候系统通过中断接管了滴答定时器的控制权。可以使用rt_thread_mdelay(2000);实现延时。
最后我们测试例子,编写main.c。
- #include "stdio.h"
- #include <NuMicro.h>
- #include <rtthread.h>
- //配置优先级,栈大小,时间片,设置不对没法运行的。
- #define THREAD_PRIORITY 5
- #define THREAD_STACK_SIZE 256
- #define THREAD_TIMESLICE 10
- void led(void *parameter)
- {
- printf("\n\nCPU <a href="home.php?mod=space&uid=72445" target="_blank">@</a> %d Hz\n", SystemCoreClock);
- printf("+-------------------------------------------------+\n");
- printf("| PB14(Output) Sample Code |\n");
- printf("+-------------------------------------------------+\n\n");
- rt_kprintf("Hello RTT_NANO\n");
- while(1)
- {
- PB14=0;
- rt_thread_mdelay(2000);
- printf("\nLED1 is ON\n");
- PB14=1;
- rt_thread_mdelay(2000);
- printf("\nLED1 is OFF\n");
- }
- //return 0;
- }
- /* 导出到 msh 命令列表中 */
- MSH_CMD_EXPORT(led, RT-Thread first led sample);
- void led2(void *parameter)
- {
- rt_kprintf("Hello RTT_NANO\n");
- while(1)
- {
- PB14=0;
- rt_thread_mdelay(3000);
- printf("\nLED2 is ON\n");
-
- PB14=1;
- rt_thread_mdelay(3000);
- printf("\nLED2 is OFF\n");
- }
- //return 0;
- }
- MSH_CMD_EXPORT(led2, RT-Thread second led sample);
- int led_sample(void)
- {
- static rt_thread_t tid = RT_NULL;
- static rt_thread_t tid2 = RT_NULL;
- /* 创建线程1 */
- tid = rt_thread_create("thread1",
- led, RT_NULL,
- THREAD_STACK_SIZE,
- THREAD_PRIORITY, THREAD_TIMESLICE);
- if (tid != RT_NULL) rt_thread_startup(tid);
- /* 创建线程2 */
- tid2 = rt_thread_create("thread2",
- led2, RT_NULL,
- THREAD_STACK_SIZE,
- THREAD_PRIORITY, THREAD_TIMESLICE);
- if (tid2 != RT_NULL) rt_thread_startup(tid2);
- //该例子共用PB14端口,所以一并在创建线程时候初始化为输出模式
- GPIO_SetMode(PB, BIT14, GPIO_MODE_OUTPUT);
- return 0;
- }
- MSH_CMD_EXPORT(led_sample, RT-Thread sample);
- /*---------------------------------------------------------------------------------------------------------*/
- /* Main Function */
- /*---------------------------------------------------------------------------------------------------------*/
- int32_t main(void)
- {
- led_sample();
- return 0;
- }
复制代码
你学会了吗,这样你就不用等RT-Thread Studio支持新唐的芯片了,自己也可以完美移植RTT到新唐单片机了。
|
+10
|