/* ---------------------------------------------------------------------------- */ /* Atmel Microcontroller Software Support */ /* SAM Software Package License */ /* ---------------------------------------------------------------------------- */ /* Copyright (c) 2015, Atmel Corporation */ /* */ /* All rights reserved. */ /* */ /* Redistribution and use in source and binary forms, with or without */ /* modification, are permitted provided that the following condition is met: */ /* */ /* - Redistributions of source code must retain the above copyright notice, */ /* this list of conditions and the disclaimer below. */ /* */ /* Atmel's name may not be used to endorse or promote products derived from */ /* this software without specific prior written permission. */ /* */ /* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */ /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */ /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, */ /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */ /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* ---------------------------------------------------------------------------- */ /* * \file */ /*---------------------------------------------------------------------------- * Headers *----------------------------------------------------------------------------*/ #include "chip.h" #include #include #include /*---------------------------------------------------------------------------- * Local definitions *----------------------------------------------------------------------------*/ /* Maximum number of interrupt sources that can be defined. This * constant can be increased, but the current value is the smallest possible * that will be compatible with all existing projects. */ #define MAX_INTERRUPT_SOURCES 7 /*---------------------------------------------------------------------------- * Local types *----------------------------------------------------------------------------*/ /** * Describes a PIO interrupt source, including the PIO instance triggering the * interrupt and the associated interrupt handler. */ typedef struct _InterruptSource { /* Pointer to the source pin instance. */ const Pin *pPin; /* Interrupt handler. */ void (*handler)(const Pin *, void *arg); void *arg; } InterruptSource; /*---------------------------------------------------------------------------- * Local variables *----------------------------------------------------------------------------*/ /* List of interrupt sources. */ static InterruptSource _aIntSources[MAX_INTERRUPT_SOURCES]; /* Number of currently defined interrupt sources. */ static uint32_t _dwNumSources = 0; /*---------------------------------------------------------------------------- * Local Functions *----------------------------------------------------------------------------*/ /** * \brief Handles all interrupts on the given PIO controller. * \param id PIO controller ID. * \param pPio PIO controller base address. */ static void PIO_Interrupt(Pio *pPio, uint32_t id) { uint32_t status; size_t i; status = pPio->PIO_ISR; status &= pPio->PIO_IMR; 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; if ((status & mask) != 0) { status &= ~mask; (*is->handler)(pin, is->arg); } } } } /*---------------------------------------------------------------------------- * Global Functions *----------------------------------------------------------------------------*/ /** * \brief Parallel IO Controller A interrupt handler * \Redefined PIOA interrupt handler for NVIC interrupt table. */ static void PIOA_Interrupt(void *arg) { PIO_Interrupt(arg, ID_PIOA); } /** * \brief Parallel IO Controller B interrupt handler * \Redefined PIOB interrupt handler for NVIC interrupt table. */ static void PIOB_Interrupt(void *arg) { PIO_Interrupt(arg, ID_PIOB); } /** * \brief Parallel IO Controller C interrupt handler * \Redefined PIOC interrupt handler for NVIC interrupt table. */ static void PIOC_Interrupt(void *arg) { PIO_Interrupt(arg, ID_PIOC); } /** * \brief Parallel IO Controller D interrupt handler * \Redefined PIOD interrupt handler for NVIC interrupt table. */ static void PIOD_Interrupt(void *arg) { PIO_Interrupt(arg, ID_PIOD); } /** * \brief Parallel IO Controller E interrupt handler * \Redefined PIOE interrupt handler for NVIC interrupt table. */ static void PIOE_Interrupt(void *arg) { PIO_Interrupt(arg, ID_PIOE); } static void PIO_SysInitializeInterrupts(void) { rtems_status_code sc; 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; 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; 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; 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; 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; 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 * pin as its parameter (enabling different pin instances to share the same * handler). * \param pPin Pointer to a Pin instance. * \param handler Interrupt handler function pointer. */ 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"); pio = pPin->pio; 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) { // enable additional interrupt mode pio->PIO_AIMER = pPin->mask; // if bit field of selected pin is 1, set as Rising Edge/High level detection event if (pPin->attribute & PIO_IT_RE_OR_HL) pio->PIO_REHLSR = pPin->mask; else pio->PIO_FELLSR = pPin->mask; /* if bit field of selected pin is 1, set as edge detection source */ if (pPin->attribute & PIO_IT_EDGE) pio->PIO_ESR = pPin->mask; else pio->PIO_LSR = pPin->mask; } else { /* disable additional interrupt mode */ pio->PIO_AIMDR = pPin->mask; } }