threadx学习笔记文档格式.docx
《threadx学习笔记文档格式.docx》由会员分享,可在线阅读,更多相关《threadx学习笔记文档格式.docx(28页珍藏版)》请在冰豆网上搜索。
=0,如此判断线程抢占是否禁止if_tx_thread_preempt_disable=0?
if!
=0,POPContext_irqfromthread’sstack,BXR14;
4、if=0,_tx_timer_time_slice=newvalue,_tx_thread_current_ptr=0,CPSR|=SVC_MODE,设置堆栈指针为系统指针SP=SP_svc,CPSR|=TX_INT_ENABLE;
5、B_tx_thread_schedule;
Tx_tsr.s用于从线程退回到系统态,负责保存线程的最小语境并退回到Threadx的调度循环状态。
它保存的上下文是请求上下文。
Void_tx_thread_system_return{
1、
PUSHContext_request:
inthread’sstack,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,最后再回到特权模式。
TX_TS.S负责调度和恢复就绪的优先级最高的线程的最后语境。
Void_tx_thread_schedule{
while(_tx_thread_execute_ptr=0);
CPSR|=TX_INT_DISABLE,_tx_threadx_current_ptr=_tx_thread_execute_ptr;
TX_run_count++,_tx_timer_time_slice=_tx_thread_current_ptr->
tx_time_slice;
If线程堆栈的中断类型=1,restoreContext_irq,elserestoreContext_request;
Tx_tic.s用于开中断和关中断。
Unint_tx_thread_interrupt_control(unintnew_posture){
R1=CPSR;
SWI;
CPSR|=RO=newposture;
R0=R1,R0为返回值;
移植该函数时,针对不同的处理器,应盖根据准热爱存放器CPSR的中断禁止未来设置开关中断向量,主要修改TX_PORT.H中的TX_INT_ENABLE和TX_INT_DISABLE.R0用来传递的参数和结果。
Tx_tsb.s负责创建每个线程的初始堆栈结构,这个初始的结构在线程创建时会引起中断上下文返回到_tx_thread_shell_entry函数的开头。
然后这个函数调用指定线程入口函数。
其中断类型设置为1,表示中断上下文。
Void_tx_thread_stack_build(TXTHREAD*thread_ptr,void(*function)(void)){
保证堆栈起始地址八字节对齐;
中断地址存入线程调用的入口地址PUSHfunction_ptr;
R0-R12,R14的初始值都设置为0,PUSH初始值;
要存入堆栈的CPSR值设置为用户模式,开中断,标志位清零,R1=USER_MODE,PUSHR1;
5、
Thread_ptr->
sp=newSP;
当处理一个低级的中断时,tx_tpc.s决定是否发生抢占,它是可选的,大多数端口都用不到。
TX_TIMIN.S负责处理定时中断。
这两个函数只要将它们翻译成相应ARM汇编语言就可以了。
threadx学习笔记〔二〕-1
tx_kernel_enter();
进入threadx核
tx_kernel_enter()
voidtx_kernel_enter(void)
所属文件
调用者
开关量
demo.C
启动代码
无
操作系统首先从从量表直接进入该函数,在函数以前没有进展任何的硬件与软件的初始化!
该函数主要包含_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_application_define(_tx_initialize_unused_memory);
/*设置系统壮伟进入线程调度做准备*/
_tx_thread_system_state=TX_INITIALIZE_IS_FINISHED;
/*进入线程循环开始执行线程*/
_tx_thread_schedule();
_tx_initialize_low_level()
tx_till.s
该函数实现对FIQ、IRQ和SVC模式下的sp存放器的初始化,并对定时堆栈的基地址、大小和定时优先级变量进展初始化。
/*该函数在文件tx_ill.s文件中*/
;
/*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,#FIQ_STACK_SIZE8];
获得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,#SYS_STACK_SIZE8]
获得IRQ(systemstacksize)
MOVa1,#IRQ_MODE;
建立IRQ模式的CPSR
进入IRQ模式
计算IRQstack的开始
建立IRQ堆栈指针
MOVa1,#SVC_MODE;
建立SVC模式的CPSR
进入SVC模式
LDRa4,[pc,#SYS_STACK_PTR8];
获得stack指针
STRa2,[a4,#0];
保存系统堆栈
/*Savethesystemstackpointer.*/
_tx_thread_system_stack_ptr=(VOID_PTR)(sp);
LDRa2,[pc,#SYS_STACK_PTR8];
获得系统堆栈指针的地址
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,#TIMER_STACK8];
获得定时堆栈指针地址
LDRa4,[pc,#TIMER_STACK_SIZE8];
获得定时堆栈大小地址
LDRa3,[pc,#TIM_STACK_SIZE8];
获得实际定时堆栈大小
STRa1,[a2,#0];
将定时堆栈的基地址放在堆栈指针地址所对应的内存中
STRa3,[a4,#0];
存储定时器堆栈大小
ADDa1,a1,a3;
新的空内存地址
LDRa2,[pc,#TIMER_PRIORITY8];
获得定时器优先级地址
MOVa3,#0;
获得定时器线程优先级
STRa3,[a2,#0];
存储定时器线程优先级
/*保存第一个变量内存地址.*/
_tx_initialize_unused_memory=(VOID_PTR)SystemStack+TimerStack;
LDRa3,[pc,#UNUSED_MEMORY8];
获得没有使用的内存指针地址
STRa1,[a3,#0];
保存第一个空内存地址
/*建立周期性的定时中断.*/
STMDB{LR}
//让lr入栈,保护lr
BL
TargetInit
//TargetInit〔〕为C语言编写的中断定时函数
LDMIA{lr}
//让lr出栈
在这里加上ARM定时器已实现周期性的中断
/*Done,returntocaller.*/
MOVpc,lr;
Returntocaller
__tx_irq_handler
IRQ中断
该函数是在定时中断后调用,该函数调用了_tx_thread_context_save函数〔包含在tx_tcs.s中〕,该函数又调用到__tx_irq_processing_return函数处〔包含在tx_till.s〕
EXPORT__tx_irq_handler
EXPORT__tx_irq_processing_return
/*调用函数保存线程上下文环境.*/
B_tx_thread_context_save
__tx_irq_processing_return
/*AtthispointexecutionisstillintheIRQmode.TheCPSR,pointof
interrupt,andallCscratchregistersareavailableforuse.In
addition,IRQinterruptsmaybere-enabled-withcertainrestrictions-
ifnestedIRQinterruptsaredesired.Interruptsmaybere-enabledover
smallcodesequenceswherelrissavedbeforeenablinginterruptsand
restoredafterinterruptsareagaindisabled.*/
/*Fordebugpurpose,executethetimerinterruptprocessinghere.In
arealsystem,somekindofstatusindicationwouldhavetobechecked
beforethetimerinterrupthandlercouldbecalled.*/
clearflag
去除中断标志位很重要〔自己移植时加的,位置是否恰当?
BL_tx_timer_interrupt;
定时中断处理函数
/*系统线程上下文环境恢复函数*/
B_tx_thread_context_restore
_tx_timer_interrupt
tx_timin.s
该函数主要是中断后将系统时钟加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
/*Uponentrytothisroutine,itisassumedthatcontextsavehasalready
beencalled,andthereforethepilerscratchregistersareavailable
foruse.*/
/*Incrementthesystemclock.*/
_tx_timer_system_clock++;
LDRa2,[pc,#SYSTEM_CLOCK8];
获得系统时钟地址
获得系统时钟
ADDa1,a1,#1;
将系统时钟加1
存储新的系统时钟时间
/*Testfortime-sliceexpiration.*/
if(_tx_timer_time_slice)
{
LDRa4,[pc,#TIME_SLICE8];
获得链表中的定时切片数地址
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
存储新的时间切片值
/*检查是否到期.*/
if(__tx_timer_time_slice==0)
>
0还是=0?
BNE__tx_timer_no_time_slice;
如果>
0,
当没有定时切片时,将定时切片数标志位置1,表示链表中没有切片了。
/*Setthetime-sliceexpiredflag.*/
_tx_timer_expired_time_slice=TX_TRUE;
LDRa4,[pc,#EXPIRED_TIME_SLICE8];
获得定时切片数是否为0标志地址
MOVa1,#1;
将标志设为1
STRa1,[a4,#0];
设立到时标志
}
__tx_timer_no_time_slice
/*Testfortimerexpiration.*/
if(*_tx_timer_current_pt