/* * Copyright (c) 2009, Swedish Institute of Computer Science * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS 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. * * This file is part of the Contiki operating system. * * @(#)$Id: irq.c,v 1.4 2010/01/14 17:39:35 nifi Exp $ */ #include "lib/sensors.h" #include "dev/irq.h" #include "dev/lpm.h" #include #define ADC12MCTL_NO(adcno) ((unsigned char *) ADC12MCTL0_)[adcno] static int (* adc12_irq[8])(void); static int (* port1_irq[8])(void); static unsigned char adcflags; /*---------------------------------------------------------------------------*/ interrupt(PORT1_VECTOR) irq_p1(void) { int i; ENERGEST_ON(ENERGEST_TYPE_IRQ); for(i = 0; i < 8; i++) { if((P1IFG & (1 << i)) && port1_irq[i] != NULL) { if((port1_irq[i])()) { LPM4_EXIT; } } } P1IFG = 0x00; ENERGEST_OFF(ENERGEST_TYPE_IRQ); } /*---------------------------------------------------------------------------*/ interrupt (ADC_VECTOR) irq_adc(void) { int i; ENERGEST_ON(ENERGEST_TYPE_IRQ); for(i = 0; i < 8; i++) { if(adc12_irq[i] != NULL) { if((adc12_irq[i])()) { LPM4_EXIT; } } } ENERGEST_OFF(ENERGEST_TYPE_IRQ); } /*---------------------------------------------------------------------------*/ void irq_init(void) { int i; adcflags = 0; for(i = 0; i < 8; i++) { adc12_irq[i] = NULL; port1_irq[i] = NULL; } /* Setup ADC12, ref., sampling time */ ADC12CTL0 = REF2_5V | SHT0_10 | SHT1_10 | MSC; /* Use sampling timer, repeat-sequence-of-channels */ /* ADC12CTL1 = SHP | CONSEQ_3 | ADC12DIV_3; */ ADC12CTL1 = SHP | CONSEQ_3 | ADC12DIV_7; } /*---------------------------------------------------------------------------*/ void irq_port1_activate(unsigned char irqno, int (* irq)(void)) { if(irqno < 8) { port1_irq[irqno] = irq; } } /*---------------------------------------------------------------------------*/ void irq_port1_deactivate(unsigned char irqno) { if(irqno < 8) { port1_irq[irqno] = NULL; } } /*---------------------------------------------------------------------------*/ /* Set lowest ADC to be start in sequence and highest to be interrupt enabled and set end-of-sequence on the highest active ADC */ static void sethilo(void) { int c; /* Clear start of sequence */ ADC12CTL1 &= ~(CSTARTADD_15); /* Set new start of sequence to lowest active memory holder */ for(c = 0; c < 8; c++) { if(adcflags & (1 << c)) { ADC12CTL1 |= (c * CSTARTADD_1); break; } } /* Clear all interrupts and end-of-sequences */ ADC12IE = 0; for(c = 0; c < 8; c++) { ADC12MCTL_NO(c) &= ~EOS; } /* Set highest interrupt and end-of-sequence. This will generate one interrupt for each sequence of conversions. */ for(c = 0; c < 8; c++) { if(adcflags & (128 >> c)) { ADC12IE |= 128 >> c; ADC12MCTL_NO(7 - c) |= EOS; break; } } } /*---------------------------------------------------------------------------*/ void irq_adc12_activate(unsigned char adcno, unsigned char config, int (* irq)(void)) { if(adcno >= 8) { return; } /* stop converting */ ADC12CTL0 &= ~ENC; /* wait for conversion to stop */ while(ADC12CTL0 & ADC12BUSY); ADC12CTL0 &= ~(ADC12ON | REFON); ADC12IE = 0; /* clear any pending interrupts */ ADC12IFG = 0; adcflags |= (1 << adcno); ADC12MCTL_NO(adcno) = config; sethilo(); ADC12CTL0 |= ADC12ON | REFON; adc12_irq[adcno] = irq; /* Delay */ clock_delay(20000); ADC12CTL0 |= ENC | ADC12SC; } /*---------------------------------------------------------------------------*/ void irq_adc12_deactivate(unsigned char adcno) { if(adcno >= 8) { return; } /* stop converting */ ADC12CTL0 &= ~ENC; /* wait for conversion to stop */ while(ADC12CTL0 & ADC12BUSY); ADC12CTL0 &= ~(ADC12ON | REFON); ADC12IE = 0; /* clear any pending interrupts */ ADC12IFG = 0; adcflags &= ~(1 << adcno); ADC12MCTL_NO(adcno) = 0; sethilo(); adc12_irq[adcno] = NULL; if(adcflags) { /* Turn on the ADC12 */ ADC12CTL0 |= (ADC12ON | REFON); /* Delay */ clock_delay(20000); /* Still active. Turn on the conversion. */ ADC12CTL0 |= ENC | ADC12SC; } } /*---------------------------------------------------------------------------*/ int irq_adc12_active(unsigned char adcno) { return adcflags & (1 << adcno) ? 1 : 0; } /*---------------------------------------------------------------------------*/