{attach/detach}Interrupt() functions.

This commit is contained in:
Cristian Maglie 2012-10-26 20:17:34 +02:00
parent e7193ac42c
commit 921dfe794f
4 changed files with 148 additions and 358 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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 <assert.h>
/*----------------------------------------------------------------------------
* 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 ;
}