Open tanakatt opened 4 years ago
re-enable MIE in your ISR.
Thank you for reply.
I did what you advised. But that doesn't work. Below is my code.
void USBFS_IRQHandler (void)
{
asm("addi sp,sp,-16");
asm("csrr t0,0x341"); // #define CSR_MEPC 0x341
asm("sw t0,4(sp)");
asm("csrr t0,0x342"); // #define CSR_MCAUSE 0x342
asm("sw t0,8(sp)");
asm("csrr t0,0x7c4"); // #define CSR_MSUBM 0x7c4
asm("sw t0,12(sp)");
eclic_global_interrupt_enable();
usbh_isr (&usb_hid_core);
eclic_global_interrupt_disable();
asm("lw t0,12(sp)");
asm("csrw 0x7c4,t0"); // #define CSR_MSUBM 0x7c4
asm("lw t0,8(sp)");
asm("csrw 0x342,t0"); // #define CSR_MCAUSE 0x342
asm("lw t0,4(sp)");
asm("csrw 0x341,t0"); // #define CSR_MEPC 0x341
asm("addi sp,sp,+16");
}
here is a simple nested interrupt sequence in non-vectored mode using CLIC mode
it has 2 external interrupts
int main(void)
{
SystemInit();
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_AF);
gpio_init(GPIOC, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
/* connect key EXTI line to key GPIO pin */
gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOC, GPIO_PIN_SOURCE_13);
gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_8);
/* configure key EXTI line */
exti_init(EXTI_13, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_flag_clear(EXTI_13);
exti_init(EXTI_8, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_flag_clear(EXTI_8);
/* enable and set key EXTI interrupt to the specified priority */
eclic_global_interrupt_enable();
eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL3_PRIO1);
eclic_irq_enable(EXTI10_15_IRQn, 1, 1); //low level interrupt
eclic_irq_enable(EXTI5_9_IRQn, 2, 1); //high level interrupt
while(1);
}
void EXTI10_15_IRQHandler(void)
{
if(exti_interrupt_flag_get(EXTI_13) == RESET)
return;
// if(gpio_output_bit_get(GPIOB,GPIO_PIN_9)==SET)
// gpio_bit_reset(GPIOB, GPIO_PIN_9);
// else
// gpio_bit_set(GPIOB, GPIO_PIN_9);
gpio_bit_set(GPIOB, GPIO_PIN_9);
delay_1ms(5000);
exti_interrupt_flag_clear(EXTI_13);
}
void EXTI5_9_IRQHandler(void)
{
if(exti_interrupt_flag_get(EXTI_8) == RESET)
return;
gpio_bit_reset(GPIOB, GPIO_PIN_9);
exti_interrupt_flag_clear(EXTI_8);
}
Call Stack of nested interrupt
as per GD32 framework code in entry.s I see that by default they have enabled global interrupt (MIE) for nested interrupt support https://github.com/riscv-mcu/GD32VF103_Firmware_Library/blob/12b61d1bf29afbee8ec4eee81cdbf1bd9f89470a/Firmware/RISCV/env_Eclipse/entry.S#L264 So we don't have to re-enable them again in our ISR. so the key here is setting the appropriate interrupt level. higher interrupt level number has highest preemption
###############################################
// IRQ entry point
//
.section .text.irq
.align 2
.global irq_entry
.weak irq_entry
irq_entry: // -------------> This label will be set to MTVT2 register
// Allocate the stack space
SAVE_CONTEXT// Save 16 regs
//------This special CSR read operation, which is actually use mcause as operand to directly store it to memory
csrrwi x0, CSR_PUSHMCAUSE, 17
//------This special CSR read operation, which is actually use mepc as operand to directly store it to memory
csrrwi x0, CSR_PUSHMEPC, 18
//------This special CSR read operation, which is actually use Msubm as operand to directly store it to memory
csrrwi x0, CSR_PUSHMSUBM, 19
service_loop:
//------This special CSR read/write operation, which is actually Claim the CLIC to find its pending highest
// ID, if the ID is not 0, then automatically enable the mstatus.MIE, and jump to its vector-entry-label, and
// update the link register
csrrw ra, CSR_JALMNXTI, ra //<---- this is a special CSR made by Nuclei Core which tells the core to re-enable MIE
//RESTORE_CONTEXT_EXCPT_X5
#---- Critical section with interrupts disabled -----------------------
DISABLE_MIE # Disable interrupts
LOAD x5, 19*REGBYTES(sp)
csrw CSR_MSUBM, x5
LOAD x5, 18*REGBYTES(sp)
csrw CSR_MEPC, x5
LOAD x5, 17*REGBYTES(sp)
csrw CSR_MCAUSE, x5
RESTORE_CONTEXT
// Return to regular code
mret
Thank you for reply.
I did what you advised. But that doesn't work. Below is my code.
void USBFS_IRQHandler (void) { asm("addi sp,sp,-16"); asm("csrr t0,0x341"); // #define CSR_MEPC 0x341 asm("sw t0,4(sp)"); asm("csrr t0,0x342"); // #define CSR_MCAUSE 0x342 asm("sw t0,8(sp)"); asm("csrr t0,0x7c4"); // #define CSR_MSUBM 0x7c4 asm("sw t0,12(sp)"); eclic_global_interrupt_enable(); usbh_isr (&usb_hid_core); eclic_global_interrupt_disable(); asm("lw t0,12(sp)"); asm("csrw 0x7c4,t0"); // #define CSR_MSUBM 0x7c4 asm("lw t0,8(sp)"); asm("csrw 0x342,t0"); // #define CSR_MCAUSE 0x342 asm("lw t0,4(sp)"); asm("csrw 0x341,t0"); // #define CSR_MEPC 0x341 asm("addi sp,sp,+16"); }
by the way I see you are taking care of context save/restore, which is not required since the irq_entry
https://github.com/riscv-mcu/GD32VF103_Firmware_Library/blob/12b61d1bf29afbee8ec4eee81cdbf1bd9f89470a/Firmware/RISCV/env_Eclipse/entry.S#L247 takes care of it unless you have your own startup initialization asm.
Thank you very much! It went well.
Thank you very much! It went well.
Cool!
I want to do preemptive interruptions. But I can't. In my environment, if multiple interrupts occur at the same time, they are handled by the tail chain. What should I do to make it preemptive?