Lab_interaccio/2012/ASK-Shield/References/waspmote-api-v.021/WInterrupts.c
Miguel Angel de Heras 451795bb92 Second commit
2025-03-05 15:57:19 +01:00

507 lines
13 KiB
C

/*
* Part of the Wiring project - http://wiring.uniandes.edu.co
*
* Copyright (c) 2004-05 Hernando Barragan
*
* Modified 24 November 2006 by David A. Mellis
*
* Copyright (C) 2009 Libelium Comunicaciones Distribuidas S.L.
* http://www.libelium.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Version: 0.4
* Design: David Gascón
* Implementation: David Cuartielles, Alberto Bielsa, David A. Mellis, Hernando Barragan
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "WConstants.h"
#include "WaspVariables.h"
#ifndef __WASPCONSTANTS_H__
#include "WaspConstants.h"
#endif
#include "wiring_private.h"
// definition of interrupt vectors
volatile static voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
volatile static voidFuncPtr twiIntFunc;
#if defined(__AVR_ATmega168__)
#define MCUCR EICRA
#define GICR EIMSK
#endif
/* attachInterrupt( interruptNum, userFunc, mode ) - attaches the interruption to the corresponding pin and subrutine
*
* It attaches the interruption to the corresponding microcontroller pin and subrutine associated to it.
*
* It returns nothing
*/
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
intFunc[interruptNum] = userFunc;
switch (interruptNum) {
case 0:
// INT0 connects to I2C_SCL
// 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.
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
// Enable the interrupt.
EIMSK |= (1 << INT0);
break;
case 1:
// INT1 connects to I2C_SDA
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
break;
case 2:
// INT2 is assigned to GPRS_RX in Wasp v5, this will allow waking up the
// processor on serial event from the GPRS
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
EIMSK |= (1 << INT2);
break;
case 3:
// INT3 corresponds to GPRS_TX in Wasp v5, it could eventually be used
// in a configuration where we were not using the GPRS board
EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
EIMSK |= (1 << INT3);
break;
case 4:
// INT4 is connected to PE4 which is also PWM2 in Wasp v5, it could be
// used as a source for an external interrupt, since it is connected
// to the analog sensor port
EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
EIMSK |= (1 << INT4);
break;
case 5:
// this hardware interrupt is connected to EN_5V_PW in Wasp v5, therefore
// it will not be used as interrupt, since it has a completely different use
// it is commented away to avoid conflicts
//EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
//EIMSK |= (1 << INT5);
break;
case 6:
// INT6 is the interrupt at PE6 which in Wasp v5 corresponds to the
// accelerometer's RDY_ACC pin, we should activate it when willing to
// get signals from it
EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
EIMSK |= (1 << INT6);
break;
case 7:
// INT7 is the interrupt at PE7 which in Wasp v5 is connected to
// RST_RTC, or the watchdog from the RTC, therefore we will have to
// connect this pin when working with the external RTC
EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
EIMSK |= (1 << INT7);
break;
}
}
}
/* detachInterrupt(interruptNum) - detaches the interruption from the corresponding pin
*
* It detaches the interruption from the corresponding microcontroller pin.
*
* It returns nothing
*/
void detachInterrupt(uint8_t interruptNum) {
cli();
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
switch (interruptNum) {
case 0:
// Disable the interrupt.
EIMSK &= ~(1 << INT0);
break;
case 1:
EIMSK &= ~(1 << INT1);
break;
case 2:
EIMSK &= ~(1 << INT2);
break;
case 3:
EIMSK &= ~(1 << INT3);
break;
case 4:
EIMSK &= ~(1 << INT4);
break;
case 5:
// this hardware interrupt is connected to EN_5V_PW in Wasp v5, therefore
// it will not be used as interrupt, since it has a completely different use
// it is commented away to avoid conflicts
//EIMSK &= ~(1 << INT5);
break;
case 6:
EIMSK &= ~(1 << INT6);
break;
case 7:
EIMSK &= ~(1 << INT7);
break;
}
intFunc[interruptNum] = 0;
}
sei();
}
void attachInterruptTwi(void (*userFunc)(void) ) {
twiIntFunc = userFunc;
}
SIGNAL(SIG_INTERRUPT0) {
if(intFunc[EXTERNAL_INT_0])
intFunc[EXTERNAL_INT_0]();
}
SIGNAL(SIG_INTERRUPT1) {
if(intFunc[EXTERNAL_INT_1])
intFunc[EXTERNAL_INT_1]();
}
SIGNAL(SIG_INTERRUPT2) {
if(intFunc[EXTERNAL_INT_2])
intFunc[EXTERNAL_INT_2]();
}
SIGNAL(SIG_INTERRUPT3) {
if(intFunc[EXTERNAL_INT_3])
intFunc[EXTERNAL_INT_3]();
}
SIGNAL(SIG_INTERRUPT4) {
if(intFunc[EXTERNAL_INT_4])
intFunc[EXTERNAL_INT_4]();
}
SIGNAL(SIG_INTERRUPT5) {
if(intFunc[EXTERNAL_INT_5])
intFunc[EXTERNAL_INT_5]();
}
SIGNAL(SIG_INTERRUPT6) {
if(intFunc[EXTERNAL_INT_6])
intFunc[EXTERNAL_INT_6]();
}
SIGNAL(SIG_INTERRUPT7) {
if(intFunc[EXTERNAL_INT_7])
intFunc[EXTERNAL_INT_7]();
}
/*SIGNAL(SIG_2WIRE_SERIAL) {
if(twiIntFunc)
twiIntFunc();
}*/
/* onHAIwakeUP(void) - setup the default interrupt for the High Activate Interrupts
*
* It setups the default interrupt for the High Activate Interrupts. There are some modules that activates interruptions
* on HIGH. These modules are Accelerometer, UART1 (GPRS) and other additional modules like sensors.
*
* This subrutine is executed when the interruption is detected on the corresponding microcontroller pin.
*
* We have to check 'intConf' flag and the monitorization pin, to know what module has activated the interruption, due to
* more than one module is multiplexed on the same microcontroller pin. When the two conditions match, 'intFlag' is activated
* on the correct position to show the module that has activated the interruption.
* A counter called 'intCounter' is incremented each time an interruption is detected.
* A counter array called 'intArray' is incremented in the correct position to know how many times a module has activated
* the interruption.
*/
void onHAIwakeUP(void)
{
cli();
// used to update the interrupt flag
if( intConf & ACC_INT )
{
if( digitalRead(ACC_INT_PIN_MON) )
{
intCounter++;
intFlag |= ACC_INT;
intArray[ACC_POS]++;
}
}
if( intConf & RTC_INT )
{
if( digitalRead(RTC_INT_PIN_MON) )
{
intCounter++;
intFlag |= RTC_INT;
intArray[RTC_POS]++;
}
}
if( intConf & UART1_INT )
{
if( digitalRead(UART1_INT_PIN_MON) )
{
intCounter++;
intFlag |= UART1_INT;
intArray[UART1_POS]++;
}
}
if( intConf & HAI_INT )
{
if( digitalRead(HAI_INT_PIN_MON) )
{
intCounter++;
intFlag |= HAI_INT;
intArray[HAI_POS]++;
}
}
if( intConf & SENS_INT )
{
if( digitalRead(SENS_INT_PIN_MON) )
{
intCounter++;
digitalWrite(SENS_INT_ENABLE,LOW);
intFlag |= SENS_INT;
intArray[SENS_POS]++;
}
}
if( intConf & ANE_INT )
{
if( !( (intConf & ACC_INT) && digitalRead(ACC_INT_PIN_MON) ) && !( (intConf & RTC_INT) && digitalRead(RTC_INT_PIN_MON) ) && !( (intConf & SENS_INT) && digitalRead(SENS_INT_PIN_MON) ) )
{
intCounter++;
intFlag |= ANE_INT;
intArray[SENS2_POS]++;
}
}
sei();
}
/* onLAIwakeUP(void) - setup the default interrupt for the Low Activate Interrupts
*
* It setups the default interrupt for the Low Activate Interrupts. There are some modules that activates interruptions
* on LOW. These modules are RTC, Low Battery, internal Watchdog and other additional modules like sensors.
*
* This subrutine is executed when the interruption is detected on the corresponding microcontroller pin.
*
* We have to check 'intConf' flag and the monitorization pin, to know what module has activated the interruption, due to
* more than one module is multiplexed on the same microcontroller pin. When the two conditions match, 'intFlag' is activated
* on the correct position to show the module that has activated the interruption.
* A counter called 'intCounter' is incremented each time an interruption is detected.
* A counter array called 'intArray' is incremented in the correct position to know how many times a module has activated
* the interruption.
*/
void onLAIwakeUP(void)
{
cli();
// used to update the interrupt flag
if( intConf & BAT_INT )
{
if( !digitalRead(BAT_INT_PIN_MON) )
{
intCounter++;
intFlag |= BAT_INT;
intArray[BAT_POS]++;
disableInterrupts(BAT_INT);
}
}
if( intConf & WTD_INT )
{
if( !digitalRead(WTD_INT_PIN_MON) )
{
intCounter++;
intFlag |= WTD_INT;
intArray[WTD_POS]++;
digitalWrite(WTD_INT_PIN_MON,HIGH);
}
}
if( intConf & LAI_INT )
{
if( !digitalRead(LAI_INT_PIN_MON) )
{
intCounter++;
intFlag |= LAI_INT;
intArray[LAI_POS]++;
}
}
if( intConf & PLV_INT )
{
if( ( !(intConf & BAT_INT) || !digitalRead(BAT_INT_PIN_MON) ) && ( !(intConf & WTD_INT) || !digitalRead(WTD_INT_PIN_MON) ) )
{
intCounter++;
intFlag |= PLV_INT;
intArray[SENS2_POS]++;
}
}
sei();
}
/* clearIntFlag() - clears 'intFlag' global variable
*
*/
void clearIntFlag()
{
intFlag=0;
}
/* enableInterrupts( conf ) - enables the specified interruption
*
* It enables the specified interruption by 'conf' input.
*
* When this function is called, 'intConf' flag is updated with the new active interruption. After that, it is attached to
* the corresponding microcontroller pin and associated subrutine.
*/
void enableInterrupts(uint16_t conf)
{
intConf |= conf;
if( conf & HAI_INT )
{
pinMode(MUX_RX,INPUT);
attachInterrupt(HAI_INT_ACT, onHAIwakeUP, HIGH);
}
if( conf & LAI_INT )
{
pinMode(MUX_TX, INPUT);
attachInterrupt(LAI_INT_ACT, onLAIwakeUP, LOW);
}
if( conf & ACC_INT )
{
pinMode(MUX_RX,INPUT);
pinMode(ACC_INT_PIN_MON, INPUT);
attachInterrupt(ACC_INT_ACT, onHAIwakeUP, HIGH);
}
if( conf & BAT_INT )
{
pinMode(MUX_TX, INPUT);
pinMode(BAT_INT_PIN_MON,INPUT);
digitalWrite(MUX_TX, HIGH);
attachInterrupt(BAT_INT_ACT, onLAIwakeUP, LOW);
}
if( conf & RTC_INT )
{
pinMode(MUX_RX, INPUT);
pinMode(RTC_INT_PIN_MON,INPUT);
attachInterrupt(RTC_INT_ACT, onHAIwakeUP, HIGH);
}
if( conf & WTD_INT )
{
pinMode(WTD_INT_PIN_MON,OUTPUT);
digitalWrite(WTD_INT_PIN_MON,HIGH);
attachInterrupt(WTD_INT_ACT, onLAIwakeUP, LOW);
}
if( conf & UART1_INT )
{
pinMode(MUX_RX, INPUT);
pinMode(UART1_INT_PIN_MON,INPUT);
attachInterrupt(UART1_INT_ACT, onHAIwakeUP, HIGH);
}
if( conf & SENS_INT )
{
pinMode(MUX_RX, INPUT);
pinMode(SENS_INT_PIN_MON,INPUT);
attachInterrupt(SENS_INT_ACT, onHAIwakeUP, HIGH);
}
if( conf & ANE_INT )
{
pinMode(MUX_RX, INPUT);
pinMode(MUX_TX, INPUT);
pinMode(SENS2_INT_PIN_MON,INPUT);
pinMode(SENS2_INT_PIN2_MON,INPUT);
attachInterrupt(ANE_INT_ACT, onHAIwakeUP, HIGH);
}
if( conf & PLV_INT )
{
pinMode(MUX_RX, INPUT);
pinMode(MUX_TX, INPUT);
pinMode(SENS2_INT_PIN_MON,INPUT);
pinMode(SENS2_INT_PIN2_MON,INPUT);
attachInterrupt(PLV_INT_ACT, onLAIwakeUP, LOW);
}
}
/* disableInterrupts( conf ) - disables the specified interruption
*
* It disables the specified interruption by 'conf' input.
*
* When this function is called, 'intConf' flag is updated with the interruption that has been detached. After that, it is
* deatached from the corresponding microcontroller pin and associated subrutine.
*/
void disableInterrupts(uint16_t conf)
{
cli();
if( conf & HAI_INT )
{
detachInterrupt(HAI_INT_ACT);
}
if( conf & LAI_INT )
{
detachInterrupt(LAI_INT_ACT);
}
if( conf & ACC_INT )
{
detachInterrupt(ACC_INT_ACT);
}
if( conf & BAT_INT )
{
detachInterrupt(BAT_INT_ACT);
}
if( conf & RTC_INT )
{
detachInterrupt(RTC_INT_ACT);
}
if( conf & UART1_INT )
{
detachInterrupt(UART1_INT_ACT);
}
if( conf & WTD_INT )
{
detachInterrupt(WTD_INT_ACT);
}
if( conf & SENS_INT )
{
detachInterrupt(SENS_INT_ACT);
}
if( conf & ANE_INT )
{
detachInterrupt(ANE_INT_ACT);
}
if( conf & PLV_INT )
{
detachInterrupt(PLV_INT_ACT);
}
intConf &= ~(conf);
sei();
}