打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
threadx学习笔记(二)
tx_kernel_enter();进入threadx核
tx_kernel_enter()
void tx_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_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()
void tx_kernel_enter(void)

所属文件    调用者    开关量
tx_till.s    启动代码    无
该函数实现对FIQ、IRQ和SVC模式下的sp寄存器的初始化,并对定时堆栈的基地址、大小和定时优先级变量进行初始化。
/* 进行一些基本硬件设置,启动程序等 */
/*该函数在文件tx_ill.s文件中*/
   _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(堆栈指针)*/
; /* We must be in SVC mode at this point! */
;
    LDR a2, =|Image$$ZI$$Limit| ; Get end of non-initialized RAM area
    LDR a3, [pc, #FIQ_STACK_SIZE-.-8] ; 获得FIO堆栈地址(这里没有弄明白,有待?)
    MOV a1, #FIQ_MODE ; 设置FIQ_MODE
    MSR CPSR_c, a1 ; 进入FIQ模式
    ADD a2, a2, a3 ;计算FIQ堆栈的开始
    BIC a2, a2, #3 ; 将a2的低两位清零确保堆栈的的开始为long对齐
    SUB a2, a2, #4 ; 往回退一个字
    MOV sp, a2 ; 建立FIQ 堆栈指针(即FIQ模式的sp)
    MOV sl, #0 ; Clear sl(R10)
    MOV fp, #0 ; Clear fp(R11)
    LDR a3, [pc, #SYS_STACK_SIZE-.-8]     ;获得 IRQ (system stack size)
    MOV a1, #IRQ_MODE ; 建立IRQ模式的 CPSR
    MSR CPSR_c, a1 ; 进入IRQ模式
    ADD a2, a2, a3 ; 计算IRQ stack的开始
     BIC a2, a2, #3 ; 将a2的低两位清零确保堆栈的的开始为long对齐
    SUB a2, a2, #4 ; 往回退一个字
    MOV sp, a2 ; 建立 IRQ 堆栈指针
    MOV a1, #SVC_MODE ; 建立SVC模式的CPSR
    MSR CPSR_c, a1 ; 进入 SVC模式
    LDR a4, [pc, #SYS_STACK_PTR-.-8] ; 获得stack 指针
    STR a2, [a4, #0] ; 保存系统堆栈
;
; /* Save the system stack pointer. */
; _tx_thread_system_stack_ptr = (VOID_PTR) (sp);
;
    LDR a2, [pc, #SYS_STACK_PTR-.-8] ; 获得系统堆栈指针的地址
    LDR a1, [a2, #0] ; 获得系统堆栈指针
    ADD a1, a1, #4 ; 增加一个long长度
;
; /* Pickup the first available memory address. */
;
; /* Allocate space for the timer thread's stack. */
; _tx_timer_stack_start = first_available_memory;
; _tx_timer_stack_size = stack_size;
; _tx_timer_priority = 0;
;
    LDR a2, [pc, #TIMER_STACK-.-8] ; 获得定时堆栈指针地址
    LDR a4, [pc, #TIMER_STACK_SIZE-.-8] ; 获得定时堆栈大小地址
    LDR a3, [pc, #TIM_STACK_SIZE-.-8] ; 获得实际定时堆栈大小
    STR a1, [a2, #0] ;将定时堆栈的基地址放在堆栈指针地址所对应的内存中
    STR a3, [a4, #0] ; 存储定时器堆栈大小
    ADD a1, a1, a3 ; 新的空内存地址
     LDR a2, [pc, #TIMER_PRIORITY-.-8] ; 获得定时器优先级地址
     MOV a3, #0 ; 获得定时器线程优先级
    STR a3, [a2, #0] ; 存储定时器线程优先级
; /*保存第一个变量内存地址. */
; _tx_initialize_unused_memory = (VOID_PTR) System Stack + Timer Stack;
;
    LDR a3, [pc, #UNUSED_MEMORY-.-8] ;获得没有使用的内存指针地址
    STR a1, [a3, #0] ; 保存第一个空内存地址
; /* 建立周期性的定时中断. */
    STMDB {LR}            //让lr入栈,保护lr

    BL    TargetInit                //TargetInit()为C语言编写的中断定时函数

    LDMIA {lr}            //让lr出栈

    在这里加上ARM定时器已实现周期性的中断
; /* Done, return to caller. */
;
    MOV pc, lr ; Return to caller
;}

__tx_irq_handler
所属文件    调用者    开关量
tx_till.s     IRQ中断    无
该函数是在定时中断后调用,该函数调用了_tx_thread_context_save函数(包含在tx_tcs.s中),该函数又调用到__tx_irq_processing_return函数处(包含在tx_till.s)

    EXPORT __tx_irq_handler
     EXPORT __tx_irq_processing_return
__tx_irq_handler

 ;
 ; /* 调用函数保存线程上下文环境. */
     B _tx_thread_context_save

__tx_irq_processing_return
 ;
; /* At this point execution is still in the IRQ mode. The CPSR, point of
; interrupt, and all C scratch registers are available for use. In
; addition, IRQ interrupts may be re-enabled - with certain restrictions -
; if nested IRQ interrupts are desired. Interrupts may be re-enabled over
; small code sequences where lr is saved before enabling interrupts and
; restored after interrupts are again disabled. */

 ;
; /* For debug purpose, execute the timer interrupt processing here. In
; a real system, some kind of status indication would have to be checked
 ; before the timer interrupt handler could be called. */

 ;
BL         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
_tx_timer_interrupt
;
; /* Upon entry to this routine, it is assumed that context save has already
; been called, and therefore the compiler scratch registers are available
; for use. */

;
; /* Increment the system clock. */
; _tx_timer_system_clock++;
;
    LDR a2, [pc, #SYSTEM_CLOCK-.-8] ; 获得系统时钟地址
    LDR a1, [a2, #0] ; 获得系统时钟
    ADD a1, a1, #1 ; 将系统时钟加1
    STR a1, [a2, #0] ; 存储新的系统时钟时间
;
; /* Test for time-slice expiration. */
; if (_tx_timer_time_slice)
; {
;
    LDR a4, [pc, #TIME_SLICE-.-8] ; 获得链表中的定时切片数地址
    LDR a3, [a4, #0] ; 获得定时切片数的值
    CMP a3, #0 ; 定时切片是否有效,>0有效,=0无效
    BEQ __tx_timer_no_time_slice ; =0时,跳到__tx_timer_no_time_slice处
; /* 时间切片减1. */
; _tx_timer_time_slice--;
;
    SUB a3, a3, #1 ; 时间切片值减1
    STR a3, [a4, #0] ; 存储新的时间切片值
;
; /* 检查是否到期. */
; if (__tx_timer_time_slice == 0)
;
    CMP a3, #0 ; >0还是=0?
BNE __tx_timer_no_time_slice ; 如果>0,
;当没有定时切片时,将定时切片数标志位置1,表示链表中没有切片了。
; /* Set the time-slice expired flag. */
; _tx_timer_expired_time_slice = TX_TRUE;
;
    LDR a4, [pc, #EXPIRED_TIME_SLICE-.-8] ; 获得定时切片数是否为0标志地址
       MOV a1, #1 ; 将标志设为1
    STR a1, [a4, #0] ; 设立到时标志
;
; }
;
__tx_timer_no_time_slice
;
; /* Test for timer expiration. */
; if (*_tx_timer_current_ptr)
; {
;
LDR a2, [pc, #TIMER_CURRENT_PTR-.-8] ; 获得的是_tx_timer_current_ptr的地址
                    ;而TIMER_DECLARE TX_INTERNAL_TIMER **_tx_timer_current_ptr
                    ;
    LDR a1, [a2, #0] ; 获得当前的_tx_timer_current_ptr
LDR a3, [a1, #0] ; 获得定时列表的入口定时切片指针
CMP a3, #0 ;链表中是否有定时切片存在
    BEQ __tx_timer_no_timer ; 不存在, 调用__tx_timer_no_time将
;_tx_timer_current_ptr++
;
; /* Set expiration flag. */
; _tx_timer_expired = TX_TRUE;
;
    LDR a4, [pc, #EXPIRED-.-8] ; Pickup expriation flag address
    MOV a3, #1 ; Build expired value
    STR a3, [a4, #0] ; Set expired flag
    B __tx_timer_done ; Finished timer processing
;
; }
; else
; {
__tx_timer_no_timer
;
; /* No timer expired, increment the timer pointer. */
; _tx_timer_current_ptr++;
;
    ADD a1, a1, #4 ; Move to next timer
;
; /* Check for wrap-around. */
; if (_tx_timer_current_ptr == _tx_timer_list_end)
;
    LDR a4, [pc, #LIST_END-.-8] ; Pickup addr of timer list end
    LDR a3, [a4, #0] ; Pickup list end
    CMP a1, a3 ; Are we at list end?
    BNE __tx_timer_skip_wrap ; No, skip wrap-around logic
;
; /* Wrap to beginning of list. */
; _tx_timer_current_ptr = _tx_timer_list_start;
;
    LDR a4, [pc, #LIST_START-.-8] ; Pickup addr of timer list start
    LDR a1, [a4, #0] ; Set current pointer to list start
;
__tx_timer_skip_wrap
;
    STR a1, [a2, #0] ; Store new current timer pointer
; }
;
__tx_timer_done
;
;
; /* See if anything has expired. */
; if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
; {
;
    LDR a4, [pc, #EXPIRED_TIME_SLICE-.-8] ; Pickup addr of expired flag
    LDR a3, [a4, #0] ; Pickup time-slice expired flag
    CMP a3, #0 ; Did a time-slice expire?
    BNE __tx_something_expired ; If non-zero, time-slice expired
    LDR a2, [pc, #EXPIRED-.-8] ; Pickup addr of other expired flag
    LDR a1, [a2, #0] ; Pickup timer expired flag
    CMP a1, #0 ; Did a timer expire?
    BEQ __tx_timer_nothing_expired ; No, nothing expired
;
__tx_something_expired
;
;
    STR lr, [sp, #-4]! ; Save the lr register on the stack
;
; /* Did a timer expire? */
; if (_tx_timer_expired)
; {
;
    LDR a2, [pc, #EXPIRED-.-8] ; Pickup addr of expired flag
    LDR a1, [a2, #0] ; Pickup timer expired flag
    CMP a1, #0 ; Check for timer expiration
    BEQ __tx_timer_dont_activate ; If not set, skip timer activation
;
; /* Increment the preempt disable counter in preparation for
; thread resumption. */

; _tx_thread_preempt_disable++;
;
    LDR a4, [pc, #PREEMPT_DISABLE-.-8] ; Pickup addr of preempt disable
    LDR a3, [a4, #0] ; Pickup actual flag
    ADD a3, a3, #1 ; Incrment the preempt disable count
    STR a3, [a4, #0] ; Store it back
;
; /* Activate the system timer thread. */
; _tx_thread_resume(&_tx_timer_thread);
;
    LDR a1, [pc, #TIMER_THREAD-.-8] ; Get timer thread control block addr
    BL _tx_thread_resume ; Call thread resume to wake up the
                                                ; timer thread
;
; }
__tx_timer_dont_activate
;
; /* Did time slice expire? */
; if (_tx_timer_expired_time_slice)
; {
;
    LDR a4, [pc, #EXPIRED_TIME_SLICE-.-8] ; Pickup addr of time-slice expired
    LDR a3, [a4, #0] ; Pickup the actual flag
    CMP a3, #0 ; See if the flag is set
    BEQ __tx_timer_not_ts_expiration ; No, skip time-slice processing
;
; /* Time slice interrupted thread. */
; if (!_tx_thread_time_slice())
; _tx_timer_time_slice = _tx_thread_current_ptr -> tx_time_slice;
;
    BL _tx_thread_time_slice ; Call time-slice processing
    CMP a1, #0 ; Check return status
    BNE __tx_timer_not_ts_expiration ; If time-sliced, skip reset processing
    LDR a2, [pc, #CURRENT_PTR-.-8] ; Pickup addr of current thread pointer
    LDR a1, [a2, #0] ; Pickup thread pointer
    LDR a3, [a1, #24] ; Pickup fresh time-slice for thread
                                                ; (a fresh time slice was setup in
                                                ; the _tx_thread_time_slice function)
    LDR a4, [pc, #TIME_SLICE-.-8] ; Pickup addr of time-slice variable
    STR a3, [a4, #0] ; Setup new time-slice
;
; }
;
__tx_timer_not_ts_expiration
;
    LDR a4, [pc, #EXPIRED_TIME_SLICE-.-8] ; Pickup address of expired time-slice flag
    MOV a1, #0 ; Clear value
    STR a1, [a4, #0] ; Clear time-slice expired flag
;
    LDR lr, [sp], #4 ; Recover lr register
;
; }
;
__tx_timer_nothing_expired
;
    MOV pc, lr ; Return to caller
;
;}
TIME_SLICE
    DCD _tx_timer_time_slice
SYSTEM_CLOCK
    DCD _tx_timer_system_clock
TIMER_CURRENT_PTR
    DCD _tx_timer_current_ptr
LIST_START
    DCD _tx_timer_list_start
LIST_END
    DCD _tx_timer_list_end
EXPIRED_TIME_SLICE
     DCD _tx_timer_expired_time_slice
EXPIRED
    DCD _tx_timer_expired
TIMER_THREAD
    DCD _tx_timer_thread
CURRENT_PTR
     DCD _tx_thread_current_ptr
THREAD_TIME_SLICE
    DCD _tx_thread_time_slice
RESUME
    DCD _tx_thread_resume
PREEMPT_DISABLE
    DCD _tx_thread_preempt_disable
    END






_tx_initialize_high_level()
VOID _tx_initialize_high_level(VOID)
所属文件    调用者    开关量
tx_ihl.c    启动代码    无
主要时对一些与硬件无关的变量进行初始化,其中主要实现了线程的初始化;定时的初始化,这里定时也是一个线程,且优先级为最高0;还有对信号量、队列、时间标志、块池、和字节池的初始化。

/*进行一些高级的初始化*/
 _tx_initialize_high_level();

    VOID _tx_initialize_high_level(VOID)
{

    /* Initialize the event log, if enabled. */
    TX_EL_INITIALIZE

    /* 调用线程初始化函数. */
    _tx_thread_initialize();

    /* 调用定时初始化函数 */
    _tx_timer_initialize();

    /* 调用信号量初始化函数 */
    _tx_semaphore_initialize();

    /* 调用队列初始化函数 */
    _tx_queue_initialize();

    /* 调用事件标志初始化函数. */
    _tx_event_flags_initialize();

    /* 调用block pool 初始化函数. */
    _tx_block_pool_initialize();

    /* 调用byte pool初始化函数. */
    _tx_byte_pool_initialize();
}


/* 调用线程初始化函数. */
_tx_thread_initialize();
VOID _tx_thread_initialize(VOID)

所属文件    调用者    开关量
tx_ti.c    启动代码    无
此函数主要实现对与线程有关的一些变量进行初始化。
    VOID _tx_thread_initialize(VOID)
{

REG_1 UINT i; /* Working index variable */
REG_2 UCHAR set_bit; /* Lowest set bit          */ H
REG_3 UINT temp; /* Working shift variable     */
REG_4 UCHAR *lowest_set_ptr; /* Pointer in set bit array     */
REG_5 TX_THREAD_PTR    *priority_list_ptr; /* Pointer in priority list */


    /* Note: the system stack pointer and the system state variables are
       initialized by the low and high-level initialization functions,
       respectively. */


    /* 初始化当前线程指针为空 */
    _tx_thread_current_ptr = TX_NULL;

    /* 初始化要执行线程指针为空. */
    _tx_thread_execute_ptr = TX_NULL;

    /* 初始化优先级信息 */
    _tx_thread_priority_map = 0;
    _tx_thread_preempted_map = 0;
    _tx_thread_highest_priority = TX_MAX_PRIORITIES;

/* 初始化the lowest-set bit 表. 这被用来当线程被挂起和从新启动时寻找下一个准备执行的线程 */
    _tx_thread_lowest_bit[0] = 0;
    lowest_set_ptr = &_tx_thread_lowest_bit[1];
    for (i = 1; i < TX_THREAD_MAX_BYTE_VALUES; i++)
    {

        /*将当前序号给临时变量 */
     temp = i;

     /* 寻找字节中的最低比特位设置,即在一个字节中的最高优先级 */ r
        set_bit = 0;
        while (!(temp & 1))
        {

            /*把序号往右移动一位.并且增加set-bit 的位置. */
            temp = temp >> 1;
            set_bit++;
        }

/* 预先求出对应的线程优先级byte值所对应的优先级最高的的bit位*/ *(lowest_set_ptr++) = set_bit;
/*例如priorityb_byte的值为5即0x101那么所对应的优先级最高为0,则
    lowest_set_ptr[priorityb_byte]=0*/

}
/*当优先级字节的值为i时,我们很快可以知道该字节的高优先级为第_tx_thread_lowest_bit[i]bit位。*/

    /* 初始化优先级头指针队列. 即将线程块对应的空间都初始化为空 */
    priority_list_ptr = &_tx_thread_priority_list[0];
    for (i = 0; i < TX_MAX_PRIORITIES; i++)
        *(priority_list_ptr++) = TX_NULL;

    /* I初始化以创建线程列表的头指针和以创建线程的个数*/
    _tx_thread_created_ptr = TX_NULL;
    _tx_thread_created_count = 0;

    /* Clear the global preempt disable variable. ???*/
    _tx_thread_preempt_disable = 0;
}

VOID _tx_timer_initialize(VOID)

所属文件    调用者    开关量
tx_timi.c    启动代码    无
主要实现有定时器有关的一些变量的初始化,并建立了一个线程专门由于定时管理。

/* 调用定时初始化函数 */
    _tx_timer_initialize();


    VOID _tx_timer_initialize(VOID)
{

REG_1 UINT i; /* Working index variable */
REG_2 TX_INTERNAL_TIMER **timer_ptr; /* Working timer pointer */


    /* 初始化系统时钟为 0. */
    _tx_timer_system_clock = 0;

    /*初始化时间切片的值为0以确保它是无效的 ?? */
    _tx_timer_time_slice = 0;

    /* 清除时间期限终止标志位 */
    _tx_timer_expired_time_slice = TX_FALSE;
    _tx_timer_expired = TX_FALSE;

    /* 初始化线程并且定时管理控制结构的应用 */

    /*首先初始化定时指针列表,即将列表中存储的指针都赋为空 */
    timer_ptr = &_tx_timer_list[0];
    for (i = 0; i < TX_TIMER_ENTRIES; i++)
        *timer_ptr++ = TX_NULL;

    /* 初始化所有列表指针. */
    _tx_timer_list_start = &_tx_timer_list[0];
    _tx_timer_current_ptr = &_tx_timer_list[0];

/* 设置定时列表的尾指针为实际定时列表的的指针再加1, 事件中断处理在前面的汇编语言中已经定义过了 (就是_tx_irq_handler) */
    _tx_timer_list_end = &_tx_timer_list[TX_TIMER_ENTRIES-1];
    _tx_timer_list_end = _tx_timer_list_end + 1;

/* 创建一个系统定时线程 这个线程处理所有的定时期限终止和从新调度. 它的堆栈和优先级在前面的low-level initialization component已经定义过了(从新回去看)*/
    _tx_thread_create(&_tx_timer_thread, "System Timer Thread", _tx_timer_thread_entry,
                (ULONG) TX_TIMER_ID, _tx_timer_stack_start, _tx_timer_stack_size,
    _tx_timer_priority, _tx_timer_priority, TX_NO_TIME_SLICE,TX_DONT_START);
/*_tx_timer_stack_start, _tx_timer_stack_size,_tx_timer_priority,是在tx_ill.s中进行了初始化,其中_timer_stack_size=1024,_tx_timer_priority=0*/
    /*初始化已建定时列表的指针 */
    _tx_timer_created_ptr = TX_NULL;

    /* 初始化已建定时数为0 */
    _tx_timer_created_count = 0;
}
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
ThreadX移植——STM32H7+MDK-AC6平台
ARM Cortex-M3的startup.s文件详解
FreeRTOS 到ARM7的移植(原创),送官方说明文档
关于
RT-Thread操作系统在cortex-m3内核的移植原理
基于DSP2812的SVPWM波形实现程序
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服