riscv-mcu / GD32VF103_Firmware_Library

Original GD32VF103 Firmware Library
128 stars 37 forks source link

I want to do preemptive interruptions. #7

Open tanakatt opened 4 years ago

tanakatt commented 4 years ago

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?

123swk123 commented 4 years ago

re-enable MIE in your ISR.

tanakatt commented 4 years ago

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");

}
123swk123 commented 4 years ago

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 image

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
123swk123 commented 4 years ago

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.

tanakatt commented 4 years ago

Thank you very much! It went well.

123swk123 commented 4 years ago

Thank you very much! It went well.

Cool!