系统时钟节拍详解FreeRTOS源码分析-4

文章详细描述了如何在嵌入式系统中初始化SysTick定时器,设置中断,以及如何在中断服务函数中实现任务调度,强调了操作系统对寄存器操作的效率和配置参数的重要性。
摘要由CSDN通过智能技术生成

SysTick初始化

//系统节拍初始化 port.c

vPortSetupTimerInterrupt();


	void vPortSetupTimerInterrupt( void )
	{


		/* 
			1、操作系统,是针对寄存器操作---效率高
			2、首先赋值装载寄存器值 = (CPU频率/配置周期)-1
				2.1、HAL_RCC_ClockConfig() cpu频率实在硬件启动时,就已经获取了
				2.2、configTICK_RATE_HZ = 1000 是由cubemx配置而得
			3、配置控制寄存器
				3.1、开启时钟源
				3.2、使能中断
				3.3、使能systick
			4、可以参考,M4权威指南  9.5章节----systick定时器
			
			5、configTICK_RATE_HZ
				5.1、建议不要小于1ms
				5.2、建议以整数倍赋值  10ms 100ms  1000ms  便于计算管理

		*/
		portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
		portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
	}

SysTick中断服务函数

//SysTick任务调度
BaseType_t xTaskIncrementTick( void )
{
TCB_t * pxTCB;
TickType_t xItemValue;
// 返回值,表示是否进行上下文切换
BaseType_t xSwitchRequired = pdFALSE;
	//uxSchedulerSuspended 表示内核调度器是否挂起,,pdFALSE 内核没有挂起
	if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
	{
		/* tick计数增加1 */
		const TickType_t xConstTickCount = xTickCount + 1;
		xTickCount = xConstTickCount;

		//其实就是判断,tick是否溢出越界
		if( xConstTickCount == ( TickType_t ) 0U )
		{
			//如果溢出,要更新延时列表
			taskSWITCH_DELAYED_LISTS();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		/* 
			1、当前节拍大于时间片的锁定时间
			2、就说明,有任务需要进行调度了,时间片用完了
		
		
		*/
		if( xConstTickCount >= xNextTaskUnblockTime )
		{
			for( ;; )//会一直遍历整个任务延时列表,主要目的是,找到时间片最短的任务,进行切换
			{
				//1、判断任务延时列表中,是否为空,也就是说,有没有任务在等待调度
				if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
				{
					//如果没有任务等待,把时间片赋值为最大值,不再调度
					xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
					break;
				}
				else
				{
					/* 
						1、从任务延时列表中,获取第一个任务控制块
							1、延时列表,插入永远是把时间片最短的任务,放在第一个
							
						2、获取任务控制块的延时时间
					
					
					*/
					pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
					xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
					//再次判断,这个任务的时间片是否到达
					if( xConstTickCount < xItemValue )
					{
						/* 没有到达,把此任务的时间片更新为当前系统的时间片 */
						xNextTaskUnblockTime = xItemValue;
						//直接退出,不用调度
						break;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* 把任务从延时列表中移除 */
					( void ) uxListRemove( &( pxTCB->xStateListItem ) );

					/* 把任务从事件列表中移除 */
					if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
					{
						( void ) uxListRemove( &( pxTCB->xEventListItem ) );
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}

					/* 把任务添加到就绪列表中 */
					prvAddTaskToReadyList( pxTCB );

					/* 抢占式处理 */
					#if (  configUSE_PREEMPTION == 1 )
					{
						/*
							1、判断优先级是否大于当前任务
								1.1、大于则进行调度
						
						
						*/
						if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
						{
							xSwitchRequired = pdTRUE;
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}
					}
					#endif /* configUSE_PREEMPTION */
				}
			}
		}

		/* 时间片处理机制 */
		#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
		{
			//1、获取就绪列表长度
				1.1、就绪列表指的是,当前任务优先级的列表
				1.2、如果有其他任务在就绪列表中,就开始调度
			if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
			{
				xSwitchRequired = pdTRUE;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */

	}
	else//内核调度器挂起了
	{
		//挂起的tick+1
		++uxPendedTicks;

	}
	//如果是抢占模式,要开启调度
	#if ( configUSE_PREEMPTION == 1 )
	{
		if( xYieldPending != pdFALSE )
		{
			xSwitchRequired = pdTRUE;
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configUSE_PREEMPTION */
	//返回调度器状态
	return xSwitchRequired;
}

SysTick任务调度

//系统节拍中断服务函数
void xPortSysTickHandler( void )
{
	/* 
		1、配置中断屏蔽寄存器
		2、不让中断打断,systick中断服务
		3、其实就是进入临街段
	*/
	vPortRaiseBASEPRI();
	{
		/* 
			操作系统调度接口
			如果调度器返回true,触发pendSV异常
		
		*/
		if( xTaskIncrementTick() != pdFALSE )
		{
			/* 触发pendSV */
			portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
		}
	}
	//清楚可屏蔽中断,其实就打开全部中断-----》pendSV就是执行
	vPortClearBASEPRIFromISR();
}

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值