本文讲述如何在FR3068X-C上移植RT-Thread nano操作系统。
1、准备工作
首先,准备最基本的能跑的FR3068x-C工程,本例以SDK中的GPIO_Demo项目为基础。
![Snipaste_2025-02-13_20-52-46.png Snipaste_2025-02-13_20-52-46.png](https://static.assets-stash.eet-china.com/forum/202502/13/173945119161400205311fqewxppvll3t1kzv.png)
项目的文件结构如上图。
2、获取RT-Thread操纵系统源码
RT-Thread Nano是Master的精简版,去掉了一些组件和各种开发板的BSP,保留了OS的核心功能,但足够我们使用了。
下载Nano的源码:https://github.com/RT-Thread/rtthread-nano/archive/refs/heads/master.zip
源码的目录结构如下:
![Snipaste_2025-02-13_21-00-36.png Snipaste_2025-02-13_21-00-36.png](https://static.assets-stash.eet-china.com/forum/202502/13/173945166028317210100w1e4qz2au6767qx5.png)
我们移植的时候只需要上图红圈中的文件,将其拷贝出来,放入我们的工程文件夹中,如下图,Rtthread文件夹中即为我们刚刚拷贝出来的nano源代码文件,为方便阅览,将工程文件夹稍微改造一下,如下图,sdk为FR3068x-C的sdk中的components文件夹改名而来,删除example文件夹,其他App文件夹放置用户app代码,Core文件夹放置防止rtthread的启动文件及配置文件,Project文件夹防止MDK项目文件。
![Snipaste_2025-02-13_21-02-26.png Snipaste_2025-02-13_21-02-26.png](https://static.assets-stash.eet-china.com/forum/202502/13/17394517806104210300glfje1gjv67jg1l1.png)
3、配置MDK项目
按如下图配置项目文件:
![Snipaste_2025-02-13_21-15-36.png Snipaste_2025-02-13_21-15-36.png](https://static.assets-stash.eet-china.com/forum/202502/13/173945256622346211606bf9d4rrbn6rn4nb4.png)
按上图将Nano源码的Src文件夹中所有文件放入项目中Rtt/Src文件夹中,由于FR3068x-C为Cortex-M33核心,将Nano源码中libcpu文件选择arm下的cortex-m33放入项目中Rtt/Port文件夹中,其他文件夹参照上图配置,主要为FR3068x-C的相关源码。
项目配置和GPIO_Demo基本一致,需要注意的是Include Paths需要根据项目实际情况修改,具体如下:
![Snipaste_2025-02-13_21-26-00.png Snipaste_2025-02-13_21-26-00.png](https://static.assets-stash.eet-china.com/forum/202502/13/173945323754643212717allrealapbrqgrgz.png)
4、修改代码
需要修改的地方主要有3点:
1、修改gpio_demo.c文件,需要修改为rhtthread的task函数形式,修改无难度,代码如下:
<pre>#include "rtthread.h"
#include "gpio_demo.h"
void gpio_demo(void *paraments)
{
GPIO_InitTypeDef GPIO_Handle;
/* init GPIO CLOCK */
__SYSTEM_GPIOB_CLK_ENABLE();
__SYSTEM_GPIOD_CLK_ENABLE();
__SYSTEM_GPIO_CLK_SELECT_COREH();
printf("gpio clock:%d\r\n", system_get_peripheral_clock( PER_CLK_GPIOx));
GPIO_Handle.Pin = GPIO_PIN_14|GPIO_PIN_15;
GPIO_Handle.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Handle.Pull = GPIO_PULLUP;
gpio_init(GPIOD, &GPIO_Handle);
while(1)
{
rt_kprintf("led on ...\r\n");
gpio_write_pin(GPIOD, GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET);
rt_thread_mdelay(RT_TICK_PER_SECOND);
rt_kprintf("led off ...\r\n");
gpio_write_pin(GPIOD, GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_CLEAR);
rt_thread_mdelay(RT_TICK_PER_SECOND);
}
}</pre>
复制代码2、修改main文件,将源main文件中时钟和串口初始化部分移除至新的init.c文件,即将硬件初始化部分独立出来。
ini.c文件如下:
<pre>#include "fr30xx.h"
int fputc(int ch, FILE *stream)
{
while(__UART_IS_TxFIFO_FULL(UART3));
__UART_WRITE_FIFO(UART3, ch);
return ch;
}
void console_uart_init(void)
{
GPIO_InitTypeDef GPIO_Handle;
UART_HandleTypeDef Uart3_handle;
/* Uart3 IO init */
GPIO_Handle.Pin = GPIO_PIN_4|GPIO_PIN_5;
GPIO_Handle.Mode = GPIO_MODE_AF_PP;
GPIO_Handle.Pull = GPIO_PULLUP;
GPIO_Handle.Alternate = GPIO_FUNCTION_1;
gpio_init(GPIOB, &GPIO_Handle);
__SYSTEM_UART_CLK_SELECT_COREH();
Uart3_handle.UARTx = UART3;
Uart3_handle.Init.BaudRate = 115200;
Uart3_handle.Init.DataLength = UART_DATA_LENGTH_8BIT;
Uart3_handle.Init.StopBits = UART_STOPBITS_1;
Uart3_handle.Init.Parity = UART_PARITY_NONE;
Uart3_handle.Init.FIFO_Mode = UART_FIFO_ENABLE;
uart_init(&Uart3_handle);
printf("SystemCoreClock:%d\r\n", system_get_CoreClock());
printf("SystemDSPClock:%d\r\n", system_get_DSPClock());
printf("System_CORE_HSCLK:%d\r\n", system_get_CORE_HSCLK());
printf("System_SPLLCLK:%d\r\n", system_get_SPLLCLK());
printf("System_AUPLLCLK:%d\r\n", system_get_AUPLLCLK());
}
void system_clock_config(void)
{
System_ClkConfig_t ClkConfig;
pmu_init();
/* CORE HSCLK Config */
ClkConfig.CORE_HSCLK_CFG.CORE_HSCLK_Source = CORE_HSCLK_SEL_HES;
/* PLL clock = HSE_VALUE*N + (HSE_VALUE/65535)*M */
/* SPLL CLK Config */
ClkConfig.SPLL_CFG.PowerEn = PLL_POWER_ENABLE;
ClkConfig.SPLL_CFG.PLL_N = 8;
ClkConfig.SPLL_CFG.PLL_M = 0;
/* PLL clock = HSE_VALUE*N + (HSE_VALUE/65535)*M */
/* AUPLL CLK Config */
ClkConfig.AUPLL_CFG.PowerEn = PLL_POWER_DISABLE;
ClkConfig.AUPLL_CFG.PLL_N = 8;
ClkConfig.AUPLL_CFG.PLL_K = 0;
ClkConfig.AUPLL_CFG.PLL_D = 0;
System_CORE_HSCLK_config(&ClkConfig.CORE_HSCLK_CFG);
if (System_SPLL_config(&ClkConfig.SPLL_CFG,200) == -1)
while(1);
if (System_AUPLL_config(&ClkConfig.AUPLL_CFG,200) == -1)
while(1);
ClkConfig.MCU_Clock_Source = MCU_CLK_SEL_CORE_HSCLK;
ClkConfig.SOC_DIV = 1; /* This parameter is valid when MCU_Clock_Source == MCU_CLK_SEL_SPLL_CLK */
ClkConfig.MCU_DIV = 1;
ClkConfig.APB0_DIV = 1;
ClkConfig.APB1_DIV = 1;
ClkConfig.APB2_DIV = 1;
System_MCU_clock_Config(&ClkConfig);
}</pre>
复制代码main.c文件修改为task启动代码:
<pre>#include "rtthread.h"
#include "gpio_demo.h"
// 启动线程
static void StartUpThread( rt_thread_t *handle,
const char *name,
void (*entry)(void *parameter),
void *parameter,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick)
{
*handle = rt_thread_create(name, entry, parameter, stack_size, priority, tick);
if (*handle != RT_NULL)
{
rt_thread_startup(*handle);
}
rt_thread_mdelay(10);
}
rt_thread_t _task_gpio = RT_NULL;
int main(void)
{
StartUpThread(&_task_gpio, "gpio", gpio_demo, RT_NULL, 512, 1, 10);
return 0;
}</pre>
复制代码board文件需要配置heap空间,配置硬件启动代码,并初始化systick时钟,这部分相对复杂一些。代码如下:
<pre>#include <rthw.h>
#include <rtthread.h>
#include "fr30xx.h"
extern void system_init(void);
extern uint32_t system_get_CORE_HSCLK(void);
extern void main_entry_point(void);
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#ifdef __ICCARM__
// Use *.icf ram symbal, to avoid hardcode.
extern char __ICFEDIT_region_IRAM1_end__;
#define MCU_SRAM_END &__ICFEDIT_region_IRAM1_end__
#else
// 根据自己的MCU不同修改
#define MCU_SRAM_SIZE 128
// 根据自己的MCU不同修改
#define MCU_SRAM_END (0x20000000 + MCU_SRAM_SIZE * 1024)
#endif
#ifdef __ICCARM__
#pragma section="HEAP"
#define HEAP_BEGIN (__segment_end("HEAP"))
#else
extern int Image$RW_IRAM1$ZI$Limit;
#define HEAP_BEGIN (&Image$RW_IRAM1$ZI$Limit)
#endif
#define HEAP_END MCU_SRAM_END
RT_WEAK void *rt_heap_begin_get(void)
{
return (void*)HEAP_BEGIN;
}
RT_WEAK void *rt_heap_end_get(void)
{
return (void *)HEAP_END;
}
#endif
void rt_os_tick_callback(void)
{
rt_interrupt_enter();
rt_tick_increase();
rt_interrupt_leave();
}
void SysTick_Handler(void)
{
rt_os_tick_callback();
}
/**
* This function will initial your board.
*/
void rt_hw_board_init(void)
{
main_entry_point();
system_init();
SysTick_Config(system_get_CORE_HSCLK() / RT_TICK_PER_SECOND);
// #error "TODO 1: OS Tick Configuration."
/*
* TODO 1: OS Tick Configuration
* Enable the hardware timer and call the rt_os_tick_callback function
* periodically with the frequency 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
}</rtthread.h></rthw.h></pre>
复制代码所以这里,我们首先删除system_fr30xx.c中如下部分代码:
<pre>extern int $Super$main(void);
int $Sub$main(void)
{
main_entry_point();
$Super$main();
return 0;
}</pre>
复制代码到此,所有代码方面的改动全部完成,编译并烧录测试。
![Snipaste_2025-02-13_22-09-50.png Snipaste_2025-02-13_22-09-50.png](https://static.assets-stash.eet-china.com/forum/202502/13/173945583014372221030qdddxdqedeenxgtd.png)
如上图所示,程序正常运行,task中断点已生效,同样,串口日志也正常输出:
![Snipaste_2025-02-13_22-08-56.png Snipaste_2025-02-13_22-08-56.png](https://static.assets-stash.eet-china.com/forum/202502/13/173945575390317220913p4cf44kh2ksjj3ch.png)
OK,移植完毕。