From 921dfe794f16aa282fd354997b847a7bfc92e233 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 26 Oct 2012 20:17:34 +0200 Subject: [PATCH] {attach/detach}Interrupt() functions. --- .../arduino/sam/cores/arduino/WInterrupts.c | 166 +++++++++-- .../arduino/sam/cores/arduino/WInterrupts.h | 52 +--- .../sam/cores/arduino/wiring_constants.h | 8 +- .../system/libsam/source/pio_it.c.disabled | 280 ------------------ 4 files changed, 148 insertions(+), 358 deletions(-) delete mode 100644 hardware/arduino/sam/system/libsam/source/pio_it.c.disabled diff --git a/hardware/arduino/sam/cores/arduino/WInterrupts.c b/hardware/arduino/sam/cores/arduino/WInterrupts.c index 8d5768aaa..68bd78c56 100644 --- a/hardware/arduino/sam/cores/arduino/WInterrupts.c +++ b/hardware/arduino/sam/cores/arduino/WInterrupts.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2011 Arduino. All right reserved. + Copyright (c) 2011-2012 Arduino. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,38 +18,152 @@ #include "WInterrupts.h" +typedef void (*interruptCB)(void); + +static int pinMapping[EXTERNAL_NUM_INTERRUPTS] = { 2, 3, 4, 5, 6, 7, 8 }; + +static interruptCB callbacksPioA[32]; +static interruptCB callbacksPioB[32]; +static interruptCB callbacksPioC[32]; + +/* Configure PIO interrupt sources */ +static void __initialize() { + int i; + for (i=0; i<32; i++) { + callbacksPioA[i] = NULL; + callbacksPioB[i] = NULL; + callbacksPioC[i] = NULL; + } + + pmc_enable_periph_clk(ID_PIOA); + NVIC_DisableIRQ(PIOA_IRQn); + NVIC_ClearPendingIRQ(PIOA_IRQn); + NVIC_SetPriority(PIOA_IRQn, 0); + NVIC_EnableIRQ(PIOA_IRQn); + + pmc_enable_periph_clk(ID_PIOB); + NVIC_DisableIRQ(PIOB_IRQn); + NVIC_ClearPendingIRQ(PIOB_IRQn); + NVIC_SetPriority(PIOB_IRQn, 0); + NVIC_EnableIRQ(PIOB_IRQn); + + pmc_enable_periph_clk(ID_PIOC); + NVIC_DisableIRQ(PIOC_IRQn); + NVIC_ClearPendingIRQ(PIOC_IRQn); + NVIC_SetPriority(PIOC_IRQn, 0); + NVIC_EnableIRQ(PIOC_IRQn); +} + + +void attachInterrupt(uint32_t interruptNum, void (*callback)(void), uint32_t mode) +{ + if (interruptNum >= EXTERNAL_NUM_INTERRUPTS) + return; + + static int enabled = 0; + if (!enabled) { + __initialize(); + enabled = 1; + } + + // Retrieve pin information + uint32_t pin = pinMapping[interruptNum]; + Pio *pio = g_APinDescription[pin].pPort; + uint32_t mask = g_APinDescription[pin].ulPin; + uint32_t pos = 0; + + uint32_t t; + for (t = mask; t>1; t>>=1, pos++) + ; + + // Set callback function + if (pio == PIOA) + callbacksPioA[pos] = callback; + if (pio == PIOB) + callbacksPioB[pos] = callback; + if (pio == PIOC) + callbacksPioC[pos] = callback; + + // Configure the interrupt mode + if (mode == CHANGE) { + // Disable additional interrupt mode (detects both rising and falling edges) + pio->PIO_AIMDR = mask; + } else { + // Enable additional interrupt mode + pio->PIO_AIMER = mask; + + // Select mode of operation + if (mode == LOW) { + pio->PIO_LSR = mask; // "Level" Select Register + pio->PIO_FELLSR = mask; // "Falling Edge / Low Level" Select Register + } + if (mode == HIGH) { + pio->PIO_LSR = mask; // "Level" Select Register + pio->PIO_REHLSR = mask; // "Rising Edge / High Level" Select Register + } + if (mode == FALLING) { + pio->PIO_ESR = mask; // "Edge" Select Register + pio->PIO_FELLSR = mask; // "Falling Edge / Low Level" Select Register + } + if (mode == RISING) { + pio->PIO_ESR = mask; // "Edge" Select Register + pio->PIO_REHLSR = mask; // "Rising Edge / High Level" Select Register + } + } + + // Enable interrupt + pio->PIO_IER = mask; +} + +void detachInterrupt( uint32_t interruptNum ) +{ + if (interruptNum >= EXTERNAL_NUM_INTERRUPTS) + return; + + // Retrieve pin information + uint32_t pin = pinMapping[interruptNum]; + Pio *pio = g_APinDescription[pin].pPort; + uint32_t mask = g_APinDescription[pin].ulPin; + + // Disable interrupt + pio->PIO_IDR = mask; +} + #ifdef __cplusplus extern "C" { #endif -/** PIO interrupt handlers array */ -/*volatile*/ static voidFuncPtr g_apfn_IntFunc[EXTERNAL_NUM_INTERRUPTS]={ 0 } ; - -void attachInterrupt( uint32_t ulInterrupt, void (*pfn_UserFunc)(void), uint32_t ulMode ) -{ - if ( ulInterrupt < EXTERNAL_NUM_INTERRUPTS ) - { - g_apfn_IntFunc[ulInterrupt] = pfn_UserFunc ; - - // Configure the interrupt mode (trigger on low input, any change, rising - // edge, or falling edge). The mode constants were chosen to correspond - // to the configuration bits in the hardware register, so we simply shift - // the mode into place. - - // Enable the interrupt. - - } +void PIOA_Handler(void) { + uint32_t isr = PIOA->PIO_ISR; + uint32_t i; + for (i=0; i<32; i++, isr>>=1) { + if ((isr & 0x1) == 0) + continue; + if (callbacksPioA[i]) + callbacksPioA[i](); + } } -void detachInterrupt( uint32_t ulInterrupt ) -{ - if ( ulInterrupt < EXTERNAL_NUM_INTERRUPTS ) - { - /* Disable the interrupt. */ +void PIOB_Handler(void) { + uint32_t isr = PIOB->PIO_ISR; + uint32_t i; + for (i=0; i<32; i++, isr>>=1) { + if ((isr & 0x1) == 0) + continue; + if (callbacksPioB[i]) + callbacksPioB[i](); + } +} - - g_apfn_IntFunc[ulInterrupt] = NULL ; - } +void PIOC_Handler(void) { + uint32_t isr = PIOC->PIO_ISR; + uint32_t i; + for (i=0; i<32; i++, isr>>=1) { + if ((isr & 0x1) == 0) + continue; + if (callbacksPioC[i]) + callbacksPioC[i](); + } } #ifdef __cplusplus diff --git a/hardware/arduino/sam/cores/arduino/WInterrupts.h b/hardware/arduino/sam/cores/arduino/WInterrupts.h index 3c8caa694..3220e850b 100644 --- a/hardware/arduino/sam/cores/arduino/WInterrupts.h +++ b/hardware/arduino/sam/cores/arduino/WInterrupts.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2011 Arduino. All right reserved. + Copyright (c) 2011-2012 Arduino. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -25,55 +25,9 @@ extern "C" { #endif +void attachInterrupt(uint32_t interruptNum, void (*callback)(void), uint32_t mode); -//typedef struct _InterruptSource -//{ -// /* Pointer to the source pin instance. */ -// PinDescription *pPin ; -// -// /* Interrupt handler. */ -// void (*handler)( const PinDescription *pPin ) ; -//} InterruptSource ; - - -/* - * \brief Specifies a function to call when an external interrupt occurs. - * Replaces any previous function that was attached to the interrupt. - * All Arduino SAM3 based boards pins can be switched into INPUT mode and have - * an interrupt user function attached to an event. - * - * \param ulInterrupt - * \param pfn_UserFunc - * \param ulMode - * -PIO_IT_RE_OR_HL = Interrupt High Level/Rising Edge detection is active -PIO_IT_EDGE = Interrupt Edge detection is active -PIO_IT_LOW_LEVEL = Low level interrupt is active -PIO_IT_HIGH_LEVEL = High level interrupt is active -PIO_IT_FALL_EDGE = Falling edge interrupt is active -PIO_IT_RISE_EDGE = Rising edge interrupt is active - -interrupt: the number of the interrupt (int) - -function: the function to call when the interrupt occurs; this function must take no parameters and return nothing. This function is sometimes referred to as an interrupt service routine. - -mode defines when the interrupt should be triggered. Four contstants are predefined as valid values: - - LOW to trigger the interrupt whenever the pin is low, - CHANGE to trigger the interrupt whenever the pin changes value - RISING to trigger when the pin goes from low to high, - FALLING for when the pin goes from high to low. - */ -extern void attachInterrupt( uint32_t ulInterrupt, void (*pfn_UserFunc)(void), uint32_t ulMode ) ; - -/* -Turns off the given interrupt. - -Parameters - -interrupt: the number of interrupt to disable (0 or 1). -*/ -extern void detachInterrupt( uint32_t ulInterrupt ) ; +void detachInterrupt(uint32_t interruptNum); #ifdef __cplusplus } diff --git a/hardware/arduino/sam/cores/arduino/wiring_constants.h b/hardware/arduino/sam/cores/arduino/wiring_constants.h index 346b56454..80f015d19 100644 --- a/hardware/arduino/sam/cores/arduino/wiring_constants.h +++ b/hardware/arduino/sam/cores/arduino/wiring_constants.h @@ -47,9 +47,11 @@ enum BitOrder { MSBFIRST = 1 }; -#define CHANGE 1 -#define FALLING 2 -#define RISING 3 +// LOW 0 +// HIGH 1 +#define CHANGE 2 +#define FALLING 3 +#define RISING 4 #define DEFAULT 1 #define EXTERNAL 0 diff --git a/hardware/arduino/sam/system/libsam/source/pio_it.c.disabled b/hardware/arduino/sam/system/libsam/source/pio_it.c.disabled deleted file mode 100644 index 0a4ebad7c..000000000 --- a/hardware/arduino/sam/system/libsam/source/pio_it.c.disabled +++ /dev/null @@ -1,280 +0,0 @@ -/* ---------------------------------------------------------------------------- - * SAM Software Package License - * ---------------------------------------------------------------------------- - * Copyright (c) 2011, Atmel Corporation - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are 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. - * ---------------------------------------------------------------------------- - */ - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "chip.h" - -#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* ) ; -} 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. - */ -extern void PioInterruptHandler( uint32_t id, Pio *pPio ) -{ - uint32_t status; - uint32_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 unconfigured 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); - } - } - i++; - } - } -} - -/*---------------------------------------------------------------------------- - * Global Functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Parallel IO Controller A interrupt handler - * \Redefined PIOA interrupt handler for NVIC interrupt table. - */ -extern void PIOA_IrqHandler( void ) -{ - if ( PIOA->PIO_PCISR != 0 ) - { - PIO_CaptureHandler() ; - } - - PioInterruptHandler( ID_PIOA, PIOA ) ; -} - -/** - * \brief Parallel IO Controller B interrupt handler - * \Redefined PIOB interrupt handler for NVIC interrupt table. - */ -extern void PIOB_IrqHandler( void ) -{ - PioInterruptHandler( ID_PIOB, PIOB ) ; -} - -/** - * \brief Parallel IO Controller C interrupt handler - * \Redefined PIOC interrupt handler for NVIC interrupt table. - */ -extern void PIOC_IrqHandler( void ) -{ - PioInterruptHandler( ID_PIOC, PIOC ) ; -} - -/** - * \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 ) -{ - TRACE_DEBUG( "PIO_Initialize()\n\r" ) ; - - /* Reset sources */ - _dwNumSources = 0 ; - - /* 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 ) ; - - 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 ) ; - - 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 ) ; -} - -/** - * 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. - */ -extern void PIO_ConfigureIt( const Pin *pPin, void (*handler)( const Pin* ) ) -{ - Pio* pio ; - InterruptSource* pSource ; - - 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 ) ; - - pSource = &(_aIntSources[_dwNumSources]) ; - pSource->pPin = pPin ; - pSource->handler = handler ; - _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; - } -} - -/** - * 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 Pio* pPio, const uint32_t dwMask ) -{ - pPio->PIO_ISR ; - pPio->PIO_IER = dwMask ; -} - -/** - * Disables a given interrupt source, with no added side effects. - * - * \param pPin Interrupt source to disable. - */ -extern void PIO_DisableIt( const Pio* pPio, const uint32_t dwMask ) -{ - pPio->PIO_IDR = dwMask ; -} -