From a4936b59cb0afe55fb1a31754293586bbde38115 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 15 Dec 2016 14:55:45 +0100 Subject: bsp/atsam: System initialization for PIO IRQs --- .../arm/atsam/libraries/libchip/include/pio_it.h | 26 ++- .../arm/atsam/libraries/libchip/source/pio_it.c | 217 +++++++++------------ c/src/lib/libbsp/shared/include/fatal.h | 8 +- 3 files changed, 127 insertions(+), 124 deletions(-) diff --git a/c/src/lib/libbsp/arm/atsam/libraries/libchip/include/pio_it.h b/c/src/lib/libbsp/arm/atsam/libraries/libchip/include/pio_it.h index 4235ec9bde..b03973caa1 100644 --- a/c/src/lib/libbsp/arm/atsam/libraries/libchip/include/pio_it.h +++ b/c/src/lib/libbsp/arm/atsam/libraries/libchip/include/pio_it.h @@ -77,11 +77,31 @@ extern "C" { extern void PIO_InitializeInterrupts(uint32_t dwPriority); -extern void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *)); +extern void PIO_ConfigureIt(const Pin *pPin, + void (*handler)(const Pin *, void *arg), void *arg); -extern void PIO_EnableIt(const Pin *pPin); -extern void PIO_DisableIt(const Pin *pPin); +/** + * Enables the given interrupt source if it has been configured. The status + * register of the corresponding PIO controller is cleared prior to enabling + * the interrupt. + * \param pPin Interrupt source to enable. + */ +static inline void PIO_EnableIt(const Pin *pPin) +{ + pPin->pio->PIO_ISR; + pPin->pio->PIO_IER = pPin->mask; +} + +/** + * Disables a given interrupt source, with no added side effects. + * + * \param pPin Interrupt source to disable. + */ +static inline void PIO_DisableIt(const Pin *pPin) +{ + pPin->pio->PIO_IDR = pPin->mask; +} extern void PIO_IT_InterruptHandler(void); diff --git a/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/pio_it.c b/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/pio_it.c index 61f0db26c1..7176288992 100644 --- a/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/pio_it.c +++ b/c/src/lib/libbsp/arm/atsam/libraries/libchip/source/pio_it.c @@ -37,7 +37,9 @@ #include "chip.h" -#include +#include +#include +#include /*---------------------------------------------------------------------------- * Local definitions @@ -61,7 +63,9 @@ typedef struct _InterruptSource { const Pin *pPin; /* Interrupt handler. */ - void (*handler)(const Pin *); + void (*handler)(const Pin *, void *arg); + + void *arg; } InterruptSource; /*---------------------------------------------------------------------------- @@ -83,37 +87,25 @@ static uint32_t _dwNumSources = 0; * \param id PIO controller ID. * \param pPio PIO controller base address. */ -extern void PioInterruptHandler(uint32_t id, Pio *pPio) +static void PIO_Interrupt(Pio *pPio, uint32_t id) { uint32_t status; - uint32_t i; + size_t i; - /* Read PIO controller status */ status = pPio->PIO_ISR; status &= pPio->PIO_IMR; - /* Check pending events */ - if (status != 0) { - TRACE_DEBUG("PIO interrupt on PIO controller #%d\n\r", id); - - /* Find triggering source */ - i = 0; - - while (status != 0) { - /* There cannot be an un-configured source enabled. */ - assert(i < _dwNumSources); - - /* Source is configured on the same controller */ - if (_aIntSources[i].pPin->id == id) { - /* Source has PIOs whose statuses have changed */ - if ((status & _aIntSources[i].pPin->mask) != 0) { - TRACE_DEBUG("Interrupt source #%d triggered\n\r", i); - _aIntSources[i].handler(_aIntSources[i].pPin); - status &= ~(_aIntSources[i].pPin->mask); - } - } + for (i = 0; status != 0 && i < MAX_INTERRUPT_SOURCES; ++i) { + const InterruptSource *is = &_aIntSources[i]; + const Pin *pin = is->pPin;; + + if (pin->id == id) { + uint32_t mask = pin->mask; - i++; + if ((status & mask) != 0) { + status &= ~mask; + (*is->handler)(pin, is->arg); + } } } } @@ -126,27 +118,27 @@ extern void PioInterruptHandler(uint32_t id, Pio *pPio) * \brief Parallel IO Controller A interrupt handler * \Redefined PIOA interrupt handler for NVIC interrupt table. */ -extern void PIOA_Handler(void) +static void PIOA_Interrupt(void *arg) { - PioInterruptHandler(ID_PIOA, PIOA); + PIO_Interrupt(arg, ID_PIOA); } /** * \brief Parallel IO Controller B interrupt handler * \Redefined PIOB interrupt handler for NVIC interrupt table. */ -extern void PIOB_Handler(void) +static void PIOB_Interrupt(void *arg) { - PioInterruptHandler(ID_PIOB, PIOB); + PIO_Interrupt(arg, ID_PIOB); } /** * \brief Parallel IO Controller C interrupt handler * \Redefined PIOC interrupt handler for NVIC interrupt table. */ -extern void PIOC_Handler(void) +static void PIOC_Interrupt(void *arg) { - PioInterruptHandler(ID_PIOC, PIOC); + PIO_Interrupt(arg, ID_PIOC); } @@ -154,83 +146,106 @@ extern void PIOC_Handler(void) * \brief Parallel IO Controller D interrupt handler * \Redefined PIOD interrupt handler for NVIC interrupt table. */ -extern void PIOD_Handler(void) +static void PIOD_Interrupt(void *arg) { - PioInterruptHandler(ID_PIOD, PIOD); + PIO_Interrupt(arg, ID_PIOD); } /** * \brief Parallel IO Controller E interrupt handler * \Redefined PIOE interrupt handler for NVIC interrupt table. */ -extern void PIOE_Handler(void) +static void PIOE_Interrupt(void *arg) { - PioInterruptHandler(ID_PIOE, PIOE); + PIO_Interrupt(arg, ID_PIOE); } -/** - * \brief Initializes the PIO interrupt management logic - * - * The desired priority of PIO interrupts must be provided. - * Calling this function multiple times result in the reset of currently - * configured interrupts. - * - * \param priority PIO controller interrupts priority. - */ -extern void PIO_InitializeInterrupts(uint32_t dwPriority) +static void PIO_SysInitializeInterrupts(void) { - TRACE_DEBUG("PIO_Initialize()\n\r"); + rtems_status_code sc; - /* Reset sources */ - _dwNumSources = 0; + TRACE_DEBUG("PIO_Initialize()\n\r"); /* Configure PIO interrupt sources */ TRACE_DEBUG("PIO_Initialize: Configuring PIOA\n\r"); PMC_EnablePeripheral(ID_PIOA); PIOA->PIO_ISR; PIOA->PIO_IDR = 0xFFFFFFFF; - NVIC_DisableIRQ(PIOA_IRQn); - NVIC_ClearPendingIRQ(PIOA_IRQn); - NVIC_SetPriority(PIOA_IRQn, dwPriority); - NVIC_EnableIRQ(PIOA_IRQn); + sc = rtems_interrupt_handler_install( + PIOA_IRQn, + "PIO A", + RTEMS_INTERRUPT_UNIQUE, + PIOA_Interrupt, + PIOA + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(ATSAM_FATAL_PIO_IRQ_A); + } TRACE_DEBUG("PIO_Initialize: Configuring PIOB\n\r"); PMC_EnablePeripheral(ID_PIOB); PIOB->PIO_ISR; PIOB->PIO_IDR = 0xFFFFFFFF; - NVIC_DisableIRQ(PIOB_IRQn); - NVIC_ClearPendingIRQ(PIOB_IRQn); - NVIC_SetPriority(PIOB_IRQn, dwPriority); - NVIC_EnableIRQ(PIOB_IRQn); + sc = rtems_interrupt_handler_install( + PIOB_IRQn, + "PIO B", + RTEMS_INTERRUPT_UNIQUE, + PIOB_Interrupt, + PIOB + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(ATSAM_FATAL_PIO_IRQ_B); + } TRACE_DEBUG("PIO_Initialize: Configuring PIOC\n\r"); PMC_EnablePeripheral(ID_PIOC); PIOC->PIO_ISR; PIOC->PIO_IDR = 0xFFFFFFFF; - NVIC_DisableIRQ(PIOC_IRQn); - NVIC_ClearPendingIRQ(PIOC_IRQn); - NVIC_SetPriority(PIOC_IRQn, dwPriority); - NVIC_EnableIRQ(PIOC_IRQn); + sc = rtems_interrupt_handler_install( + PIOC_IRQn, + "PIO C", + RTEMS_INTERRUPT_UNIQUE, + PIOC_Interrupt, + PIOC + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(ATSAM_FATAL_PIO_IRQ_C); + } TRACE_DEBUG("PIO_Initialize: Configuring PIOD\n\r"); PMC_EnablePeripheral(ID_PIOD); PIOD->PIO_ISR; PIOD->PIO_IDR = 0xFFFFFFFF; - NVIC_DisableIRQ(PIOD_IRQn); - NVIC_ClearPendingIRQ(PIOD_IRQn); - NVIC_SetPriority(PIOD_IRQn, dwPriority); - NVIC_EnableIRQ(PIOD_IRQn); + sc = rtems_interrupt_handler_install( + PIOD_IRQn, + "PIO D", + RTEMS_INTERRUPT_UNIQUE, + PIOD_Interrupt, + PIOD + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(ATSAM_FATAL_PIO_IRQ_D); + } TRACE_DEBUG("PIO_Initialize: Configuring PIOE\n\r"); PMC_EnablePeripheral(ID_PIOE); PIOE->PIO_ISR; PIOE->PIO_IDR = 0xFFFFFFFF; - NVIC_DisableIRQ(PIOE_IRQn); - NVIC_ClearPendingIRQ(PIOE_IRQn); - NVIC_SetPriority(PIOE_IRQn, dwPriority); - NVIC_EnableIRQ(PIOE_IRQn); + sc = rtems_interrupt_handler_install( + PIOE_IRQn, + "PIO E", + RTEMS_INTERRUPT_UNIQUE, + PIOE_Interrupt, + PIOE + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(ATSAM_FATAL_PIO_IRQ_E); + } } +RTEMS_SYSINIT_ITEM(PIO_SysInitializeInterrupts, RTEMS_SYSINIT_BSP_START, + RTEMS_SYSINIT_ORDER_LAST); + /** * Configures a PIO or a group of PIO to generate an interrupt on status * change. The provided interrupt handler will be called with the triggering @@ -239,25 +254,33 @@ extern void PIO_InitializeInterrupts(uint32_t dwPriority) * \param pPin Pointer to a Pin instance. * \param handler Interrupt handler function pointer. */ -extern void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *)) +void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *, void *arg), + void *arg) { Pio *pio; InterruptSource *pSource; + rtems_interrupt_level level; TRACE_DEBUG("PIO_ConfigureIt()\n\r"); - assert(pPin); pio = pPin->pio; - assert(_dwNumSources < MAX_INTERRUPT_SOURCES); - /* Define new source */ - TRACE_DEBUG("PIO_ConfigureIt: Defining new source #%d.\n\r", _dwNumSources); + rtems_interrupt_disable(level); + + if (_dwNumSources == MAX_INTERRUPT_SOURCES) { + bsp_fatal(ATSAM_FATAL_PIO_CONFIGURE_IT); + } pSource = &(_aIntSources[_dwNumSources]); pSource->pPin = pPin; pSource->handler = handler; _dwNumSources++; + rtems_interrupt_enable(level); + + /* Define new source */ + TRACE_DEBUG("PIO_ConfigureIt: Defining new source #%d.\n\r", _dwNumSources); + /* PIO3 with additional interrupt support * Configure additional interrupt mode registers */ if (pPin->attribute & PIO_IT_AIME) { @@ -280,49 +303,3 @@ extern void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *)) pio->PIO_AIMDR = pPin->mask; } } - -/** - * Enables the given interrupt source if it has been configured. The status - * register of the corresponding PIO controller is cleared prior to enabling - * the interrupt. - * \param pPin Interrupt source to enable. - */ -extern void PIO_EnableIt(const Pin *pPin) -{ - uint32_t i = 0; - uint32_t dwFound = 0; - - TRACE_DEBUG("PIO_EnableIt()\n\r"); - - assert(pPin != NULL); - -#ifndef NOASSERT - - while ((i < _dwNumSources) && !dwFound) { - if (_aIntSources[i].pPin == pPin) - dwFound = 1; - - i++; - } - - assert(dwFound != 0); -#endif - - pPin->pio->PIO_ISR; - pPin->pio->PIO_IER = pPin->mask; -} - -/** - * Disables a given interrupt source, with no added side effects. - * - * \param pPin Interrupt source to disable. - */ -extern void PIO_DisableIt(const Pin *pPin) -{ - assert(pPin != NULL); - - TRACE_DEBUG("PIO_DisableIt()\n\r"); - - pPin->pio->PIO_IDR = pPin->mask; -} - diff --git a/c/src/lib/libbsp/shared/include/fatal.h b/c/src/lib/libbsp/shared/include/fatal.h index 1336c78392..fd8b6783f5 100644 --- a/c/src/lib/libbsp/shared/include/fatal.h +++ b/c/src/lib/libbsp/shared/include/fatal.h @@ -127,7 +127,13 @@ typedef enum { QORIQ_FATAL_RESTART_INTERRUPT_FAILED, /* ATSAM fatal codes */ - ATSAM_FATAL_XDMA_IRQ_INSTALL = BSP_FATAL_CODE_BLOCK(11) + ATSAM_FATAL_XDMA_IRQ_INSTALL = BSP_FATAL_CODE_BLOCK(11), + ATSAM_FATAL_PIO_IRQ_A, + ATSAM_FATAL_PIO_IRQ_B, + ATSAM_FATAL_PIO_IRQ_C, + ATSAM_FATAL_PIO_IRQ_D, + ATSAM_FATAL_PIO_IRQ_E, + ATSAM_FATAL_PIO_CONFIGURE_IT } bsp_fatal_code; RTEMS_NO_RETURN static inline void -- cgit v1.2.3