RT-Thread论坛
直播中

建立建利12

9年用户 1453经验值
擅长:可编程逻辑 嵌入式技术
私信 关注
[问答]

rt thread 按照官方视频一个字一个字敲都不行,连main函数都无法进入,为什么?

之前看过一个论坛帖子,board.c文件中的代码可以运行,但就是运行不到主函数,而是卡死在以下两个函数中,遇到同样的问题,而且gd32f103,和gd32e230系列都不行,(armgcc开源交叉编译工具链)

需求很简单,使led灯500ms闪烁。在不用rt thread的前提下是可以用到,目前为止一个例子都没跑出来,但是是对照官方视频敲都代码,官方不是也说了支持armgcc的吗?
看教程,移植时修改gd官方启动文件将bl main 改为了 bl entry


目前都还好

一直可以执行到这里,然后就不动了


在idle.c 两个函数(rt_thread_defunct_dequeue,rt_defunct_execute)里来回摇摆?有没有人帮忙排查下问题?万分感谢


回帖(1)

斯克迪亚

2025-10-11 16:08:50

根据您提供的信息,问题可能出现在RT-Thread的启动流程中。您提到在移植GD32F103和GD32E230系列时,程序卡死在`rt_thread_defunct_dequeue`和`rt_defunct_execute`这两个函数中,而无法进入主函数。以下是一些可能的原因和解决步骤:

### 1. **启动文件修改**
   - 您已经将启动文件中的`bl main`改为`bl entry`,这是正确的,因为RT-Thread的入口函数是`entry`(在`components.c`中定义)。
   - 请确认启动文件中是否正确地初始化了堆栈(Heap和Stack),并调用了`SystemInit`(如果GD32需要的话)。

### 2. **系统时钟配置**
   - GD32的时钟树配置可能与STM32不同。请确保在`board.c`中正确配置了系统时钟(例如,通过`SystemCoreClockUpdate`函数)。
   - 如果系统时钟没有正确配置,可能导致定时器、延时等函数无法正常工作,进而导致任务调度出现问题。

### 3. **RT-Thread系统初始化流程**
   - RT-Thread启动后,会依次执行以下函数:
     - `entry`:RT-Thread的入口函数。
     - `rtthread_startup`:初始化系统,包括硬件初始化、内核初始化、创建主线程等。
   - 主线程(main线程)会执行`main`函数(即您的应用程序入口)。
   - 如果系统在`rt_thread_defunct_dequeue`或`rt_defunct_execute`处卡死,通常是因为系统调度已经开始,但是主线程尚未创建或无法运行。

### 4. **堆栈大小不足**
   - 检查主线程的堆栈大小是否足够。在`main.c`中,通常有如下代码:
     ```c
     #define RT_MAIN_THREAD_STACK_SIZE 1024
     int main(void)
     {
         // 用户代码
     }
     ```
     如果堆栈大小设置过小,可能导致主线程无法正常运行。

### 5. **中断向量表配置**
   - 确保在启动文件中正确设置了中断向量表,并且在`board.c`中调用了`nvic_priority_group_set`(对于GD32)来设置中断优先级分组。
   - 确认PendSV和SysTick中断的优先级设置为最低(数值最大),以确保任务切换不会阻塞其他中断。

### 6. **系统节拍定时器(SysTick)**
   - SysTick中断必须正常工作,因为RT-Thread依赖它进行任务调度。
   - 检查`board.c`中的SysTick配置是否正确。例如:
     ```c
     void rt_hw_board_init()
     {
         // ... 其他初始化
         SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
         // ...
     }
     ```
     这里的`RT_TICK_PER_SECOND`通常为1000(即1ms一个tick)。

### 7. **钩子函数问题**
   - 如果您使用了任何钩子函数(例如调度器钩子),请检查是否有死循环或阻塞操作。

### 8. **调试方法**
   - 使用调试器(如J-Link或ST-Link)连接到GD32,设置断点,查看卡死时的调用栈。
   - 在`rtthread_startup`函数中逐步执行,观察在哪一步出现问题。
   - 特别关注`rt_system_scheduler_init`、`rt_system_timer_init`、`rt_application_init`(创建主线程)和`rt_system_scheduler_start`。

### 9. **针对GD32的特定移植**
   - 由于GD32与STM32存在一些差异(例如时钟树、外设地址等),请确保您使用的BSP(板级支持包)是针对GD32的,而不是直接使用STM32的BSP。
   - 检查`drv_common.c`和`drv_clk.c`(或类似文件)中的时钟配置是否适用于您的GD32型号。

### 10. **最小系统测试**
   - 先不创建任何线程,仅在main函数中初始化引脚并控制LED闪烁(使用`rt_thread_mdelay`延时),看是否能正常运行。如果这样也不行,说明系统初始化有问题。

### 示例代码片段
下面是一个简单的`main.c`示例,用于测试LED闪烁(假设LED引脚为PA5):
```c
#include
#include

#define LED_PIN GET_PIN(A, 5)

int main(void)
{
    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
    while (1)
    {
        rt_pin_write(LED_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }
    return RT_EOK;
}
```

### 移植步骤回顾
1. 使用正确的GD32启动文件(例如`startup_gd32f103xb.s`),并修改复位处理程序:将`bl main`改为`bl entry`。
2. 在`board.c`中实现`rt_hw_board_init`,配置系统时钟、SysTick等。
3. 确保链接脚本(.ld文件)正确设置堆和栈的大小。

希望以上建议能帮助您解决问题。如果仍有困难,请提供更多信息,例如启动文件、`board.c`以及`rtconfig.h`的配置,以便进一步分析。

根据您的描述,问题可能出现在RT-Thread的移植环节。以下是针对无法进入main()函数的完整解决方案:


关键问题原因分析



  1. 启动流程断链:从启动文件跳转到entry后,RT-Thread初始化流程未正确完成

  2. 系统时钟配置错误:GD32的时钟树与STM32存在差异(尤其是HXTAL值)

  3. 堆栈配置异常:系统堆或主线程堆栈不足导致调度失败

  4. 中断向量表未重定位:未正确设置VTOR寄存器


解决方案(GD32F103为例)


1. 启动文件修改(startup_gd32f10x_hd.s)


Reset_Handler:
    ldr   sp, =_estack      /* 设置栈指针 */
    bl    SystemInit        /* 调用时钟初始化 */
    bl    __libc_init_array /* C++支持(可选) */
    bl    entry             /* 跳转到RT-Thread入口 !重点! */
    bl    main              /* 保留此行(实际不会执行)*/

2. 时钟配置(board.c)


// 添加GD32专用时钟初始化
void SystemInit(void)
{
    rcu_deinit();
    rcu_osci_on(RCU_HXTAL);
    while(rcu_osci_stab_wait(RCU_HXTAL) == ERROR){};
    rcu_ck_sys_config(RCU_CKSYSSRC_PLL);
    rcu_pll_config(RCU_PLLSRC_HXTAL, 2, 30); // 8MHz*30/2=120MHz
    rcu_osci_on(RCU_PLL_CK);
    while(rcu_osci_stab_wait(RCU_PLL_CK) == ERROR){};
    SystemCoreClock = 120000000;
}

// 修正RT-Thread板级初始化
void rt_hw_board_init()
{
    SystemInit();
    SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); // 确保tick频率正确
    rt_hw_interrupt_enable(0);
}

3. 链接脚本修改(gd32f103.ld)


/* 增加主线程堆栈 */
_estack = ORIGIN(RAM) + LENGTH(RAM);

/* 显式指定堆大小 */
_heap_size = 0x400;   /* 1KB 堆 */
_stack_size = 0x1000; /* 4KB 栈 */

SECTIONS {
  .isr_vector : { ... }

  .text : {
    _stext = .;
    KEEP(*(.entry))  /* 确保entry函数在首位 */
    ...
  }

  /* 增加堆栈保护区 */
  .stack (NOLOAD) : {
    . = ALIGN(8);
    _sstack = .;
    . = . + _stack_size;
    . = ALIGN(8);
    _estack = .;
  } > RAM
}

4. 中断向量表重定位(board.c)


// 在rt_hw_board_init()中增加:
SCB->VTOR = (uint32_t)&__isr_vector;  // __isr_vector需和链接脚本一致

5. 主函数验证(main.c)


#include 
#include

#define LED_PIN GET_PIN(A, 1)  // 根据实际电路修改

int main(void)
{
    rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);

    while(1) {
        rt_pin_write(LED_PIN, PIN_HIGH);
        rt_thread_mdelay(300);
        rt_pin_write(LED_PIN, PIN_LOW);
        rt_thread_mdelay(300);
    }
    return 0;
}

调试技巧



  1. entry()函数中添加串口打印:
    void entry(void)
    {
       rt_kprintf("RT-Thread Entry Point!n");
       rtthread_startup();
    }

  2. 检查调度器启动状态:
    // rtthread_startup()中
    rt_system_scheduler_start(); // 在此处设置断点


常见错误排查表
































现象 可能原因 解决方法
卡在defunct函数 主线程堆栈溢出 增大RT_MAIN_THREAD_STACK_SIZE
无任何输出 时钟未配置/串口未初始化 验证SystemCoreClock值
随机复位 VTOR未设置 检查SCB->VTOR赋值
只能执行一次LED闪烁 SysTick中断未响应 确认中断优先级(PendSV最低)

最终验证步骤



  1. 编译命令:arm-none-eabi-gcc -mcpu=cortex-m3 -T gd32f103.ld ...

  2. 使用OpenOCD烧录:openocd -f gd32f1x.cfg -c "program rtthread.elf verify reset exit"



注:GD32E230需要额外注意:



  1. 使用rcu_periph_clock_enable(RCU_AF)开启复用功能

  2. 系统时钟配置使用rcu_system_clock_config()



完成以上步骤后,系统应能正常进入main函数并实现LED闪烁。如果仍有问题,建议使用J-Link的RTT Viewer进行实时调试输出。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分