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.
Adapting IRQ Handler for Beaglebone Black, ThreadX
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
2 answers
Sort by: Most helpful
-
Scott Azure RTOS 4,051 Reputation points
2022-11-18T21:41:21.763+00:00 -
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
.