CH32V3xx RT-Thread Nano调试记录

1、工程创建

使用MounRiver集成开发环境可以直接创建带有RT-Thread Nano的工程,步骤如下:
打开MounRiver,点击新建MounRiver工程;
在这里插入图片描述
在模板类型处选择RT-Thread,然后选择使用的芯片型号,点击完成工程就创建好了。
在这里插入图片描述
创建完的工程如下
在这里插入图片描述

2、代码修改与调试

2.1 RT-Thread 配置

首先确认一下RT-Thread的配置情况,根据自己的需要进行修改。

/* RT-Thread config file */

#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__

#if defined(__CC_ARM) || defined(__CLANG_ARM)
#include "RTE_Components.h"

#if defined(RTE_USING_FINSH)
#define RT_USING_FINSH
#endif //RTE_USING_FINSH

#endif //(__CC_ARM) || (__CLANG_ARM)

// <<< 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  16			// 优先级最大16
// <o>OS tick per second
//  <i>Default: 1000   (1ms)
#define RT_TICK_PER_SECOND  1000			// 每秒1000tick 即1tick = 1ms
// <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    8
// <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     512		// main线程栈大小为512

// </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_MEMPOOL
//#define RT_USING_MEMHEAP
#define RT_USING_SMALL_MEM		// 使用小内存管理
#define RT_USING_HEAP			// 使用内存堆


// </c>
// <c1>using tiny size of memory
//  <i>using tiny size of memory
//#define RT_USING_TINY_SIZE
// </c>
// </h>

/* Kernel Device Object */

#define RT_USING_DEVICE			// 使用device框架

#if 0							// 使用的MCU RAM空间不是很大,将控制台部分全部注释掉不使用
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE 128
#define RT_CONSOLE_DEVICE_NAME  "uart5"


#define RT_USING_FINSH
#if defined(RT_USING_FINSH)
    #define FINSH_USING_MSH
    #define FINSH_USING_MSH_DEFAULT
    #define FINSH_USING_MSH_ONLY
    #define FINSH_THREAD_NAME "tshell"

    #define __FINSH_THREAD_PRIORITY     5
    #define FINSH_THREAD_PRIORITY       (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1)
    // <o>the stack of finsh thread <1-4096>
    //  <i>the stack of finsh thread
    //  <i>Default: 4096  (4096Byte)
    #define FINSH_THREAD_STACK_SIZE     1024

    #define FINSH_USING_HISTORY
    #define FINSH_HISTORY_LINES         5
    #define FINSH_USING_SYMTAB
    #define FINSH_USING_DESCRIPTION
    #define FINSH_CMD_SIZE 80

    // </h>
#endif
#endif

// <<< end of configuration section >>>

#define RT_USING_SERIAL
#define RT_USING_PIN
#define RT_USING_UART5
#define RT_USING_DEVICE_IPC

#endif

2.2 打印串口修改

使用串口5打印log,在debug.c /.h 中进行修改。
debug.h

#define DEBUG_UART5    5

#ifndef DEBUG
#define DEBUG   DEBUG_UART5
#endif

debug.c 添加UART5代码

void USART_Printf_Init(uint32_t baudrate)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

#if(DEBUG == DEBUG_UART1)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

#elif(DEBUG == DEBUG_UART2)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
    GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE );

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

#elif(DEBUG == DEBUG_UART3)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
#elif(DEBUG == DEBUG_UART5)

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
    GPIO_PinRemapConfig(GPIO_FullRemap_USART5, ENABLE );

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOE, &GPIO_InitStructure);

#endif

    USART_InitStructure.USART_BaudRate = baudrate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;

#if(DEBUG == DEBUG_UART1)
    USART_Init(USART1, &USART_InitStructure);
    USART_Cmd(USART1, ENABLE);

#elif(DEBUG == DEBUG_UART2)
    USART_Init(USART2, &USART_InitStructure);
    USART_Cmd(USART2, ENABLE);

#elif(DEBUG == DEBUG_UART3)
    USART_Init(USART3, &USART_InitStructure);
    USART_Cmd(USART3, ENABLE);
#elif(DEBUG == DEBUG_UART5)
    USART_Init(UART5, &USART_InitStructure);
    USART_Cmd(UART5, ENABLE);
#endif
}

__attribute__((used)) int _write(int fd, char *buf, int size)
{
    int i;

    for(i = 0; i < size; i++)
    {
#if(DEBUG == DEBUG_UART1)
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
        USART_SendData(USART1, *buf++);
#elif(DEBUG == DEBUG_UART2)
        while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
        USART_SendData(USART2, *buf++);
#elif(DEBUG == DEBUG_UART3)
        while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
        USART_SendData(USART3, *buf++);
#elif(DEBUG == DEBUG_UART5)
        while(USART_GetFlagStatus(UART5, USART_FLAG_TC) == RESET);
        USART_SendData(UART5, *buf++);
#endif
    }

    return size;
}

2.3 测试验证

创建2个线程,分别在线程中控制LED闪烁

#define THREAD_STACK_SIZE   512     // 栈大小
#define THREAD_PRIORITY     15      // 线程优先级(值越小优先级越高)
#define THREAD_TIMESLICE    15      // 时间片大小


#define LED_H4_PIN  31
#define LED_H5_PIN  32

rt_thread_t thread1;
rt_thread_t thread2;

// LED初始化
void LED1_BLINK_INIT(void)
{
    GPIO_InitTypeDef GPIO_InitStructure={0};
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_ResetBits(GPIOA,GPIO_Pin_6);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_ResetBits(GPIOA,GPIO_Pin_7);
}


static void thread1_entry(void* param)
{
    LogI("thread1_entry run\r\n");

    rt_pin_mode(LED_H4_PIN, PIN_MODE_OUTPUT);

    while(1)
    {
        rt_pin_write(LED_H4_PIN, PIN_LOW);
        rt_thread_mdelay(500);
        rt_pin_write(LED_H4_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
    }
}

static void thread2_entry(void* param)
{
    LogI("thread2_entry run\r\n");

    rt_pin_mode(LED_H5_PIN, PIN_MODE_OUTPUT);

    while(1)
    {
        rt_pin_write(LED_H5_PIN, PIN_LOW);
        rt_thread_mdelay(1000);
        rt_pin_write(LED_H5_PIN, PIN_HIGH);
        rt_thread_mdelay(1000);
    }
}


int main(void)
{
    SystemCoreClockUpdate();
    USART_Printf_Init(115200);
    LogI("CH32V307 SysClk: %dHz,ChipID: %08x\r\n", SystemCoreClock, DBGMCU_GetCHIPID());

	LED1_BLINK_INIT();

    thread1 = rt_thread_create("thread1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
    if (thread1!= RT_NULL)
        rt_thread_startup(thread1);


    thread2 = rt_thread_create("thread2", thread2_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
    if (thread1!= RT_NULL)
        rt_thread_startup(thread2);


}

编译下载到开发板中运行,可以看到2个LED在以不同的频率闪烁。打印log可以看到2个线程都运行了。
在这里插入图片描述

3. RT-Thread 启动流程

la t0, entry	// startup_ch32v30x.S  
			   // 主要完成:初始化时钟、配置中断向量表;完成全局 / 静态变量的初始化工作;初始化堆栈;
			   // 库函数的初始化;程序的跳转等内容
	int entry(void) // GCC下的startup_ch32v30x.S 会跳转到 entry()函数
		rtthread_startup();	// RT-Thread 启动代码统一入口
			rt_hw_board_init();
				_SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); // 配置系统时钟
				rt_components_board_init();	// INIT_BOARD_EXPORT()的函数,pin驱动、uart驱动等
				
			rt_application_init(void)
				rt_thread_create("main", main_thread_entry, RT_NULL,
                           RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20); // 创建Main线程
             rt_thread_idle_init(); // 创建Idle线程
             rt_system_scheduler_start(); // 启动调度器
             	main_thread_entry() // 进入main线程入口函数
             		int main(void) // 进入main函数

以上是近期使用的一些总结,后续如有需要会继续补充!

To Be Continue …

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

madao1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值