Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I want to do preemptive interruptions. #7

Open
tanakatt opened this issue Jun 10, 2020 · 6 comments
Open

I want to do preemptive interruptions. #7

tanakatt opened this issue Jun 10, 2020 · 6 comments

Comments

@tanakatt
Copy link

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
Copy link

re-enable MIE in your ISR.

@tanakatt
Copy link
Author

tanakatt commented Jun 15, 2020

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
Copy link

123swk123 commented Jun 18, 2020

here is a simple nested interrupt sequence in non-vectored mode using CLIC mode

it has 2 external interrupts

  • EXTI_13 <- rising edge, configured as level 1 interrupt, which is low level
  • EXTI_8 <- rising edge, configured as level 2 interrupt, which is one level higher than EXTI_13 hence this will preempt EXTI_13
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

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
Copy link

123swk123 commented Jun 18, 2020

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

irq_entry: // -------------> This label will be set to MTVT2 register
takes care of it unless you have your own startup initialization asm.

@tanakatt
Copy link
Author

Thank you very much!
It went well.

@123swk123
Copy link

Thank you very much!
It went well.

Cool!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants