习惯在rtos下写代码回不去祼机下大循环标志位的写法,几K内存也跑个RTOS,参照论坛一篇rt-thread nano移植的帖子,也做了一次rt-thread nano的适配到M031LE3AE芯片。finsh串口为UART1的PB6、PB7,芯片时钟为内部RC 48MHz。
一、在keil MDK安装相应的组件包,并配置加入工程中
二、加入新M0的硬件驱动库并加入头文件 路径
三、配置rtconfig.h文件
四、修改board.c及finsh_port.c文件完成BSP硬件对接
修改RT_HEAP_SIZE为合适的堆大小,不然没法编译
把retarget.c文件的HardFault_Handler函数注释掉,由rt-thread nano的HardFault_Handler接管 修改system_M031Serials.c的系统时钟为__HIRC
uint32_t SystemCoreClock = __HIRC;
uint32_t CyclesPerUs = (__HIRC / 1000000);
uint32_t PllClock = __HIRC;
依次按照#error设定的4个部分配置时钟和硬件初始化,串口初始化,串口输出,串口输入。 时钟初始化,复制SYS_Init(); 并在其中完善滴答定时器的启动与配置。 打开board.c添加系统初始化代码
void SYS_Init(void)
{
SYS_UnlockReg();
PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);
CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);
CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);
CLK_SetCoreClock(FREQ_48MHZ);
CLK_EnableSysTick(CLK_CLKSEL0_STCLKSEL_HCLK,SystemCoreClock / RT_TICK_PER_SECOND);
CLK_EnableModuleClock(UART1_MODULE);
CLK_SetModuleClock(UART1_MODULE, CLK_CLKSEL1_UART1SEL_HIRC, CLK_CLKDIV0_UART1(1));
SystemCoreClockUpdate();
SYS->GPB_MFPL = (SYS->GPB_MFPL & ~(SYS_GPB_MFPL_PB6MFP_Msk | SYS_GPB_MFPL_PB7MFP_Msk)) | \
(SYS_GPB_MFPL_PB7MFP_UART1_TXD | SYS_GPB_MFPL_PB6MFP_UART1_RXD);
SYS_LockReg();
}
滴答定时器中断的内容:
/* systick 中断服务例程 */
void SysTick_Handler(void)
{
rt_os_tick_callback();
}
其中内部的回调函数,rtt的board.c已经帮我们完成,只需要添加以上代码段即可,也可修改回调函数的名字为中断入口。
将系统初始化代码填入#error "TODO 1: OS Tick Configuration."后面,并注释掉该行,确保编译时候不再报错提示该位置。 串口初始化,按如下代码进行初始化
static int uart_init(void)
{
SYS_ResetModule(UART1_RST);
UART_Open(UART1, 115200);
return 0;
}
串口输出功能 串口打印函数是调用rt-thread nano的rt_kprintf函数,
voidrt_hw_console_output(const char *str)
{
UART_Write(UART1,(uint8_t *)str,rt_strlen(str));
}
串口输入功能
串口输入功能的配置在finsh_port.c
RT_WEAK char rt_hw_console_getchar(void)
{
int ch = -1;
if((UART1->FIFOSTS & UART_FIFOSTS_RXEMPTY_Msk) == 0)
{
return (UART1->DAT);
}
return ch;
}
完整board.c文件
#include <rthw.h>
#include <rtthread.h>
#include <NuMicro.h>
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE (12*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;
}
#endif
void rt_os_tick_callback(void)
{
rt_interrupt_enter();
rt_tick_increase();
rt_interrupt_leave();
}
void SysTick_Handler(void)
{
rt_os_tick_callback();
}
void SYS_Init(void)
{
SYS_UnlockReg();
PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);
CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk);
CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk);
CLK_SetCoreClock(FREQ_51MHZ);
CLK_EnableSysTick(CLK_CLKSEL0_STCLKSEL_HCLK,SystemCoreClock / RT_TICK_PER_SECOND);
CLK_EnableModuleClock(UART0_MODULE);
CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
SystemCoreClockUpdate();
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);
SYS_LockReg();
}
void rt_hw_board_init(void)
{
#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
}
#ifdef RT_USING_CONSOLE
static int uart_init(void)
{
SYS_ResetModule(UART0_RST);
UART_Open(UART0, 115200);
return 0;
}
INIT_BOARD_EXPORT(uart_init);
void rt_hw_console_output(const char *str)
{
UART_Write(UART0,(uint8_t *)str,rt_strlen(str));
}
#endif
五、测试代码
#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)
{
rt_kprintf("\n\nCPU @ %d Hz\n", SystemCoreClock);
rt_kprintf("+-------------------------------------------------+\n");
rt_kprintf("| PB14(Output) Sample Code |\n");
rt_kprintf("+-------------------------------------------------+\n\n");
rt_kprintf("Hello RTT_NANO\n");
while(1)
{
PB14=0;
rt_thread_mdelay(2000);
rt_kprintf("\nLED1 is ON\n");
PB14=1;
rt_thread_mdelay(2000);
rt_kprintf("\nLED1 is OFF\n");
}
}
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);
rt_kprintf("\nLED2 is ON\n");
PB14=1;
rt_thread_mdelay(3000);
rt_kprintf("\nLED2 is OFF\n");
}
}
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;
tid = rt_thread_create("thread1",
led, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
if (tid != RT_NULL)
rt_thread_startup(tid);
tid2 = rt_thread_create("thread2",
led2, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
if (tid2 != RT_NULL)
rt_thread_startup(tid2);
GPIO_SetMode(PB, BIT14, GPIO_MODE_OUTPUT);
return 0;
}
MSH_CMD_EXPORT(led_sample, RT-Thread sample);
int32_t main(void)
{
led_sample();
return 0;
}
六、rt-thread nano对新塘M0的适配还是很简单的,新建工程->添加组件->添加驱动库->屏蔽hard_fault_handler函数->按照错误提示修改系统时钟驱动接口->测试
在secureCRT打印不会换行还没找原因 只能在SSCOM下先用着
完整工程下载连接:https://download.csdn.net/download/dmjkun/85059255
|