Contiki 2.6

adc-sensor.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010, Loughborough University - Computer Science
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * This file is part of the Contiki operating system.
00030  */
00031 
00032 /**
00033  * \file
00034  *         ADC sensor module for sensinode devices.
00035  *
00036  *         This file respects configuration in contiki-conf.h. It also turns
00037  *         off features which are not present in the model that we are
00038  *         building for.
00039  *
00040  * \author
00041  *         George Oikonomou - <oikonomou@users.sourceforge.net>
00042  */
00043 #include "dev/sensinode-sensors.h"
00044 
00045 #if ADC_SENSOR_ON
00046 SENSORS_SENSOR(adc_sensor, ADC_SENSOR, value, configure, status);
00047 
00048 static uint8_t ready;
00049 
00050 /*---------------------------------------------------------------------------*/
00051 static int
00052 value(int type)
00053 {
00054   uint16_t reading;
00055   /*
00056    * For single-shot AD conversions, we may only write to ADCCON3[3:0] once
00057    * (This write triggers the conversion). We thus use the variable 'command'
00058    * to store intermediate steps (reference, decimation rate, input channel)
00059    */
00060   uint8_t command;
00061 
00062   ADCCFG = 0; /* Enables/Disables Input Channel */
00063 
00064   /* 1.25V ref, max decimation rate */
00065   command = ADEDIV1 | ADEDIV0;
00066 
00067   /* Clear the Interrupt Flag */
00068   TCON_ADCIF = 0;
00069 
00070   /* Depending on the desired reading, append the input bits to 'command' and
00071    * enable the corresponding input channel in ADCCFG if necessary */
00072   switch(type) {
00073 #if TEMP_SENSOR_ON
00074   case ADC_SENSOR_TYPE_TEMP:
00075     command |= ADECH3 | ADECH2 | ADECH1;
00076     break;
00077 #endif
00078 #if ACC_SENSOR_ON
00079   case ADC_SENSOR_TYPE_ACC_X:
00080     ADCCFG = ADC5EN;
00081     command |= ADECH2 | ADECH0;
00082     break;
00083   case ADC_SENSOR_TYPE_ACC_Y:
00084     ADCCFG = ADC6EN;
00085     command |= ADECH2 | ADECH1;
00086     break;
00087   case ADC_SENSOR_TYPE_ACC_Z:
00088     ADCCFG = ADC7EN;
00089     command |= ADECH2 | ADECH1 | ADECH0;
00090     break;
00091 #endif
00092 #if VDD_SENSOR_ON
00093   case ADC_SENSOR_TYPE_VDD:
00094     command |= ADECH3 | ADECH2 | ADECH1 | ADECH0;
00095     break;
00096 #endif
00097 #if LIGHT_SENSOR_ON
00098   case ADC_SENSOR_TYPE_LIGHT:
00099     ADCCFG = ADC0EN;
00100     break;
00101 #endif
00102 #if BATTERY_SENSOR_ON
00103   case ADC_SENSOR_TYPE_BATTERY:
00104     ADCCFG = ADC1EN;
00105     command |= ADECH0 | ADEREF1; /* AVDD_SOC reference */
00106     break;
00107 #endif
00108   default:
00109     /* If the sensor is not present or disabled in conf, return -1 */
00110     return -1;
00111   }
00112 
00113   /* Writing in bits 3:0 of ADCCON3 will trigger a single conversion */
00114   ADCCON3 = command;
00115 
00116   /*
00117    * When the conversion is complete, the ADC interrupt flag is set. We don't
00118    * use an ISR here, we just wait on the flag and clear it afterwards.
00119    */
00120   while(!TCON_ADCIF);
00121 
00122   /* Clear the Interrupt Flag */
00123   TCON_ADCIF = 0;
00124 
00125   reading = 0;
00126   reading = ADCL;
00127   reading |= (((uint8_t) ADCH) << 8);
00128   /* 12-bit decimation rate: 4 LS bits are noise */
00129   reading >>= 4;
00130 
00131   return reading;
00132 }
00133 /*---------------------------------------------------------------------------*/
00134 static int
00135 status(int type)
00136 {
00137     return ready;
00138   }
00139 /*---------------------------------------------------------------------------*/
00140 /*
00141  * On N740 we can control Ill and Acc individually:
00142  * ADC_VAL_OTHERS     0x01
00143  * ADC_VAL_LIGHT_ON   0x04
00144  * ADC_VAL_ACC_ON     0x08
00145  * ADC_VAL_ACC_GSEL   0x10
00146  *
00147  * Return Value is always light | acc | acc_gsel
00148  *
00149  * SENSORS_ACTIVE:
00150  *   - 1: Activate everything, use default setting for ACC G-select
00151  *   - 0: Turn everything off
00152  *   - xyz: Mask with the defines above and act accordingly.
00153  *
00154  * SENSORS_READY:
00155  *   - Return Status (0: all off or a value based on the defines above)
00156  */
00157 static int
00158 configure(int type, int value)
00159 {
00160 #ifdef MODEL_N740
00161   /*
00162    * Read current state of the ser-par, ignoring current sensor settings
00163    * Those will be set all over depending on VALUE
00164    */
00165   uint8_t ser_par_val = n740_ser_par_get() & 0xF2;
00166 #endif /* MODEL_N740 */
00167 
00168   /* 'Others' are either compiled in or not. Can't be turned on/off */
00169   ready = ADC_VAL_ALL;
00170 
00171   switch(type) {
00172   case SENSORS_HW_INIT:
00173   case SENSORS_ACTIVE:
00174 #ifdef MODEL_N740
00175     if(value == ADC_VAL_ALL) {
00176       value = ADC_VAL_ACC_ON | ADC_VAL_LIGHT_ON;
00177 #if ACC_SENSOR_GSEL
00178       value |= ADC_VAL_ACC_GSEL;
00179 #endif /* ACC_SENSOR_GSEL */
00180     }
00181 #endif /* MODEL_N740 */
00182 
00183     /* OK, Now value definitely specifies our bits, start masking
00184      * We will refuse to turn things on if they are specified OFF in conf. */
00185 #ifdef MODEL_N740
00186 #if ACC_SENSOR_ON
00187     if(value & ADC_VAL_ACC_ON) {
00188       P0SEL |= 0x80 | 0x40 | 0x20;
00189       ser_par_val |= N740_SER_PAR_ACC;
00190       ready |= ADC_VAL_ACC_ON;
00191 #if ACC_SENSOR_GSEL
00192       if(value & ADC_VAL_ACC_GSEL) {
00193         ser_par_val |= N740_SER_PAR_ACC_GSEL;
00194         ready |= ADC_VAL_ACC_GSEL;
00195       }
00196 #endif /*ACC_SENSOR_GSEL */
00197     }
00198 #endif /* ACC_SENSOR_ON */
00199 
00200 #if LIGHT_SENSOR_ON
00201     if(value & ADC_VAL_LIGHT_ON) {
00202       ser_par_val |= N740_SER_PAR_LIGHT;
00203       ready |= ADC_VAL_LIGHT_ON;
00204     }
00205 #endif /* LIGHT_SENSOR_ON */
00206       n740_ser_par_set(ser_par_val);
00207 #endif /* MODEL_N740 */
00208     }
00209   return ready;
00210 }
00211 
00212 #endif /* ADC_SENSOR_ON */