I wrote a short test program which starts a IRQ handler on each falling edge on a GPIO input pin.
After struggling with some parameters in the ioport and pio ASF functions used to configure the IRQ handler and GPIO pin I finally got as best result a 4µs delay between input pin signal change and IRQ handler start. I am using a scope for measurement.
This is quite a long time for a 300MHz embedded MCU which is optimized for fast interrupt handling I think. I know that there is some code executed in front of the handler due to the PIO handler and FPU support but, well.... I'm stuck here.
// "/INT" pin #define PIN_NOT_INT_GPIO (PIO_PA6_IDX) #define PIN_NOT_INT_FLAGS (IOPORT_MODE_PULLUP | IOPORT_MODE_GLITCH_FILTER) #define PIN_NOT_INT_SENSE (IOPORT_SENSE_FALLING) #define PIN_NOT_INT_MASK PIO_PA6 #define PIN_NOT_INT_PIO PIOA #define PIN_NOT_INT_ID ID_PIOA #define PIN_NOT_INT_ATTR (PIO_PULLUP | PIO_DEGLITCH | PIO_IT_FALL_EDGE) #define PIN_NOT_INT_IRQn PIOA_IRQn #define PEAK_CURR_IRQ_PRIOR_PIO 0x00 // highest priority static void PeakCurrentIrq_Handler(uint32_t id, uint32_t mask) { // signal IRQ handler function entry on digital output ioport_set_pin_level(PIN_TEST1_GPIO, IOPORT_PIN_LEVEL_HIGH); // clear and re-init interrupt uint32_t bitmask = pio_get_interrupt_mask(PIN_NOT_INT_PIO); pio_disable_interrupt(PIN_NOT_INT_PIO, 0xFFFFFFFF); pio_get_interrupt_status(PIN_NOT_INT_PIO); NVIC_DisableIRQ((IRQn_Type) PIN_NOT_INT_ID); ; // do what has to be done NVIC_ClearPendingIRQ((IRQn_Type) PIN_NOT_INT_ID); NVIC_SetPriority((IRQn_Type) PIN_NOT_INT_ID, PEAK_CURR_IRQ_PRIOR_PIO); NVIC_EnableIRQ((IRQn_Type) PIN_NOT_INT_ID); pio_enable_interrupt(PIN_NOT_INT_PIO, bitmask); // signal IRQ handler function exit on digital output ioport_set_pin_level(PIN_TEST1_GPIO, IOPORT_PIN_LEVEL_LOW); return; } static void enable_peak_irq(void) { pmc_enable_periph_clk(PIN_NOT_INT_ID); /* Interrupt on falling edge */ pio_handler_set(PIN_NOT_INT_PIO, PIN_NOT_INT_ID, PIN_NOT_INT_MASK, PIN_NOT_INT_ATTR, PeakCurrentIrq_Handler); pio_handler_set_priority(PIN_NOT_INT_PIO, (IRQn_Type) PIN_NOT_INT_ID, PEAK_CURR_IRQ_PRIOR_PIO); } int main(void) { /* Initialize the SAM system. */ sysclk_init(); board_init(); ioport_set_pin_input_mode(PIN_NOT_INT_GPIO, PIN_NOT_INT_FLAGS, PIN_NOT_INT_SENSE); // enable peak current detection enable_peak_irq(); while(1) { // pull IRQ input pin low to run IRQ handler ioport_set_pin_level(PIN_D4_GPIO, IOPORT_PIN_LEVEL_LOW); delay_ms(1); // set IRQ input pin high ioport_set_pin_level(PIN_D4_GPIO, IOPORT_PIN_LEVEL_HIGH); delay_ms(1); } } PIN_D4_GPIO is physically connected to the IRQ input pin PIN_NOT_INT_GPIO and is used to trigger the scope. PIN_TEST1_GPIO is an output used for timing measurement. Trivial initialization code of these two pins is not shown here in this example.
Has anyone any experience / results / ideas on that topic ?
P.S:
PIN_D4_GPIO is physically connected to the IRQ input pin PIN_NOT_INT_GPIO and is used to trigger the scope.
PIN_TEST1_GPIO is an output used for timing measurement.
Trivial initialization code of these two pins is not shown here in this example.