Adapting IRQ Handler for Beaglebone Black, ThreadX

Sulav Lal Shrestha 361 Reputation points
2022-11-18T21:31:17.53+00:00

Hello, I am trying to integrate Azure RTOS ThreadX into BeagleBone Black. First I got a demo LWIP program running on BBB which got the IP address using DHCP. Then, I integrated threadx source files with cortex-a8 port. With the default interrupt handler provided by TI Starterware, the timer interrupt works. I wanted to know how I can adapt the interrupt handler for threadx.

The Interrupt Handler provided by TI Starterware:

@******************************************************************************  
@*                  Function Definition of IRQ Handler  
@******************************************************************************      
@  
@ The IRQ handler jumps to the ISR of highest priority pending IRQ.  
@ This handler is a prioritized interrupt handler. The handler is a  
@ re-entrant IRQ handler. So interrupt service routines are processed  
@ in system mode to avoid lr_irq corruption  
@  
IRQHandler:  
        SUB      r14, r14, #4             @ Apply lr correction  
        STMFD    r13!, {r0-r3, r12, r14}  @ Save context  
        MRS      r12, spsr                @ Copy spsr  
        VMRS     r1, FPSCR                @ Copy fpscr  
        STMFD    r13!, {r1, r12}          @ Save spsr and fpscr  
        VSTMDB   r13!, {d0-d7}            @ Save D0-D7 NEON/VFP registers  
  
        LDR      r0, =ADDR_THRESHOLD      @ Get the IRQ Threshold  
        LDR      r1, [r0, #0]               
        STMFD    r13!, {r1}               @ Save the threshold value  
  
        LDR      r2, =ADDR_IRQ_PRIORITY   @ Get the active IRQ priority            
        LDR      r3, [r2, #0]  
        STR      r3, [r0, #0]             @ Set the priority as threshold     
  
        LDR      r1, =ADDR_SIR_IRQ        @ Get the Active IRQ  
        LDR      r2, [r1]  
        AND      r2, r2, #MASK_ACTIVE_IRQ @ Mask the Active IRQ number  
  
        MOV      r0, #NEWIRQAGR           @ To enable new IRQ Generation  
        LDR      r1, =ADDR_CONTROL  
          
        CMP      r3, #0                   @ Check if non-maskable priority 0  
        STRNE    r0, [r1]                 @ if > 0 priority, acknowledge INTC  
        DSB                               @ Make sure acknowledgement is completed  
          
        @  
        @ Enable IRQ and switch to system mode. But IRQ shall be enabled  
        @ only if priority level is > 0. Note that priority 0 is non maskable.  
        @ Interrupt Service Routines will execute in System Mode.  
        @  
        MRS      r14, cpsr                @ Read cpsr  
        ORR      r14, r14, #MODE_SYS  
        BICNE    r14, r14, #I_BIT         @ Enable IRQ if priority > 0  
        MSR      cpsr, r14  
                               
         
        STMFD    r13!, {r14}              @ Save lr_usr  
  
        LDR      r0, =fnRAMVectors        @ Load the base of the vector table  
        ADD      r14, pc, #0              @ Save return address in LR  
        LDR      pc, [r0, r2, lsl #2]     @ Jump to the ISR  
   
        LDMFD    r13!, {r14}              @ Restore lr_usr  
  
        @  
        @ Disable IRQ and change back to IRQ mode  
        @  
        CPSID    i, #MODE_IRQ  
  
        LDR      r0, =ADDR_THRESHOLD      @ Get the IRQ Threshold  
  
        LDR      r1, [r0, #0]  
        CMP      r1, #0                   @ If priority 0  
        MOVEQ    r2, #NEWIRQAGR           @ Enable new IRQ Generation  
        LDREQ    r1, =ADDR_CONTROL   
        STREQ    r2, [r1]  
          
        LDMFD    r13!, {r1}  
        STR      r1, [r0, #0]             @ Restore the threshold value  
        VLDMIA   r13!, {d0-d7}            @ Restore D0-D7 Neon/VFP registers  
        LDMFD    r13!, {r1, r12}          @ Get fpscr and spsr  
        MSR      spsr, r12                @ Restore spsr  
        VMSR     fpscr, r1                @ Restore fpscr  
  
        LDMFD    r13!, {r0-r3, r12, pc}^  @ Restore the context and return  
Azure RTOS
Azure RTOS
An Azure embedded development suite including a small but powerful operating system for resource-constrained devices.
323 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Scott Azure RTOS 4,051 Reputation points
    2022-11-18T21:41:21.763+00:00

    You need to make sure you call _tx_thread_context_save and _tx_thread_context_restore at the beginning and end of your ISR. See example here.
    For the timer interrupt, you need to call _tx_timer_interrupt in the timer ISR.

    2 people found this answer helpful.

  2. Sulav Lal Shrestha 361 Reputation points
    2023-01-18T23:18:11.5766667+00:00

    My interrupt exception handler now looks like this:

    __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.  */  
      
        /* 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.  */  
      
        LDR      r0, =ADDR_THRESHOLD       @ Get the IRQ Threshold 0x48200068  
        LDR      r1, [r0, #0]  
        STMFD    r13!, {r1}                @ Save the threshold value  
      
        LDR      r2, =ADDR_IRQ_PRIORITY    @ Get the active IRQ priority  
        LDR      r3, [r2, #0]  
        STR      r3, [r0, #0]              @ Set the priority as threshold  
      
        LDR      r1, =ADDR_SIR_IRQ         @ Get the Active IRQ  
        LDR      r2, [r1]  
        AND      r2, r2, #MASK_ACTIVE_IRQ  @ Mask the Active IRQ number  
      
        MOV      r0, #NEWIRQAGR           @ To enable new IRQ Generation  
        LDR      r1, =ADDR_CONTROL  
      
        CMP      r3, #0                   @ Check if non-maskable priority 0  
        STRNE    r0, [r1]                 @ if > 0 priority, acknowledge INTC  
        DSB                                @ Make sure acknowledgement is completed  
      
        @  
        @ Enable IRQ and switch to system mode. But IRQ shall be enabled  
        @ only if priority level is > 0. Note that priority 0 is non maskable.  
        @ Interrupt Service Routines will execute in System Mode.  
        @  
        MRS      r14, cpsr                @ Read cpsr  
        ORR      r14, r14, #MODE_SYS  
        BICNE    r14, r14, #I_BIT         @ Enable IRQ if priority > 0  
        MSR      cpsr, r14  
      
        STMFD    r13!, {r14}               @ Save lr_usr  
      
     /*Even though TX_ENABLE_IRQ_NESTING is not defined the assembly code assumes that IRQ Nesting is enabled*/  
    #ifdef TX_ENABLE_IRQ_NESTING  
        BL      _tx_thread_irq_nesting_start  
    #endif  
      
        /* 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     TimerTickISR                  @ Timer interrupt handler  
      
        LDR     r0, =ADDR_SIR_IRQ              @ Address of INTC_SIR_IRQ ADDR_SIR_IRQ  
        LDR     r2, [r0]  
        ANDS    r0, r2, #127  
        LSLS    r0, r0, #2  
        LDR     r1, =fnRAMVectors  
        LDR     r0, [r0, +r1]  
      
        BLX     r0  
      
      
     LDMFD    r13!, {r14}               @ Restore lr_usr  
      
        /* 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.  */  
      
        /*Even though TX_ENABLE_IRQ_NESTING is not defined the assembly code assumes that IRQ Nesting is enabled*/  
    #ifdef TX_ENABLE_IRQ_NESTING  
        BL      _tx_thread_irq_nesting_end  
    #endif  
      
        @  
        @ Disable IRQ and change back to IRQ mode  
        @  
        CPSID    i, #MODE_IRQ  
      
        LDR      r0, =ADDR_THRESHOLD      @ Get the IRQ Threshold  
      
        LDR      r1, [r0, #0]  
        CMP      r1, #0                   @ If priority 0  
        MOVEQ    r2, #NEWIRQAGR           @ Enable new IRQ Generation  
        LDREQ    r1, =ADDR_CONTROL  
        STREQ    r2, [r1]  
      
        LDMFD    r13!, {r1}  
        STR      r1, [r0, #0]             @ Restore the threshold value  
      
        /* Jump to context restore to restore system context.  */  
        B       _tx_thread_context_restore  
    

    The TX_ENABLE_IRQ_NESTING macro is undefined. And, after entering the specific interrupt handler I have to disable the interrupt and after interrupt processing is done, I have to reenable it.

    What I have done is taken the code from IRQ Handler provided by TI except for the registers save and restore code at the beginning and the end, and I have put the code after the label __tx_irq_processing_return.

    2 people found this answer helpful.
    0 comments No comments