嵌入式实时操作系统的设计与开发

时钟管理

在RTOS中,时钟具有非常重要的作用,通过时钟可实现延时任务、周期性触发任务执行、任务有限等待的计时。

大多数嵌入式系统有两种时钟源,分别为实时时钟RTC(Real-Time Clock)和定时器/计数器。
实时时钟一般是靠电池供电,即使系统断电,也可以维持日期和时间。由于实时时钟独立于操作系统,因此也被称为硬件时钟,它为整个系统提供一个时间标准。
嵌入式处理器通常集成了多个定时器或计数器,实时内核需要一个定时器作为系统时钟,并由内核控制系统时钟工作。

一般而言,实时时钟是系统时钟的基准,实时内核通过读取实时时钟来初始化系统时钟,此后,二者保持同步运行,共同维持系统时钟。
因此,系统时钟只有当系统运行起来以后才有效,并且由实时内核完全控制。

定时器一般由晶体振荡器提供周期信号源,并通过程序对其计数寄存器进行设置,让其产生固定周期的脉冲,每次脉冲的产生都触发一个时钟中断,时钟中断的频率既是系统的心跳,也称为时基或Tick,Tick的大小决定了整个系统的时间粒度。

在这里插入图片描述
晶体振荡器提供周期信号源,它通过Bus总线连接到CPU核上,开发人员设定计数寄存器的初始值,随后,每一个晶体振荡器输入信号都会导致该值增加,当计数器溢出时,就产生一个输出脉冲(Pulse),输出脉冲可以用来触发CPU核上的一个中断。
输出脉冲是RTOS的硬件基础,因为它将送到中断控制器上,产生中断信号,触发时钟中断,由时钟中断服务程序维持系统时钟的正常工作。

实时内核的时间管理以系统时钟为基础,通过Tick处理程序来实现。
定时器产生中断后,RTOS将响应并执行器中断服务程序,并在中断服务程序中调用Tick处理函数,它作为实时内核的一部分,与具体的定时器/计数器无关,由系统时钟中断服务程序调用,使内核具有对不同定时器/计数器的适应性。

在内核层初始化中,重要的一步就是通过acoral_intr_attach()将时钟中断服务程序与Ticks处理程序进行绑定。
这样,每当定时器产生一个输出脉冲(Pulse),输出脉冲就向CPU发出一个时钟中断,找到内核层对应的时钟中断号,最终将执行该中断号对应的服务程序,即Ticks处理函数aCoral_Ticks_entry()。

内核时钟管理的绝大部分工作都在aCoral_Ticks_entry()进行的,如线程延迟操作time_delay_deal()、超时处理timeout_delay_deal()、与调度策略相关的操作(如时间片轮转调度)等。

如果任务采用时间片轮转调度,则需要再Ticks处理程序中对当前正在运行的任务已执行的时间进行“+1”操作。执行完该操作后,如果任务的已执行时间同任务时间片相等,则表示任务使用完一个时间片的执行时间,需要通过acoral_sched()触发重调度。

如果开发人员在线程中调用acoral_delay_thread()对线程进行延迟操作,则会让当前运行线程从运行(Running)状态切换到挂起(Suspend)状态,并将其挂载到一个等待队列“acoral_list_t waiting”,这里的等待队列也称为时间等待链,用来存放需要延迟处理的任务。
接下来每当定时器产生一个Tick,Tick处理函数aCoral_Ticks_entry()的time_delay_deal()需要对时间等待链中线程的剩余等待时间进行“减1”操作,如果某个线程的剩余等待时间被减到了0,则将该线程从等待队列中移出,挂载到就绪队列,通过acoral_sched()触发重调度。

如,开发人员用acoral_delay_thread()将线程A、B、C、D分别延迟。
通常情况下,每当定时器产生一个Tick,time_delay_deal()会对时间等待链中的每一个结点进行“减1”操作。
若时间等待链的结点数越多,时钟中断的Tick处理函数的计算开销就比较大,从而降低系统性能。

为了提高系统性能,减小计算开销,可采用差分时间等待链来描述延迟队列。
在这里插入图片描述
队列中某个结点的值是相对于前一个结点的时间差。
当采用查分时间等待链后,每当时钟中断产生一个Tick,只需对队列头部结点进行“减1”操作,当减到0时,就将其从等待链中取下,后续结点将成为新的头部,并且被激活。
等待链其它结点的值保持不变,无须对每一个结点进行“减1”操作,这样可减小计算开销。

如果有新线程要进行延迟操作,需要往差分时间等待链中插入新的结点,如线程E要延迟7Ticks。
只需要在线程B(3+2)和C(3+2+5)中插入线程E即可。再修改结点C的值即可(10-7)。

acoral_list_t time_delay_queue; //线程延时队列,调用线程delay相关函数的线程都会被加到这个队列上,等待一段具体时间后重新被唤醒。

acoral_list_t timeout_queue; //aCoral获取资源(互斥量)超时等待队列,即在timeout时间内获取即成功,否则超时失败。
void time_delay_deal()
{
	acoral_list_t *tmp,*tmp1,*head;
	acoral_thread_t *thread;
	head = &time_delay_queue; //获取时间等待链的头部
	if(acoral_list_empty(head))
		return;
	thread = list_entry(head->next,acoral_thread_t,waiting); //获取时间等待链头结点对应的TCB地址
	thread->delay--; //对时间等待链头结点对应线程delay成员的剩余等待时间
	for(tmp=head->next;tmp!=head;)
	{
		if(thread->delay > 0) //如果头结点线程delay成员大于0,则退出
			break;
		//delay=0,线程延迟结束
		tmp1 = tmp>next;
		acoral_list_del(&thread->waiting); //将该线程从时间等待链中删除
		tmp = tmp1;
		thread->state &= ~ACORAL_THREAD_STATE_DELAY; //将线程切换为就绪态	
		acoral_rdy_thread(thread); //将其挂到就绪队列上
	}
}

waiting成员主要用来将线程结构挂到相应链表队列,是一个双向链表结构。

struct acoral_list{
	struct acoral_list *next,*prev;
};

以就绪队列ready为例,当用户调用了acoral_rdy_thread或acoral_resume_thread接口时,就会将线程挂到就绪队列acoral_ready_queue上。
在这里插入图片描述

acoral_list_t policy_list;
void acoral_policy_delay_deal()
{
	acoral_list_t *tmp,*head;
	acoral_sched_policy_t *policy_ctrl;
	head = &policy_list;
	tmp = head;
	for(tmp=head->next;tmp!=head;tmp=tmp->next)
	{
		policy_ctrl = list_entry(tmp,acoral_sched_policy_list,list);
		if(policy_ctrl->delay_deal!=NULL)
			policy_ctrl->delay_deal();
	}
}
void period_policy_init(void)
{
	acoral_init_list(&period_delay_queue);
	period_policy.type=ACORAL_SCHED_POLICY_PERIOD;
	period_policy.policy_thread_init=period_policy_thread_init;
	period_policy.policy_thread_release=period_policy_thread_release;
	period_policy.delay_deal=period_delay_deal;
	period_policy.name="period";
	acoral_register_sched_policy(&period_policy);
}
typedef struct{
	unsigned int time; //线程周期,单位为ms
	void (*route)(void *args); //线程函数
	void *args; //线程函数的参数
}period_private_data_t; //周期线程私有数据块,用于保存自己的周期、函数体,以便在新周期重新挂载线程时使用。
acoral_list_t period_delay_queue; //周期线程专用延时队列,只要是周期线程,就会被挂载到这个队列上,
void period_delay_deal()
{
	acoral_list_t *tmp,*tmp1,*head;
	acoral_thread_t *thread;
	period_private_data_t * private_data;
	head = &period_delay_queue;
	if(acoral_list_empty(head))
		return;
	thread = list_entry(head->next,acoral_thread_t,waiting);
	thread->delay--;
	for(tmp=head->next;tmp!=head;){
		thread = list_entry(tmp,acoral_thread_t,waiting);
		if(thread->delay > 0)
			break;
		private->data = thread->private_data;
		tmp1 = tmp->next; //保存下一个周期延时队列上的结点
		acoral_list_del(&thread->waiting);
		tmp = tmp1;
		if(thread->state & ACORAL_THREAD_STATE_SUSPEND){
			thread->stack = (unsigned int *)((char *)thread->stack_buttom+thread->stack_size - 4);
			HAL_STACK_INIT(&thread->stack,private_data->route,period_thread_exit,private_data->args);
			acoral_rdy_thread(thread);
		}
		period_thread_delay(thread,private_data->time);
	}
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
《基于嵌入式实时操作系统的程序设计技术.pdf》是一本关于嵌入式实时操作系统(RTOS)程序设计技术的参考书。嵌入式系统是一类专门设计用于特定应用领域的计算机系统,它们通常具有实时性要求和资源受限的特点。 该书首先介绍了嵌入式系统的概念、特点和发展历程,对嵌入式实时操作系统的基本原理进行了详细解释。它涵盖了RTOS的基本概念、任务管理、调度算法、中断处理、进程通信、资源管理等关键技术。 在任务管理方面,该书详细介绍了任务的创建、删除、挂起和恢复等操作,以及任务优先级、任务同步、任务通信等相关内容。调度算法部分包括了常见的调度算法如先来先服务(FCFS)、最短作业优先(SJF)、优先级调度、轮转调度等,并对每种算法的适用场景和实现方式进行了详细阐述。 该书还针对中断处理机制进行了深入讲解,包括中断优先级、中断嵌套和中断服务程序设计等方面的内容。进程通信章节介绍了进程间的消息传递、信号量、互斥锁和邮箱等通信机制。 最后,资源管理方面主要介绍了内存管理、定时器管理和硬件设备驱动等相关技术。书中还提供了丰富的代码示例和实践案例,帮助读者更好地理解和应用所学知识。 总的来说,《基于嵌入式实时操作系统的程序设计技术.pdf》是一本系统全面介绍嵌入式实时操作系统程序设计技术的权威参考书,适合嵌入式系统开发人员和学习者阅读和参考。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

饼干饼干圆又圆

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

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

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

打赏作者

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

抵扣说明:

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

余额充值