GD32F30x 移植 FreeRTOS 之 SysTick 系统时钟的配置说明

书接上回

示例工程代码库地址如下:

1. 错误理解

博主以 GD32F30x 固件库中的 Template 工程作为示例基础工程,
进行 FreeRTOS 移植,其 main 函数部分实现如下:

int main(void)
{
    /* configure systick */
    systick_config();
  
    /* print out the clock frequency of system, AHB, APB1 and APB2 */
    printf("\r\nCK_SYS is %d", rcu_clock_freq_get(CK_SYS));
    printf("\r\nCK_AHB is %d", rcu_clock_freq_get(CK_AHB));
    printf("\r\nCK_APB1 is %d", rcu_clock_freq_get(CK_APB1));
    printf("\r\nCK_APB2 is %d", rcu_clock_freq_get(CK_APB2));
}

移植过程中,没有去深究 FreeRTOS 内核源码,移植后的 main 函数实现如下:

int main(void)
{  
	/* configure systick */
    systick_config();
    delay_init();
    uart_printf_init();

    OS_Init();
    system_init();
    OS_StartScheduler();
    while(1) { OLOGI("!"); }//OS_StartScheduler 调用失败将返回,添加死循环更容易排查问题
}

想当然的以为 FreeRTOS 的 SysTick 系统滴答时钟配置是调用 systick_config 函数实现的,
由于其内部配置的滴答频率和我配置的 FreeRTOS 系统滴答频率一致,暂时没有出问题。

其定义实现分别如下:

void systick_config(void)
{
    /* setup systick timer for 1000Hz interrupts */
    if (SysTick_Config(SystemCoreClock / 1000U)){
        /* capture error */
        while (1){
        }
    }
    /* configure the systick handler priority */
    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}

void SysTick_Handler(void)
{
	xPortSysTickHandler();
	
    delay_decrement();
}

FreeRTOSConfig.h

#define configCPU_CLOCK_HZ				( ( unsigned long ) SystemCoreClock )	
#define configTICK_RATE_HZ				( ( TickType_t ) 1000 )

当博主想使用 Systick 来做 us 级延时时,问题便暴露了。

systick_config 修改为 1000000 Hz 中断频率:

void systick_config(void)
{
    /* setup systick timer for 1000Hz interrupts */
    if (SysTick_Config(SystemCoreClock / 1000000U)){
        /* capture error */
        while (1){
        }
    }
    /* configure the systick handler priority */
    NVIC_SetPriority(SysTick_IRQn, 0x00U);
}

gd32f30x_it.c 中 SysTick_Handler 实现修改如下:

void SysTick_Handler(void)
{
	static uint32_t s_ticks = 0;
	if(1000 == (++s_ticks)){
		s_ticks = 0;
		xPortSysTickHandler();
	}
	
    delay_decrement();
}

这样就天真的认为 xPortSysTickHandler 的调用频率仍旧是 configTICK_RATE_HZ = 1000Hz
根据官网说明,configTICK_RATE_HZ 不能定义太大,否则系统调度将占用大量时间,降低效率。

可现实往往事与愿违,运行发现 FreeRTOS 延时函数的延时时间不正常了,系统调度也出现了问题

其原因调试了很久,才发现原来 SysTick 中断频率仍旧是 1000Hz,
导致 xPortSysTickHandler 的调用频率经上面处理变成了 1Hz

经过这么一折腾,就有了下面的正确理解。

2. 正确理解

FreeRTOS 的调度函数 vTaskStartScheduler 部分实现如下:

void vTaskStartScheduler( void )
{
	/* 省略部分代码 */
	
	//创建空闲任务
    /* The Idle task is being created using dynamically allocated RAM. */
    xReturn = xTaskCreate( prvIdleTask,
                                   configIDLE_TASK_NAME,
                                   configMINIMAL_STACK_SIZE,
                                   ( void * ) NULL,
                                   portPRIVILEGE_BIT,  /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                   &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
        }

    /* 省略部分代码 */

	//跟 MCU 相关的任务调度启动函数
    /* Setting up the timer tick is hardware specific and thus in the
     * portable interface. */
    if( xPortStartScheduler() != pdFALSE )
    {
        /* Should not reach here as if the scheduler is running the
         * function will not return. */
    }
    else
    {
        /* Should only reach here if a task calls xTaskEndScheduler(). */
    }

	/* 省略部分代码 */
}

xPortStartScheduler 函数,其部分实现如下:

BaseType_t xPortStartScheduler( void )
{
	/* 省略部分代码 */
	
	/* 此处设置了 SysTick 中断的优先级为 portNVIC_SYSTICK_PRI 
	* 而 portNVIC_SYSTICK_PRI = (((uint32_t)configKERNEL_INTERRUPT_PRIORITY) << 24UL)
	*/
    /* Make PendSV and SysTick the lowest priority interrupts. */
    portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
    portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;

    /* Start the timer that generates the tick ISR.  Interrupts are disabled
     * here already. */
    vPortSetupTimerInterrupt();//里面再次对 SysTick 进行了相关配置

	/* 省略部分代码 */	
	
    /* Start the first task. */
    prvStartFirstTask();

    /* Should not get here! */
    return 0;
}

vPortSetupTimerInterrupt 函数实现如下:

__weak void vPortSetupTimerInterrupt( void )
    {
        /* Calculate the constants required to configure the tick interrupt. */
        #if ( configUSE_TICKLESS_IDLE == 1 )
            {
                ulTimerCountsForOneTick = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ );
                xMaximumPossibleSuppressedTicks = portMAX_24_BIT_NUMBER / ulTimerCountsForOneTick;
                ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / ( configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ );
            }
        #endif /* configUSE_TICKLESS_IDLE */

        /* Stop and clear the SysTick. */
        portNVIC_SYSTICK_CTRL_REG = 0UL;
        portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;

        /* Configure SysTick to interrupt at the requested rate. */
        //设置 SysTick 的计数值,根据 FreeRTOSConfig.h 中定义的 configTICK_RATE_HZ
        portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
        //启用 SysTick IRQ 和 SysTick 定时器
        portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
    }

至此,SysTick 的计数值,中断优先级,中断的使能以及定时器的启用,都进行了配置。
因为 vTaskStartScheduler 函数内部对 SysTick 进行了初始化的配置,
所以一开始的 main 函数中调用 systick_config 其实是不需要的,
就算调用最终也会被 vTaskStartScheduler 中的配置覆盖,
而这也是导致前面错误理解中遇到的问题的根本原因了

3. 总结

FreeRTOS 内核源码还是要多读一读,才能知其根本。
若有解说不当之处,欢迎指正,以免误己误人。

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: GD32F4xx是一款基于ARM Cortex-M4内核的微控制器,而FreeRTOS是一款适用于微处理器的实时操作系统GD32F4xx移植FreeRTOS需要以下步骤: 第一步,选择合适的FreeRTOS版本。需要选择与GD32F4xx芯片相兼容的版本。 第二步,将FreeRTOS的源代码移植GD32F4xx芯片上。这包括将源代码编译为GD32F4xx所支持的格式,并将内存分配到合适的RAM和ROM。 第三步,对FreeRTOS进行配置。可以根据系统需要配置不同的内存分配方式、任务堆栈大小、时间片、任务优先级等参数。 第四步,编写系统初始化代码。在初始化代码中,需要对系统时钟、外设、GPIO等进行初始化,以便正常运行FreeRTOS系统。 第五步,编写任务。在任务中,需要定义任务的执行程序、任务优先级、任务堆栈大小等。同时,可以使用FreeRTOS提供的其他功能,如数据队列、信号量等实现任务与任务之间的通信。 最后要进行的是验证阶段。为了验证系统能够正常运行,需要进行测试和调试。此时,可以使用FreeRTOS提供的调试工具进行调试。 在将FreeRTOS移植GD32F4xx芯片中后,系统可以获得更好的性能和可靠性,提高系统的实时性和可拓展性。移植FreeRTOSGD32F4xx芯片中需要一定的技能水平和经验,但如果正确地进行了操作,将会使系统更加健壮和稳定。 ### 回答2: 首先需要了解GD32F4xx的硬件架构和FreeRTOS的基本概念。GD32F4xx是一种基于ARM Cortex-M4内核的微控制器,具有丰富的外设和功能。FreeRTOS是一个开源的实时操作系统,可以运行在不同的芯片架构上。 移植FreeRTOSGD32F4xx上,需要完成以下步骤: 1. 选择适当的FreeRTOS版本,下载相关的源代码和文档。 2. 配置环境,安装相关软件。需要安装ARM GCC编译器和调试工具,例如OpenOCD。 3. 编译FreeRTOS源代码,生成适用于GD32F4xx的可执行文件。 4. 在GD32F4xx上搭建FreeRTOS环境。在GD32F4xx的开发板上,连接相应的调试接口,并将编译好的可执行文件烧录到芯片中。 5. 编写应用程序代码,并集成到FreeRTOS中。在GD32F4xx上运行FreeRTOS应用程序,包括启动FreeRTOS内核、创建任务、控制任务挂起和挂起等。 6. 调试和测试。通过调试工具,对应用程序进行调试和性能测试,确保FreeRTOSGD32F4xx上正常运行。 需要注意的是,在移植过程中还需要根据GD32F4xx的具体硬件架构和外设进行适当的设置和配置,以确保FreeRTOS可以正确地访问这些硬件和外设。这需要进行一定的代码修改和调试工作。同时,还需要对内存和中断管理进行详细的分析和调试,以保证系统的实时性和稳定性。 总之,移植FreeRTOSGD32F4xx上是一个复杂而繁琐的过程,需要仔细分析和调试。但一旦成功移植,就可以为GD32F4xx提供一个高效、可靠且易于开发的实时操作系统,为各种应用提供更高效的支持。 ### 回答3: 对于想要将freertos移植gd32f4xx上的开发者,需要注意如下几点: 1. 首先要确定gd32f4xx的硬件平台,并且要了解它的处理器架构和外设接口。这包括处理器的位数、SRAM和Flash存储器、时钟中断控制器以及外设接口,如串口、SPI,I2C等。 2. 在freertos移植过程中,需要进行一些必要的修改,以适配到gd32f4xx的硬件平台。具体来说,需要修改端口文件的寄存器定义、中断处理函数时钟初始化和任务切换等方面。 3. 在移植过程中还需要完成调度器、任务、任务通信等功能的移植。需要按照要求进行修改和编写,以确保能够运行。 4. 对于初学者来说,移植freertos是一个比较复杂的过程,在移植之前,建议先了解freertosgd32f4xx的基本知识,并阅读官方文档,以便更好地理解和完成移植。 总之,在进行gd32f4xx移植freertos的时候,需要认真学习编写,保证效率和运行质量,充分测试和验证,降低出现异常和bug的概率。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值