您尚未登录。

楼主 # 2023-10-26 19:10:22

flyaqiao
会员
注册时间: 2023-09-25
已发帖子: 18
积分: 113

NUC972 成功移植Threadx 6.x, 记录一下移植过程...

项目需要,使用的nuc972主芯片,需要支持网络协议,就打算移植一下azure的tx,filex,netxduo,下面新记录一下tx的移植过程:
由于新唐的arm9中断处理和定时器初始化的寄存器并不同于tx官方的arm9的port,所以官方的port无法正常运行.

1.首先从github下载最新的tx代码.
git clone https://github.com/azure-rtos/threadx.git

2.创建tx的keil工程,nuc972官方没有提供iar工程,所以这里都使用keil,编译成lib的形式.
项目结构:
共三个目录:将tx的common/src目录下的所有文件添加到src目录
将tx的common/inc目录下的所有文件添加到inc目录
将tx的ports/arm9/ac5/inc目录下的所有文件添加到inc目录(其实就一个tx_port.h)
将tx的ports/arm9/ac5/src目录下的所有文件添加到port目录
如图:
.png
设置DEVICE:
DEV.png
设置Output:
LIB.png
设置Include:
INC.png
编译生成tx.lib文件备用,也可以直接下载工程文件并到tx根目录下:tx_lib_20231026182439.rar
.png
以上就是tx库的生成过程

3.打开新唐官方Non-OS BSP中的hello工程
将刚才生成的tx.lib放到hello目录下
将ports/arm9/ac5/example_build下的tx_initialize_low_level.s放到hello目录下,移植的主要工作就是修改这个文件,这里先放上我移植好的文件
tx_initialize_low_level_20231026183734.rar
打开工程加入刚才的两个文件,并在项目中排除startup_NUC970.s文件
hello-2.pnghello-1.png
此时编译项目应该没有错误
移植之前先修改sys.c文件,删除注册中断回调时的sysInitializeAIC调用
hello-3.png
中断入口将由tx_initialize_low_level.s中的__tx_irq_handler接管,所以不能再动态修改中断入口

;/**************************************************************************/
;/*                                                                        */
;/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
;/*                                                                        */
;/*       This software is licensed under the Microsoft Software License   */
;/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
;/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
;/*       and in the root directory of this software.                      */
;/*                                                                        */
;/**************************************************************************/
;
;
;/**************************************************************************/
;/**************************************************************************/
;/**                                                                       */ 
;/** ThreadX Component                                                     */ 
;/**                                                                       */
;/**   Initialize                                                          */
;/**                                                                       */
;/**************************************************************************/
;/**************************************************************************/
;
;
;#define TX_SOURCE_CODE
;
;
;/* Include necessary system files.  */
;
;#include "tx_api.h"
;#include "tx_initialize.h"
;#include "tx_thread.h"
;#include "tx_timer.h"
;
;
SVC_MODE        EQU     0xD3                 ; Disable IRQ/FIQ SVC mode
IRQ_MODE        EQU     0xD2                 ; Disable IRQ/FIQ IRQ mode
FIQ_MODE        EQU     0xD1                 ; Disable IRQ/FIQ FIQ mode
SYS_MODE        EQU     0xDF                 ; Disable IRQ/FIQ SYS mode
HEAP_SIZE       EQU     4096                 ; Heap size
UND_STACK_SIZE  EQU     256
ABT_STACK_SIZE  EQU     256
FIQ_STACK_SIZE  EQU     512                  ; FIQ stack size
SVC_STACK_SIZE  EQU     1024
SYS_STACK_SIZE  EQU     1024                 ; SYS stack size (used for nested interrupts)
IRQ_STACK_SIZE  EQU     1024                 ; IRQ stack size

;
;
;/* ARM9 ARMulator Timer and Interrupt controller information.  This depends on 
;   the ARMulator's Interrupt Controller and Timer being enabled in the default.ami.
;   In addition, the addresses must match those specified in the peripherals.ami file.
;   Please refer to section 2.10 and 4.16 of the Debug Target Guide, version 1.2.  */
;
TMR0_CLK        EQU     0x00E4E1C0
TMR0_IRQn       EQU     16
REG_TMR_TISR    EQU     0xB8001060  ; Timer Interrupt Status Register
REG_AIC_BA      EQU     0xB8002000  ; Interrupt Controller
REG_AIC_IPER    EQU     0xB8002118  ; Interrupt priority encoding register
REG_AIC_ISNR    EQU     0xB8002120  ; Interrupt source number register
REG_AIC_MDCR    EQU     0xB8002138  ; Mask disable command register
REG_AIC_MDCRH   EQU     0xB800213C  ; Mask disable command register (High)
REG_AIC_EOSCR   EQU     0xB8002150

;
;
    IMPORT      _tx_thread_system_stack_ptr
    IMPORT      _tx_initialize_unused_memory
    IMPORT      _tx_thread_context_save
    IMPORT      _tx_thread_context_restore
    IF  :DEF:TX_ENABLE_FIQ_SUPPORT
    IMPORT      _tx_thread_fiq_context_save
    IMPORT      _tx_thread_fiq_context_restore
    ENDIF
    IF  :DEF:TX_ENABLE_IRQ_NESTING
    IMPORT      _tx_thread_irq_nesting_start
    IMPORT      _tx_thread_irq_nesting_end
    ENDIF
    IF  :DEF:TX_ENABLE_FIQ_NESTING
    IMPORT      _tx_thread_fiq_nesting_start
    IMPORT      _tx_thread_fiq_nesting_end
    ENDIF
    IMPORT      _tx_timer_interrupt
    IMPORT      __main
    IMPORT      _tx_version_id
    IMPORT      _tx_build_options
    IMPORT      sysIrqHandlerTable
    IMPORT      sysSetTimerReferenceClock
    IMPORT      sysStartTimer
    IMPORT      sysGetSdramSizebyMB
    IMPORT      |Image$$RW_RAM1$$ZI$$Limit|
;
    AREA NUC_INIT, CODE, READONLY
;
;/* Define the ARM9 vector area.  This should be located or copied to 0.  */
;
    ENTRY
    EXPORT  Reset_Go
    EXPORT  __vectors
__vectors
    B       Reset_Go
    LDR     pc,=__tx_undefined                  ; Undefined handler
    LDR     pc,=__tx_swi_interrupt              ; Software interrupt handler
    LDR     pc,=__tx_prefetch_handler           ; Prefetch exception handler
    LDR     pc,=__tx_abort_handler              ; Abort exception handler
    LDR     pc,=__tx_reserved_handler           ; Reserved exception handler
    LDR     pc,=__tx_irq_handler                ; IRQ interrupt handler
    LDR     pc,=__tx_fiq_handler                ; FIQ interrupt handler
;
;

Reset_Go
    ; Disable Interrupt in case code is load by ICE while other firmware is executing
    LDR    r0, =REG_AIC_MDCR
    LDR    r1, =0xFFFFFFFF
    STR    r1, [r0]
    LDR    r0, =REG_AIC_MDCRH
    STR    r1, [r0]
    ;--------------------------------
    ; Initial Stack Pointer register
    ;--------------------------------
    ;INIT_STACK
    LDR     r1, =|Image$$RW_RAM1$$ZI$$Limit|    ; Get end of non-initialized RAM area
    LDR     r2, =HEAP_SIZE                      ; Pickup the heap size
    ADD     r1, r2, r1                          ; Setup heap limit
    ADD     r1, r1, #4                          ; Setup stack limit

;    /* Setup the system mode stack for nested interrupt support  */
    LDR     r2, =SYS_STACK_SIZE                 ; Pickup stack size
    MOV     r3, #SYS_MODE                       ; Build SYS mode CPSR
    MSR     CPSR_c, r3                          ; Enter SYS mode
    ADD     r1, r1, r2                          ; Calculate start of SYS stack
    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
    MOV     sp, r1                              ; Setup SYS stack pointer

    LDR     r2, =FIQ_STACK_SIZE                 ; Pickup stack size
    MOV     r0, #FIQ_MODE                       ; Build FIQ mode CPSR
    MSR     CPSR_c, r0                          ; Enter FIQ mode
    ADD     r1, r1, r2                          ; Calculate start of FIQ stack
    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
    MOV     sp, r1                              ; Setup FIQ stack pointer
    MOV     sl, #0                              ; Clear sl
    MOV     fp, #0                              ; Clear fp
    MOV     r0, #IRQ_MODE                       ; Build IRQ mode CPSR
    MSR     CPSR_c, r0                          ; Enter IRQ mode
    ADD     r1, r1, r2                          ; Calculate start of IRQ stack
    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
    MOV     sp, r1                              ; Setup IRQ stack pointer
    LDR     r2, =SVC_STACK_SIZE                 ; Pickup SVC (SVC stack size)
    MOV     r0, #SVC_MODE                       ; Build SVC mode CPSR
    MSR     CPSR_c, r0                          ; Enter SVC mode
    ADD     r1, r1, r2                          ; Calculate start of SVC stack
    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
    MOV     sp, r1                              ; Setup SVC stack pointe
    ;------------------------------------------------------
    ; Set the normal exception vector of CP15 control bit
    ;------------------------------------------------------
    MRC p15, 0, r0 , c1, c0     ; r0 := cp15 register 1
    BIC r0, r0, #0x2000         ; Clear bit13 in r1
    MCR p15, 0, r0 , c1, c0     ; cp15 register 1 := r0


    IMPORT  __main
    ;-----------------------------
    ;   enter the C code
    ;-----------------------------
    B   __main

    AREA ||.text||, CODE, READONLY
;/**************************************************************************/ 
;/*                                                                        */ 
;/*  FUNCTION                                               RELEASE        */ 
;/*                                                                        */ 
;/*    _tx_initialize_low_level                             ARM9/AC5       */ 
;/*                                                           6.0.1        */
;/*  AUTHOR                                                                */
;/*                                                                        */
;/*    William E. Lamie, Microsoft Corporation                             */
;/*                                                                        */
;/*  DESCRIPTION                                                           */
;/*                                                                        */ 
;/*    This function is responsible for any low-level processor            */ 
;/*    initialization, including setting up interrupt vectors, setting     */ 
;/*    up a periodic timer interrupt source, saving the system stack       */ 
;/*    pointer for use in ISR processing later, and finding the first      */ 
;/*    available RAM memory address for tx_application_define.             */ 
;/*                                                                        */ 
;/*  INPUT                                                                 */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  OUTPUT                                                                */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  CALLS                                                                 */ 
;/*                                                                        */ 
;/*    None                                                                */ 
;/*                                                                        */ 
;/*  CALLED BY                                                             */ 
;/*                                                                        */ 
;/*    _tx_initialize_kernel_enter           ThreadX entry function        */ 
;/*                                                                        */ 
;/*  RELEASE HISTORY                                                       */ 
;/*                                                                        */ 
;/*    DATE              NAME                      DESCRIPTION             */
;/*                                                                        */
;/*  06-30-2020     William E. Lamie         Initial Version 6.0.1         */
;/*                                                                        */
;/**************************************************************************/
;VOID   _tx_initialize_low_level(VOID)
;{
    EXPORT  _tx_initialize_low_level
_tx_initialize_low_level
    PRESERVE8
;
;
;    /****** NOTE ****** We must be in SVC MODE at this point.  Some monitors
;       enter this routine in USER mode and require a software interrupt to
;       change into SVC mode.  */
;
    LDR     r2, =SVC_STACK_SIZE                 ; Pickup SVC
    MOV     r0, #SVC_MODE                       ; Build SVC mode CPSR
    MSR     CPSR_c, r0                          ; Enter SVC mode
    MOV     r1, sp
    ADD     r1, r1, r2                          ; Calculate start of SVC stack
    LDR     r3, =_tx_thread_system_stack_ptr    ; Pickup stack pointer
    STR     r1, [r3, #0]                        ; Save the system stack
;
;    /* Save the system stack pointer.  */
;    _tx_thread_system_stack_ptr = (VOID_PTR) (sp);
;
    LDR     r1, =_tx_thread_system_stack_ptr    ; Pickup address of system stack ptr
    LDR     r0, [r1, #0]                        ; Pickup system stack 
    ADD     r0, r0, #4                          ; Increment to next free word
;
;    /* Save the first available memory address.  */
;    _tx_initialize_unused_memory =  (VOID_PTR) |Image$$ZI$$Limit| + HEAP + [SYS_STACK] + FIQ_STACK + IRQ_STACK;
;
    LDR     r2, =_tx_initialize_unused_memory   ; Pickup unused memory ptr address
    STR     r0, [r2, #0]                        ; Save first free memory address

;
;    /* Setup Timer for periodic interrupts.  */
;
;    /* Setup ARMulator Timer0 for periodic interrupts.  */
    PUSH    {lr}                                ; Save ISR lr
    LDR     r1,=TMR0_CLK
    MOV     r0,#0
    BL      sysSetTimerReferenceClock
    MOV     r2,#1                               ; PERIODIC_MODE
    MOV     r1,#0x64                            ; TX_TIMER_TICKS_PER_SECOND
    MOV     r0,#0                               ; TIMER0
    BL      sysStartTimer
    POP     {lr}                                ; Recover ISR lr
;    /* Done, return to caller.  */
;
    IF  {INTER} = {TRUE}
    BX      lr                                  ; Return to caller
    ELSE
    MOV     pc, lr                              ; Return to caller
    ENDIF
;}
;
;
;/* Define initial heap/stack routine for the ARM RealView (and ADS) startup code.  This
;   routine will set the initial stack to use the ThreadX IRQ & FIQ & 
;   (optionally SYS) stack areas.  */
;
;    EXPORT  __user_initial_stackheap
;__user_initial_stackheap
;    LDR     r0, =|Image$$ZI$$Limit|             ; Get end of non-initialized RAM area
;    LDR     r2, =HEAP_SIZE                      ; Pickup the heap size
;    ADD     r2, r2, r0                          ; Setup heap limit
;    ADD     r3, r2, #4                          ; Setup stack limit
;   MOV     r1, r3                              ; Setup start of stack
;    IF :DEF:TX_ENABLE_IRQ_NESTING
;    LDR     r12, =SYS_STACK_SIZE                ; Pickup IRQ system stack
;    ADD     r1, r1, r12                         ; Setup the return system stack
;    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
;    ENDIF
;    LDR     r12, =FIQ_STACK_SIZE                ; Pickup FIQ stack size
;    ADD     r1, r1, r12                         ; Setup the return system stack
;    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
;    LDR     r12, =IRQ_STACK_SIZE                ; Pickup IRQ system stack
;    ADD     r1, r1, r12                         ; Setup the return system stack
;    BIC     r1, r1, #7                          ; Ensure 8-byte alignment
;    IF  {INTER} = {TRUE}
;    BX      lr                                  ; Return to caller
;    ELSE
;    MOV     pc, lr                              ; Return to caller
;    ENDIF
;
;
;/* Define shells for each of the interrupt vectors.  */
;
    EXPORT  __tx_undefined
__tx_undefined
    B       __tx_undefined                      ; Undefined handler
;
    EXPORT  __tx_swi_interrupt
__tx_swi_interrupt
    B       __tx_swi_interrupt                  ; Software interrupt handler
;
    EXPORT  __tx_prefetch_handler
__tx_prefetch_handler
    B       __tx_prefetch_handler               ; Prefetch exception handler
;
    EXPORT  __tx_abort_handler
__tx_abort_handler
    B       __tx_abort_handler                  ; Abort exception handler
;
    EXPORT  __tx_reserved_handler
__tx_reserved_handler
    B       __tx_reserved_handler               ; Reserved exception handler
;
;
    EXPORT  __tx_irq_handler
    EXPORT  __tx_irq_processing_return      
__tx_irq_handler
;
;    /* Jump to context save to save system context.  */
    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.  */
;
;
;    /* Check for Timer0 interrupts on the ARMulator.  */
    LDR     r0,=REG_AIC_IPER
    LDR     r0,[r0]
    MOV     r1,#0x3f
    AND     r0,r1,r0,LSR #2
    PUSH    {r0}
    LDR     r2,=TMR0_IRQn                       ; Pickup Timer0 interrupt present bit
    CMP     r2, r0                              ; 
    BNE     _tx_not_timer_interrupt             ; If 0, not a timer interrupt
    LDR     r0,=REG_TMR_TISR
    LDR     r0,[r0]
    AND     r0,r0,#1
    CMP     r0,#0
    BEQ     _tx_not_timer_interrupt
    LDR     r1,=REG_TMR_TISR                    ; Build address of Timer0 clear register
    MOV     r0,#1                               ; 
    STR     r0, [r1]                            ; Clear timer 0 interrupt

    BL      _tx_timer_interrupt                 ; Timer interrupt handler
_tx_not_timer_interrupt
;
;    /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start 
;       from IRQ mode with interrupts disabled.  This routine switches to the
;       system mode and returns with IRQ interrupts enabled.  
;       
;       NOTE:  It is very important to ensure all IRQ interrupts are cleared 
;       prior to enabling nested IRQ interrupts.  */
    IF :DEF:TX_ENABLE_IRQ_NESTING
    BL      _tx_thread_irq_nesting_start
    ENDIF
;
;
;    /* Application IRQ handlers can be called here!  */
;
; LDR     r0,=REG_AIC_IPER
; LDR     r0,[r0]
; MOV     r1,#0x3f
; AND     r0,r1,r0,LSR #2
    POP     {r0}
    SUB     sp,sp,#8
    STR     r0,[sp,#4]
    LDR     r0,=REG_AIC_ISNR
    LDR     r0,[r0]
    STR     r0,[sp,#0]
    LDR     r0,[sp,#4]
    CMP     r0,#0
    BEQ     _irq_exit
    LDR     r0,[sp,#0]
    CMP     r0,#0
    BEQ     _irq_clear
    LDR     r1,=sysIrqHandlerTable
    LDR     r2,[sp,#4]
    LDR     r0,[r1,r2,LSL #2]
    BLX     r0
_irq_clear
    MOV     r0,#1
    LDR     r1,=REG_AIC_EOSCR
    STR     r0,[r1]
_irq_exit
    ADD      sp,sp,#8
;    /* If interrupt nesting was started earlier, the end of interrupt nesting
;       service must be called before returning to _tx_thread_context_restore.  
;       This routine returns in processing in IRQ mode with interrupts disabled.  */
    IF :DEF:TX_ENABLE_IRQ_NESTING
    BL      _tx_thread_irq_nesting_end
    ENDIF
;
;    /* Jump to context restore to restore system context.  */
    B       _tx_thread_context_restore
;
;
;    /* This is an example of a vectored IRQ handler.  */
;
    EXPORT  __tx_example_vectored_irq_handler
__tx_example_vectored_irq_handler
;
;
;    /* Save initial context and call context save to prepare for 
;       vectored ISR execution.  */
;
;    STMDB   sp!, {r0-r3}                        ; Save some scratch registers
;    MRS     r0, SPSR                            ; Pickup saved SPSR
;    SUB     lr, lr, #4                          ; Adjust point of interrupt 
;    STMDB   sp!, {r0, r10, r12, lr}             ; Store other scratch registers
;    BL      _tx_thread_vectored_context_save    ; Vectored context save
;
;    /* 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.  */
;
;
;    /* Interrupt nesting is allowed after calling _tx_thread_irq_nesting_start 
;       from IRQ mode with interrupts disabled.  This routine switches to the
;       system mode and returns with IRQ interrupts enabled.  
;       
;       NOTE:  It is very important to ensure all IRQ interrupts are cleared 
;       prior to enabling nested IRQ interrupts.  */
;    IF :DEF:TX_ENABLE_IRQ_NESTING
;    BL      _tx_thread_irq_nesting_start
;    ENDIF
;
;    /* Application IRQ handlers can be called here!  */
;
;    /* If interrupt nesting was started earlier, the end of interrupt nesting
;       service must be called before returning to _tx_thread_context_restore.  
;       This routine returns in processing in IRQ mode with interrupts disabled.  */
;    IF :DEF:TX_ENABLE_IRQ_NESTING
;    BL      _tx_thread_irq_nesting_end
;    ENDIF
;
;    /* Jump to context restore to restore system context.  */
;    B       _tx_thread_context_restore
;
;
    IF  :DEF:TX_ENABLE_FIQ_SUPPORT
    EXPORT  __tx_fiq_handler
    EXPORT  __tx_fiq_processing_return
__tx_fiq_handler
;
;    /* Jump to fiq context save to save system context.  */
    B       _tx_thread_fiq_context_save
__tx_fiq_processing_return
;
;    /* At this point execution is still in the FIQ mode.  The CPSR, point of
;       interrupt, and all C scratch registers are available for use.  */
;
;    /* Interrupt nesting is allowed after calling _tx_thread_fiq_nesting_start 
;       from FIQ mode with interrupts disabled.  This routine switches to the
;       system mode and returns with FIQ interrupts enabled. 
;
;       NOTE:  It is very important to ensure all FIQ interrupts are cleared 
;       prior to enabling nested FIQ interrupts.  */
    IF  :DEF:TX_ENABLE_FIQ_NESTING
    BL      _tx_thread_fiq_nesting_start
    ENDIF
;
;    /* Application FIQ handlers can be called here!  */
;
;    /* If interrupt nesting was started earlier, the end of interrupt nesting
;       service must be called before returning to _tx_thread_fiq_context_restore.  */
    IF  :DEF:TX_ENABLE_FIQ_NESTING
    BL      _tx_thread_fiq_nesting_end
    ENDIF
;
;    /* Jump to fiq context restore to restore system context.  */
    B       _tx_thread_fiq_context_restore
;
;
    ELSE
    EXPORT  __tx_fiq_handler
__tx_fiq_handler
    B       __tx_fiq_handler                    ; FIQ interrupt handler
    ENDIF
;
;    /* Reference build options and version ID to ensure they come in.  */
;
    LDR     r2, =_tx_build_options              ; Pickup build options variable address
    LDR     r0, [r2, #0]                        ; Pickup build options content
    LDR     r2, =_tx_version_id                 ; Pickup version ID variable address
    LDR     r0, [r2, #0]                        ; Pickup version ID content
;
;
    END

这个代码主要干以下任务:
__vectors初始化中断向量表
Reset_Go程序入口,初始化AIC和堆栈,并跳转main函数
_tx_initialize_low_level是tx_kernel_enter调用,用来初始化timer0做为OS的tick定时器,并初始化_tx_thread_system_stack_ptr和_tx_initialize_unused_memory
后的就是中断处理函数,主要是__tx_irq_handler

    LDR     r0,=REG_AIC_IPER
    LDR     r0,[r0]
    MOV     r1,#0x3f
    AND     r0,r1,r0,LSR #2
    PUSH    {r0}
    LDR     r2,=TMR0_IRQn                       ; Pickup Timer0 interrupt present bit
    CMP     r2, r0                              ; 
    BNE     _tx_not_timer_interrupt             ; If 0, not a timer interrupt
    LDR     r0,=REG_TMR_TISR
    LDR     r0,[r0]
    AND     r0,r0,#1
    CMP     r0,#0
    BEQ     _tx_not_timer_interrupt
    LDR     r1,=REG_TMR_TISR                    ; Build address of Timer0 clear register
    MOV     r0,#1                               ; 
    STR     r0, [r1]                            ; Clear timer 0 interrupt
    BL      _tx_timer_interrupt                 ; Timer interrupt handler

这段代码检查是不是Timer0定时器中断,如果是则调用_tx_timer_interrupt,否则跳转到_tx_not_timer_interrupt执行正常中断处理
这里的PUSH    {r0}注意,由于REG_AIC_IPER只能读取一次,这里压栈保存,方便后面正常中断处理使用

    POP     {r0}                        ; 弹出前面压入的中断号
    SUB     sp,sp,#8                  ; 在栈中为临时变量留出空间
    STR     r0,[sp,#4]
    LDR     r0,=REG_AIC_ISNR
    LDR     r0,[r0]
    STR     r0,[sp,#0]
    LDR     r0,[sp,#4]
    CMP     r0,#0
    BEQ     _irq_exit
    LDR     r0,[sp,#0]
    CMP     r0,#0
    BEQ     _irq_clear
    LDR     r1,=sysIrqHandlerTable
    LDR     r2,[sp,#4]
    LDR     r0,[r1,r2,LSL #2]
    BLX     r0
_irq_clear
    MOV     r0,#1
    LDR     r1,=REG_AIC_EOSCR
    STR     r0,[r1]
_irq_exit
    ADD      sp,sp,#8     ; 返还临时变量占用的空间

这就是正常中断处理了,作用等同于sys.c中的sysIrqHandler函数
移植到此就完成了
4.验证
修改main.c文件

/**************************************************************************//**
 * @file     main.c
 * @version  V1.00
 * $Date: 15/05/07 5:38p $
 * @brief    NUC970 Driver Sample Code
 *
 * @note
 * Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
 ******************************************************************************/
#include "nuc970.h"
#include "sys.h"
#include "tx_api.h"
#define DEMO_STACK_SIZE         (1024 * 32)
#define DEMO_BYTE_POOL_SIZE     (1024 * 1024)
TX_THREAD               thread_0;
TX_THREAD               thread_1;
TX_THREAD               thread_2;
TX_BYTE_POOL            byte_pool_0;
TX_EVENT_FLAGS_GROUP    event_flags_0;
UINT thread_0_counter = 0;
/* Define what the initial system looks like.  */
void thread_0_entry(ULONG thread_input)
{
  UINT status;
  /* This thread simply sits in while-forever-sleep loop.  */
  while (1) {
    /* Increment the thread counter.  */
    thread_0_counter++;
    /* Sleep for 10 ticks.  */
    if (thread_0_counter & 1)
      tx_thread_sleep(TX_TIMER_TICKS_PER_SECOND / 10);
    else
      tx_thread_sleep(TX_TIMER_TICKS_PER_SECOND);
    /* Set event flag 0 to wakeup thread 5.  */
    status =  tx_event_flags_set(&event_flags_0, 0x1, TX_OR);
    /* Check status.  */
    if (status != TX_SUCCESS)
      break;
  }
}
void thread_1_entry(ULONG thread_input)
{
  UINT    status;
  ULONG   actual_flags;
  /* This thread simply waits for an event in a forever loop.  */
  while (1) {
    /* Wait for event flag 0.  */
    status =  tx_event_flags_get(&event_flags_0, 0x1, TX_OR_CLEAR,
                                 &actual_flags, TX_WAIT_FOREVER);
    /* Check status.  */
    if ((status != TX_SUCCESS) || (actual_flags != 0x1))
      break;
    sysprintf("%s\r\n", __func__);
  }
}
void thread_2_entry(ULONG thread_input)
{
  /* This thread simply sits in while-forever-sleep loop.  */
  while (1) {
    tx_thread_sleep(TX_TIMER_TICKS_PER_SECOND);
    sysprintf("%d\r\n", thread_0_counter);
  }
}
/*-----------------------------------------------------------------------------*/
int main(void)
{
    sysDisableCache();
    sysFlushCache(I_D_CACHE);
    sysEnableCache(CACHE_WRITE_BACK);
    sysInitializeUART();
    sysprintf("\n\n Hello NUC970 !!!\n");

    sysprintf("APLL    clock %d MHz\n", sysGetClock(SYS_APLL));
    sysprintf("UPLL    clock %d MHz\n", sysGetClock(SYS_UPLL));
    sysprintf("CPU     clock %d MHz\n", sysGetClock(SYS_CPU));
    sysprintf("System  clock %d MHz\n", sysGetClock(SYS_SYSTEM));
    sysprintf("HCLK1   clock %d MHz\n", sysGetClock(SYS_HCLK1));
    sysprintf("HCLK234 clock %d MHz\n", sysGetClock(SYS_HCLK234));
    sysprintf("PCLK    clock %d MHz\n", sysGetClock(SYS_PCLK));
    tx_kernel_enter();
    return 0;
}
void tx_application_define(void *first_unused_memory)
{
  CHAR    *pointer = TX_NULL;
  /* Create a byte memory pool from which to allocate the thread stacks.  */
  tx_byte_pool_create(&byte_pool_0, "byte pool 0", first_unused_memory, DEMO_BYTE_POOL_SIZE);
  /* Put system definition stuff in here, e.g. thread creates and other assorted
     create information.  */
  /* Allocate the stack for thread 0.  */
  tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  /* Create the main thread.  */
  tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0,
                   pointer, DEMO_STACK_SIZE,
                   1, 1, TX_NO_TIME_SLICE, TX_AUTO_START);
  /* Allocate the stack for thread 1.  */
  tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  /* Create thread 1.  This thread simply pends on an event flag which will be set
     by thread_0.  */
  tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0,
                   pointer, DEMO_STACK_SIZE,
                   4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
  /* Allocate the stack for thread 2.  */
  tx_byte_allocate(&byte_pool_0, (VOID **) &pointer, DEMO_STACK_SIZE, TX_NO_WAIT);
  tx_thread_create(&thread_2, "thread 2", thread_2_entry, 0,
                   pointer, DEMO_STACK_SIZE,
                   5, 5, TX_NO_TIME_SLICE, TX_AUTO_START);
  tx_event_flags_create(&event_flags_0, "event flags 0");
}

创建三个任务,和一个事件任务0和任务2通过事件通知,任务1打印任务0中的记数
设置项目引用,包含tx的common/inc和port/arm9/ac5/inc
hello-4.png
编译项目,下载测试
这里注意sysprintf并没有做可重入处理,项目中建议需要处理一下
此项目只做移植说明,并没有在目标板实测运行,另外实测的项目相对复杂,不便于讲解.

后记:
filex基于sdnand早前移植过,前后台模式下使用,没有支持os的,后面需要打开一下os再测试一下,下一步需要移植netxduo了,这个还是第一次用.
不足之处还请多多指教

离线

楼主 #2 2023-11-02 17:26:16

flyaqiao
会员
注册时间: 2023-09-25
已发帖子: 18
积分: 113

Re: NUC972 成功移植Threadx 6.x, 记录一下移植过程...

dave 说:

大佬在硬件上跑过了吗?

跑过,开了几个任务,闪灯,跑了几天.

离线

楼主 #5 2023-11-13 13:58:31

flyaqiao
会员
注册时间: 2023-09-25
已发帖子: 18
积分: 113

Re: NUC972 成功移植Threadx 6.x, 记录一下移植过程...

感觉这个社区不是很活跃,主要还是用他的filex,原来一个项目用emmc,试用了好多文件系统,还是filex问题比较少.就接触了一下.

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn