1 / 48
文档名称:

threadx学习笔记.pdf

格式:pdf   大小:1,380KB   页数:48页
下载后只包含 1 个 PDF 格式的文档,没有任何的图纸或源代码,查看文件列表

如果您已付费下载过本站文档,您可以点这里二次下载

分享

预览

threadx学习笔记.pdf

上传人:mama1 2023/3/13 文件大小:1.35 MB

下载得到文件列表

threadx学习笔记.pdf

文档介绍

文档介绍:该【threadx学习笔记 】是由【mama1】上传分享,文档一共【48】页,该文档可以免费在线阅读,需要了解更多关于【threadx学习笔记 】的内容,可以使用淘豆网的站内搜索功能,选择自己适合的文档,以下文字是截取该文章内的部分文字,如需要获得完整电子版,请下载此文档到您的设备,方便您编辑和打印。:.
threadx学****笔记(一)
文件用来处理初始化过程中的汇编语言,它是面向处理器和
开发工具的。
Void_tx_initialize_low_level{
1、CPSCR|=FIQ_MODE,SETSP_fiq;
2、CPSCR|=IRQ_MODE,SETSP_irp;
3、CPSCR|=SVC_MODE,SETSP_svc;
4、设置中断向量表IRQ_TABLE;
5、设置内部TIMER线程的堆栈起始地址,堆栈大小和优先
级::tx_timer_stack_start,_tx_timer_stack_size,_tx_timer_priorit;
6、设置初始化后未使用内存地址的初始值
_tx_initialize_unused_memory;
}
负责在中断发生时对上次的运行现场进行保存,它保存中断
上下文,为了不覆盖R14_irq离得中断返回地址,TCS的返回是
通过跳到__tx_irq_processing_return地址做到的。负责中断处理
程序执行完后的处理。
Void_tx_thread_context_save{
1、把表示中断嵌套个数的变量_tx_thread_system_state++;
2、if_tx_thread_system_state>1,PUSHR0-R3,CPSR,R14inIRQ
stack,B__tx_irq_processing_return;:.
3、elseif_tx_thread_current_ptr=0判断是否有线程正在运行,
ifnot,B_tx_irq_processing_return;
4、else,PUSHContext_irqinthread’sstack,SP_thread=newSP,B
_tx_irq_processing_return;
}
由于R13和R14在不同的CPU模式下对应的是不同的物理寄
存器,所以若要得到中断前的线程堆栈指针,需要先返回到该线
程的运行模式,同时禁止中断,取值后再返回到终端模式。R14_irq
保存的是终端发生时PC值+8,R14_svc保存得失中断前线程自己
的返回地址。所以在中段上下文中,(R14_irq-4)应该存在中断
地址,而R14_svc存在R14的位置。
Void_tx_thread_context_restore{
1、_tx_thread_system_state--,if
_tx_thread_system_state>0,POPR0-R3,CPSR,R14fromIRQstack,BX
R14;
2、elseif_tx_thread_current_ptr=0?if=0
CPSR|=VC_MODE,CPSR|=TX_INT_ENABLE,跳到线程调度程序B
_tx_thread_schedule;
3、if!=0,则判断线程抢占是否禁止if
_tx_thread_preempt_disable=0?if!=0,POPContext_irqfrom
thread’sstack,BXR14;
4、if=0,_tx_timer_time_slice=new:.
value,_tx_thread_current_ptr=0,CPSR|=SVC_MODE,设置堆栈指针
为系统指针SP=SP_svc,CPSR|=TX_INT_ENABLE;
5、B_tx_thread_schedule;
}
用于从线程退回到系统态,负责保存线程的最小语境并退回
到Threadx的调度循环状态。它保存的上下文是请求上下文。
Void_tx_thread_system_return{
1、PUSHContext_request:inthread’s
????????????
stack,CPSR|=TX_INT_DISABLE;
2、
????????????
_tx_thread_current_ptr->SP=SP,CPSR|=SVC_MODE;
3、设置堆栈指针为系统指针SP=SP_svc,
????????????
_tx_thread_current_ptr=0,CPSR|=TX_INT_ENABLE;
4、B_tx_thread_schedule;
????????????
}
由于用户模式不能直接更改CPSR来关断的,所以要通过SWI
指令进入特权模式,而且特权模式和用户模式的SP对应不同的
物理寄存器,所以要在转入系统模式取得用户模式下SP,最后
再回到特权模式。
负责调度和恢复就绪的优先级最高的线程的最后语境。
Void_tx_thread_schedule{
1、while(_tx_thread_execute_ptr=0);
????????????:.
2、
????????????
CPSR|=TX_INT_DISABLE,_tx_threadx_current_ptr=_tx_t
hread_execute_ptr;
3、
????????????
_tx_thread_current_ptr->TX_run_count++,_tx_timer_ti
me_slice=_tx_thread_current_ptr->tx_time_slice;
4、If线程堆栈的中断类型=1,restore
????????????
Context_irq,elserestoreContext_request;
}
用于开中断和关中断。
Unint_tx_thread_interrupt_control(unintnew_posture){
1、R1=CPSR;
????????????
2、SWI;
????????????
3、CPSR|=RO=newposture;
????????????
4、R0=R1,R0为返回值;
????????????
}
移植该函数时,针对不同的处理器,应盖根据准热爱寄存器
CPSR的中断禁止未来设置开关中断向量,主要修改中的
TX_INT_ENABLE和用来传递的参数和结果。
负责创建每个线程的初始堆栈结构,这个初始的结构在线程
创建时会引起中断上下文返回到_tx_thread_shell_entry函数的开
头。然后这个函数调用指定线程入口函数。其中断类型设置为1,:.
表示中断上下文。
Void_tx_thread_stack_build(TXTHREAD*thread_ptr,void
(*function)(void)){
1、保证堆栈起始地址八字节对齐;
????????????
2、中断地址存入线程调用的入口地址PUSH
????????????
function_ptr;
3、R0-R12,R14的初始值都设置为0,PUSH初始值;
????????????
4、要存入堆栈的CPSR值设置为用户模式,开中断,
????????????
标志位清零,R1=USER_MODE,PUSHR1;
5、Thread_ptr->sp=newSP;
????????????
}
当处理一个低级的中断时,决定是否发生抢占,它是可选的,
大多数端口都用不到。负责处理定时中断。这两个函数只要将它
们翻译成相应ARM汇编语言就可以了。
threadx学****笔记(二)1
tx_kernel_enter();进入threadx核
tx_kernel_enter()
voidtx_kernel_enter(void)
所属文件????调用者????开关量
????启动代码????无
:.
操作系统首先从从量表直接进入该函数,在函数以前没有进行任何的硬件
及软件的初始化!该函数主要包含_tx_initialize_low_level(),
_tx_initialize_high_level(),
tx_application_define(_tx_initialize_unused_memory),
_tx_thread_schedule()。
VOID_tx_initialize_kernel_enter(VOID)
{
????/*确定编译器是否已经初始化过*/
????if(_tx_thread_system_state!=TX_INITIALIZE_ALMOST_DONE)
????{
????????/*没有初始化的话执行下面程序*/
/*设置系统状态变量来表示现正在处理过程中注意该变量在后边的中断
嵌套中会使用????*/
????????_tx_thread_system_state=TX_INITIALIZE_IN_PROGRESS;
????????/*进行一些基本硬件设置,启动程序等*/
????????_tx_initialize_low_level();
????
????????/*进行一些高级的初始化*/
????????_tx_initialize_high_level();
????}
/*设置系统状态变量来表示现正在处理过程中注意该变量在后边的中断
嵌套中会使用*/
:.
????_tx_thread_system_state=TX_INITIALIZE_IN_PROGRESS;
????/*调用初始化中提供的应用程序把第一个未使用的变量地址传送给
它*/
????tx_application_define(_tx_initialize_unused_memory);
????/*设置系统壮伟进入线程调度做准备*/
????_tx_thread_system_state=TX_INITIALIZE_IS_FINISHED;
????/*进入线程循环开始执行线程*/
????_tx_thread_schedule();
}
_tx_initialize_low_level()
voidtx_kernel_enter(void)
所属文件????调用者????开关量
????启动代码????无
该函数实现对FIQ、IRQ和SVC模式下的sp寄存器的初始化,并对定时堆
栈的基地址、大小和定时优先级变量进行初始化。
/*进行一些基本硬件设置,启动程序等*/
/*该函数在文件文件中*/
???_tx_initialize_low_level();
;/*VOID_tx_initialize_low_level(VOID)
;{
:.
????EXPORT_tx_initialize_low_level
_tx_initialize_low_level
;/*保存系统堆栈指针.*/
;/*_tx_thread_system_stack_ptr=(VOID_PTR)A7(SP);*/
;????/*设置各个模式下的sp(堆栈指针)*/
;/*WemustbeinSVCmodeatthispoint!*/
;
????LDRa2,=|Image$$ZI$$Limit|;Getendofnon-initializedRAMarea
????LDRa3,[pc,#];获得FIO堆栈地址(这里没有弄明白,有待?)
????MOVa1,#FIQ_MODE;设置FIQ_MODE
????MSRCPSR_c,a1;进入FIQ模式
????ADDa2,a2,a3;计算FIQ堆栈的开始
????BICa2,a2,#3;将a2的低两位清零确保堆栈的的开始为long对齐
????SUBa2,a2,#4;往回退一个字
????MOVsp,a2;建立FIQ堆栈指针(即FIQ模式的sp)
????MOVsl,#0;Clearsl(R10)
????MOVfp,#0;Clearfp(R11)
????LDRa3,[pc,#]????;获得IRQ(systemstacksize)
????MOVa1,#IRQ_MODE;建立IRQ模式的CPSR
????MSRCPSR_c,a1;进入IRQ模式
????ADDa2,a2,a3;计算IRQstack的开始
?????BICa2,a2,#3;将a2的低两位清零确保堆栈的的开始为long对

????SUBa2,a2,#4;往回退一个字
:.
????MOVsp,a2;建立IRQ堆栈指针
????MOVa1,#SVC_MODE;建立SVC模式的CPSR
????MSRCPSR_c,a1;进入SVC模式
????LDRa4,[pc,#];获得stack指针
????STRa2,[a4,#0];保存系统堆栈
;
;/*Savethesystemstackpointer.*/
;_tx_thread_system_stack_ptr=(VOID_PTR)(sp);
;
????LDRa2,[pc,#];获得系统堆栈指针的地址
????LDRa1,[a2,#0];获得系统堆栈指针
????ADDa1,a1,#4;增加一个long长度
;
;/*Pickupthefirstavailablememoryaddress.*/
;
;/*Allocatespaceforthetimerthread'sstack.*/
;_tx_timer_stack_start=first_available_memory;
;_tx_timer_stack_size=stack_size;
;_tx_timer_priority=0;
;
????LDRa2,[pc,#];获得定时堆栈指针地址
????LDRa4,[pc,#];获得定时堆栈大小地址
????LDRa3,[pc,#];获得实际定时堆栈大小
????STRa1,[a2,#0];将定时堆栈的基地址放在堆栈指针地址所对应的
内存中
????STRa3,[a4,#0];存储定时器堆栈大小
:.
????ADDa1,a1,a3;新的空内存地址
?????LDRa2,[pc,#];获得定时器优先级地址
?????MOVa3,#0;获得定时器线程优先级
????STRa3,[a2,#0];存储定时器线程优先级
;/*保存第一个变量内存地址.*/
;_tx_initialize_unused_memory=(VOID_PTR)SystemStack+Timer
Stack;
;
????LDRa3,[pc,#];获得没有使用的内存指针地址
????STRa1,[a3,#0];保存第一个空内存地址
;/*建立周期性的定时中断.*/
????STMDB{LR}????????????*/
;
????MOVpc,lr;Returntocaller
;}
__tx_irq_handler
所属文件????调用者????开关量
????IRQ中断????无
该函数是在定时中断后调用,该函数调用了_tx_thread_context_save函数
(包含在中),该函数又调用到__tx_irq_processing_return函数处(包
含在)
????EXPORT__tx_irq_handler
?????EXPORT__tx_irq_processing_return
__tx_irq_handler
:.
?;
?;/*调用函数保存线程上下文环境.*/
?????B_tx_thread_context_save
__tx_irq_processing_return
?;
;/*,point
of
;interrupt,
;addition,IRQinterruptsmaybere-enabled-withcertain
restrictions-
;-enabled
over
;smallcodesequenceswherelrissavedbeforeenablinginterrupts
and
;restoredafterinterruptsareagaindisabled.*/
?;
;/*Fordebugpurpose,executethetimerinterruptprocessinghere.
In
;arealsystem,somekindofstatusindicationwouldhavetobe
checked
?;beforethetimerinterrupthandlercouldbecalled.*/
?;
BL????????clearflag????????;清除中断标志位很重要(自己移植时加的,
位置是否恰当?)
?????BL_tx_timer_interrupt;定时中断处理函数
:.
?;
?;/*系统线程上下文环境恢复函数*/
?????B_tx_thread_context_restore
_tx_timer_interrupt
所属文件????调用者????开关量
????启动代码????无
该函数主要是中断后将系统时钟加1,时间切片减1。定时部分比较多,没
有完全看明白。
IMPORT_tx_timer_time_slice
????IMPORT_tx_timer_system_clock
????IMPORT_tx_timer_current_ptr
????IMPORT_tx_timer_list_start
????IMPORT_tx_timer_list_end
????IMPORT_tx_timer_expired_time_slice
????IMPORT_tx_timer_expired
????IMPORT_tx_timer_thread
???IMPORT_tx_thread_current_ptr
????IMPORT_tx_thread_time_slice
????IMPORT_tx_thread_resume
????IMPORT_tx_thread_preempt_disable
;
????????PRESERVE8
????????AREA|C$$code|,CODE,READONLY
|x$codeseg|DATA
:.
;VOID_tx_timer_interrupt(VOID)
;{
????EXPORT_tx_timer_interrupt
_tx_timer_interrupt
;
;/*Uponentrytothisroutine,itisassumedthatcontextsavehas
already
;beencalled,andthereforethecompilerscratchregistersare
available
;foruse.*/
;
;/*Incrementthesystemclock.*/
;_tx_timer_system_clock++;
;
????LDRa2,[pc,#];获得系统时钟地址
????LDRa1,[a2,#0];获得系统时钟
????ADDa1,a1,#1;将系统时钟加1
????STRa1,[a2,#0];存储新的系统时钟时间
;
;/*Testfortime-sliceexpiration.*/
;if(_tx_timer_time_slice)
;{
;
????LDRa4,[pc,#];获得链表中的定时切片数地址
????LDRa3,[a4,#0];获得定时切片数的值
:.
????CMPa3,#0;定时切片是否有效,>0有效,=0无效
????BEQ__tx_timer_no_time_slice;=0时,跳到
__tx_timer_no_time_slice处
;/*时间切片减1.*/
;_tx_timer_time_slice--;
;
????SUBa3,a3,#1;时间切片值减1
????STRa3,[a4,#0];存储新的时间切片值
;
;/*检查是否到期.*/
;if(__tx_timer_time_slice==0)
;
????CMPa3,#0;>0还是=0?
BNE__tx_timer_no_time_slice;如果>0,
;当没有定时切片时,将定时切片数标志位置1,表示链表中没有切片了。
;/*Setthetime-sliceexpiredflag.*/
;_tx_timer_expired_time_slice=TX_TRUE;
;
????LDRa4,[pc,#];获得定时切片数是否为0标志地址
???????MOVa1,#1;将标志设为1
????STRa1,[a4,#0];设立到时标志
;
;}
;
__tx_timer_no_time_slice
;
:.
;/*Testfortimerexpiration.*/
;if(*_tx_timer_current_ptr)
;{
;
LDRa2,[pc,#];获得的是_tx_timer_current_ptr的地址
????????????????????;而TIMER_DECLARETX_INTERNAL_TIMER
**_tx_timer_current_ptr
????????????????????;
????LDRa1,[a2,#0];获得当前的_tx_timer_current_ptr
LDRa3,[a1,#0];获得定时列表的入口定时切片指针
CMPa3,#0;链表中是否有定时切片存在
????BEQ__tx_timer_no_timer;不存在,调用__tx_timer_no_time将
;_tx_timer_current_ptr++
;
;/*Setexpirationflag.*/
;_tx_timer_expired=TX_TRUE;
;
????LDRa4,[pc,#];Pickupexpriationflagaddress
????MOVa3,#1;Buildexpiredvalue
????STRa3,[a4,#0];Setexpiredflag
????B__tx_timer_done;Finishedtimerprocessing
;
;}
;else
;{
__tx_timer_no_timer
:.
;
;/*Notimerexpired,incrementthetimerpointer.*/
;_tx_timer_current_ptr++;
;
????ADDa1,a1,#4;Movetonexttimer
;
;/*Checkforwrap-around.*/
;if(_tx_timer_current_ptr==_tx_timer_list_end)
;
????LDRa4,[pc,#];Pickupaddroftimerlistend
????LDRa3,[a4,#0];Pickuplistend
????CMPa1,a3;Areweatlistend?
????BNE__tx_timer_skip_wrap;No,skipwrap-aroundlogic
;
;/*Wraptobeginningoflist.*/
;_tx_timer_current_ptr=_tx_timer_list_start;
;
????LDRa4,[pc,#];Pickupaddroftimerliststart
????LDRa1,[a4,#0];Setcurrentpointertoliststart
;
__tx_timer_skip_wrap
;
????STRa1,[a2,#0];Storenewcurrenttimerpointer
;}
;
__tx_timer_done
:.
;
;
;/*Seeifanythinghasexpired.*/
;if((_tx_timer_expired_time_slice)||(_tx_timer_expired))
;{
;
????LDRa4,[pc,#];Pickupaddrofexpiredflag
????LDRa3,[a4,#0];Pickuptime-sliceexpiredflag
????CMPa3,#0;Didatime-sliceexpire?
????BNE__tx_something_expired;Ifnon-zero,time-sliceexpired
????LDRa2,[pc,#];Pickupaddrofotherexpiredflag
????LDRa1,[a2,#0];Pickuptimerexpiredflag
????CMPa1,#0;Didatimerexpire?
????BEQ__tx_timer_nothing_expired;No,nothingexpired
;
__tx_something_expired
;
;
????STRlr,[sp,#-4]!;Savethelrregisteronthestack
;
;/*Didatimerexpire?*/
;if(_tx_timer_expired)
;{
;
????LDRa2,[pc,#];Pickupaddrofexpiredflag
????LDRa1,[a2,#0];Pickuptimerexpiredflag
:.
????CMPa1,#0;Checkfortimerexpiration
????BEQ__tx_timer_dont_activate;Ifno