硬汉嵌入式论坛

 找回密码
 立即注册
查看: 989|回复: 8
收起左侧

[ThreadX全家桶] [threadx] cpu利用率例程的问题

[复制链接]

2

主题

9

回帖

15

积分

新手上路

积分
15
发表于 2024-7-12 14:43:40 | 显示全部楼层 |阅读模式
刚开始学习,请教一下大佬们,谢谢。
请问一下,在硬汉哥提供的V7-3002_Threadx Kernel Template例程里,cpu是怎么从AppTaskIDLE任务切换回AppTaskStart任务的?或者说是在哪个中断悬起pendsv?

在main()关闭了systick中断。



AppTaskIDLE任务是死循环,没有信号量、延时的操作去悬起pendsv,时间片也是关闭的


回复

使用道具 举报

2

主题

9

回帖

15

积分

新手上路

积分
15
 楼主| 发表于 2024-7-12 20:04:08 | 显示全部楼层
补充上面的图 捕获.PNG VIAH}S9$K~I2@GL]1H0NBGL.png
回复

使用道具 举报

0

主题

18

回帖

18

积分

新手上路

积分
18
QQ
发表于 2024-7-13 08:12:15 | 显示全部楼层
tx_kernel_enter(); -> _tx_initialize_kernel_enter() ->  _tx_thread_schedule() -> CPSIE   i
开启调度器的时候在 tx_thread_schedule.s 中使能了中断
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115896
QQ
发表于 2024-7-13 09:12:39 | 显示全部楼层
这个OSStatInit是最关键的。

[C] 纯文本查看 复制代码
*
*********************************************************************************************************
* 函 数 名: AppTaskStatistic
* 功能说明: 统计任务,用于实现 CPU 利用率的统计。为了测试更加准确,可以开启注释调用的全局中断开关
* 形 参: thread_input 创建该任务时传递的形参
* 返 回 值: 无
* 优 先 级: 30
*********************************************************************************************************
*/
void OSStatInit (void)
{
OSStatRdy = FALSE;
 tx_thread_sleep(2u); /* 时钟同步 */
 //__disable_irq();
 OSIdleCtr = 0uL; /* 清空闲计数 */
//__enable_irq();
 tx_thread_sleep(100); /* 统计 100ms 内,最大空闲计数 */
 //__disable_irq();
 OSIdleCtrMax = OSIdleCtr; /* 保存最大空闲计数 *
 OSStatRdy = TRUE;
//__enable_irq();
}
static void AppTaskStat(ULONG thread_input)
{
(void)thread_input;
 while (OSStatRdy == FALSE)
{
 tx_thread_sleep(200); /* 等待统计任务就绪 */
 }
 OSIdleCtrMax /= 100uL;
 if (OSIdleCtrMax == 0uL)
{
 OSCPUUsage = 0u;
 }
 //__disable_irq();
 OSIdleCtr = OSIdleCtrMax * 100uL; /* 设置初始 CPU 利用率 0% */
//__enable_irq();
 for (;;)
{
 // __disable_irq();
 OSIdleCtrRun = OSIdleCtr; /* 获得 100ms 内空闲计数 */
 OSIdleCtr = 0uL; /* 复位空闲计数 */
 // __enable_irq(); /* 计算 100ms 内的 CPU 利用率 */
 OSCPUUsage = (100uL - (float)OSIdleCtrRun / OSIdleCtrMax);
 tx_thread_sleep(100); /* 每 100ms 统计一次 */
 }


进入到启动任务后,其它任何任务都不要创建,先创建一个统计任务,不让执行。

启动任务延迟 100ms,延迟的这 100ms 时间基本都是空闲任务在执行,在空闲任务里面做 32 变量加 1 计算。我们就以这 100ms,变量计数的最大值作为 CPU 利用率的分母。

然后开启统计任务的执行,每 100ms 执行一次,统计即可。空闲任务此时的计数值作为分子。通过这种方式就实现了 CPU 利用率的统计。
回复

使用道具 举报

2

主题

9

回帖

15

积分

新手上路

积分
15
 楼主| 发表于 2024-7-13 10:22:29 | 显示全部楼层
eric2013 发表于 2024-7-13 09:12
这个OSStatInit是最关键的。

[C] 纯文本查看 复制代码
*
[/quote]

[mw_shl_code=c,true]/*
*********************************************************************************************************
*	函 数 名: AppTaskIDLE
*	功能说明: 空闲任务
*	形    参: thread_input 创建该任务时传递的形参
*	返 回 值: 无
	优 先 级: 31
*********************************************************************************************************
*/
static void AppTaskIDLE(ULONG thread_input)
{	
  TX_INTERRUPT_SAVE_AREA

  (void)thread_input;
	
  while(1)
  {
	   TX_DISABLE
       OSIdleCtr++;
	   TX_RESTORE
  }			  	 	       											   
}
回复

使用道具 举报

2

主题

9

回帖

15

积分

新手上路

积分
15
 楼主| 发表于 2024-7-13 10:32:24 | 显示全部楼层
eric2013 发表于 2024-7-13 09:12
这个OSStatInit是最关键的。

[C] 纯文本查看 复制代码
*
[/quote]

[mw_shl_code=c,true]/*
*********************************************************************************************************
*	函 数 名: AppTaskIDLE
*	功能说明: 空闲任务
*	形    参: thread_input 创建该任务时传递的形参
*	返 回 值: 无
	优 先 级: 31
*********************************************************************************************************
*/
static void AppTaskIDLE(ULONG thread_input)
{	
  TX_INTERRUPT_SAVE_AREA

  (void)thread_input;
	
  while(1)
  {
	   TX_DISABLE
       OSIdleCtr++;
	   TX_RESTORE
  }			  	 	       											   
}

谢谢回复哈,是的,这个实现流程我理解了。但是有一点不太理解,麻烦再解答一下。就是,空闲任务是一个死循环,没有主动挂起或者堵塞,那么空闲任务是怎么被启动任务抢占的?是在哪个中断悬起了pendsv吗,毕竟悬起pendsv才能做任务切换。
回复

使用道具 举报

2

主题

9

回帖

15

积分

新手上路

积分
15
 楼主| 发表于 2024-7-13 10:47:57 | 显示全部楼层
SunHaoArm 发表于 2024-7-13 08:12
tx_kernel_enter(); -> _tx_initialize_kernel_enter() ->  _tx_thread_schedule() -> CPSIE   i
开启调度 ...

我的理解是,CPSIE   i只是屏蔽掉中断,而并不是不让中断源产生中断;但HAL_SuspendTick()就是让systick到达计数值了也不产生中断。
回复

使用道具 举报

0

主题

18

回帖

18

积分

新手上路

积分
18
QQ
发表于 2024-7-13 13:02:16 | 显示全部楼层
tx_kernel_enter() -> _tx_initialize_kernel_enter() ->  _tx_initialize_low_level() 好像是这个地方重新配置了 SysTick,恢复了 SysTick_Handler 中断
回复

使用道具 举报

2

主题

9

回帖

15

积分

新手上路

积分
15
 楼主| 发表于 2024-7-14 18:19:08 | 显示全部楼层
SunHaoArm 发表于 2024-7-13 13:02
tx_kernel_enter() -> _tx_initialize_kernel_enter() ->  _tx_initialize_low_level() 好像是这个地方重新 ...

嗯嗯,是这样的。正是因为这里的SYSTICK中断使能,才能让tx_timer到时间后执行去_tx_timer_expiration_process,而这个函数会让调度器去切换到_tx_timer_thread_entry任务,并且_tx_timer_thread_entry任务结束后就会主动挂起。所以调度器才有机会去切换其它任务。感谢答疑!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-5-25 16:21 , Processed in 0.272975 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表