Contiki 2.6

ds2401.c

00001 /*
00002  * Copyright (c) 2009, University of Colombo School of Computing
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 /*
00034  * Device driver for the Dallas Semiconductor DS2401 chip. Heavily
00035  * based on the application note 126 "1-Wire Communications Through
00036  * Software".
00037  *
00038  * http://www.maxim-ic.com/appnotes.cfm/appnote_number/126
00039  */
00040 
00041 /*
00042  * For now we stuff in Crossbow Technology, Inc's unique OUI.
00043  * 00:1A:4C    Crossbow Technology, Inc
00044  *
00045  * The EUI-64 is a concatenation of the 24-bit OUI value assigned by
00046  * the IEEE Registration Authority and a 40-bit extension identifier
00047  * assigned by the organization with that OUI assignment.
00048  */
00049 
00050 #include <avr/io.h>
00051 #include <string.h>
00052 #include "contiki.h"
00053 
00054 #include "ds2401.h"
00055 
00056 unsigned char ds2401_id[8];
00057 
00058 /* 1-wire is at PortA.4 */
00059 #define SERIAL_ID_PIN_READ PINA
00060 #define SERIAL_ID_PIN_MASK _BV(4)
00061 #define SERIAL_ID_PxOUT PORTA
00062 #define SERIAL_ID_PxDIR DDRA
00063 
00064 #define SET_PIN_INPUT() (SERIAL_ID_PxDIR &= ~SERIAL_ID_PIN_MASK)
00065 #define SET_PIN_OUTPUT() (SERIAL_ID_PxDIR |= SERIAL_ID_PIN_MASK)
00066 
00067 #define OUTP_0() (SERIAL_ID_PxOUT &= ~SERIAL_ID_PIN_MASK)
00068 #define OUTP_1() (SERIAL_ID_PxOUT |= SERIAL_ID_PIN_MASK) 
00069 
00070 #define PIN_INIT() do{  \
00071                      SET_PIN_INPUT();    \
00072                      OUTP_0();           \
00073                    } while(0)
00074 
00075 
00076 /* Drive the one wire interface low */
00077 #define OW_DRIVE() do {                    \
00078                      SET_PIN_OUTPUT();     \
00079                      OUTP_0();             \
00080                    } while (0)
00081 
00082 /* Release the one wire by turning on the internal pull-up. */
00083 #define OW_RELEASE() do {                  \
00084                        SET_PIN_INPUT();    \
00085                        OUTP_1();           \
00086                      } while (0)
00087 
00088 /* Read one bit. */
00089 #define INP()  (SERIAL_ID_PIN_READ & SERIAL_ID_PIN_MASK)
00090 
00091 /*
00092  * Delay times in us.
00093  */
00094 #define tA 6          /* min-5, recommended-6, max-15 */              
00095 #define tB 64         /* min-59, recommended-64, max-N/A */
00096 #define tC 60         /* min-60, recommended-60, max-120 */                     
00097 #define tD 10         /* min-5.3, recommended-10, max-N/A */
00098 #define tE 9          /* min-0.3, recommended-9, max-9.3 */
00099 #define tF 55         /* min-50, recommended-55, max-N/A */
00100 #define tG 0          /* min-0, recommended-0, max-0 */
00101 #define tH 480        /* min-480, recommended-480, max-640 */
00102 #define tI 70         /* min-60.3, recommended-70, max-75.3 */
00103 #define tJ 410        /* min-410, recommended-410, max-N/A */
00104 /*---------------------------------------------------------------------------*/
00105 /*
00106  * The delay caused by calling the delay_loop is given by the following
00107  * formula.
00108  *           delay(us) = (4n + 1)/XTAL
00109  * where n is the number of iterations and XTAL is the clock frequency(in MHz). 
00110  * TODO: Moving the delay_loop to dev/clock.c
00111  */
00112 static void
00113 delay_loop(uint16_t __count)
00114 {
00115   asm volatile ("1: sbiw %0,1" "\n\t"
00116                 "brne 1b"
00117                 : "=w" (__count)
00118                 : "0" (__count)
00119                );
00120 }
00121 /*---------------------------------------------------------------------------*/
00122 /*
00123  * This macro relies on the compiler doing the arithmetic during compile time
00124  * for the needed iterations.!!
00125  * In MICAz, XTAL = 7.3728 MHz
00126  */
00127 #define udelay(u) delay_loop(((7.3728F * u)-1)/4)
00128 /*---------------------------------------------------------------------------*/
00129 static uint8_t
00130 reset(void)
00131 {
00132   uint8_t result;
00133   OW_DRIVE();
00134   udelay(500);     /* 480 < tH < 640 */
00135   OW_RELEASE();    /* Releases the bus */
00136   udelay(tI);
00137   result = INP();
00138   udelay(tJ);
00139   return result;
00140 }
00141 /*---------------------------------------------------------------------------*/
00142 static void
00143 write_byte(uint8_t byte)
00144 {
00145   uint8_t i = 7;
00146   do {
00147     if (byte & 0x01) {
00148       OW_DRIVE();
00149       udelay(tA);
00150       OW_RELEASE();    /* Releases the bus */
00151       udelay(tB);
00152     } else {
00153       OW_DRIVE();
00154       udelay(tC);
00155       OW_RELEASE();    /* Releases the bus */
00156       udelay(tD);
00157     }
00158     if (i == 0)
00159       return;
00160     i--;
00161     byte >>= 1;
00162   } while (1);
00163 }
00164 /*---------------------------------------------------------------------------*/
00165 static unsigned
00166 read_byte(void)
00167 {
00168   unsigned result = 0;
00169   int i = 7;
00170   do {
00171     OW_DRIVE();
00172     udelay(tA);
00173     OW_RELEASE();       /* Releases the bus */
00174     udelay(tE);
00175     if (INP())
00176       result |= 0x80;   /* LSbit first */
00177     udelay(tF);
00178     if (i == 0)
00179       return result;
00180     i--;
00181     result >>= 1;
00182   } while (1);
00183 }
00184 /*---------------------------------------------------------------------------*/
00185 /* Polynomial ^8 + ^5 + ^4 + 1 */
00186 static unsigned
00187 crc8_add(unsigned acc, unsigned byte)
00188 {
00189   int i;
00190   acc ^= byte;
00191   for (i = 0; i < 8; i++)
00192     if (acc & 1)
00193       acc = (acc >> 1) ^ 0x8c;
00194     else
00195       acc >>= 1;
00196 
00197   return acc;
00198 }
00199 /*---------------------------------------------------------------------------*/
00200 int
00201 ds2401_init()
00202 {
00203   int i;
00204   uint8_t volatile sreg;
00205   unsigned family, crc, acc;
00206 
00207   PIN_INIT();
00208 
00209   sreg = SREG;    /* Save status register before disabling interrupts. */
00210   cli();    /* Disable interrupts. */
00211 
00212   if (reset() == 0) {
00213     write_byte(0x33);    /* Read ROM command. */   
00214     family = read_byte();
00215     for (i = 7; i >= 2; i--) {
00216       ds2401_id[i] = read_byte();
00217     }
00218     crc = read_byte();
00219 
00220     SREG = sreg;    /* Enable interrupts. */
00221 
00222     if(family != 0x01) {
00223       goto fail;
00224     }
00225     acc = crc8_add(0x0, family);
00226     for (i = 7; i >= 2; i--) {
00227       acc = crc8_add(acc, ds2401_id[i]);
00228     }
00229     if (acc == crc) {
00230       /* 00:1A:4C    OUI for Crossbow Technology, Inc. */
00231       ds2401_id[0] = 0x00;
00232       ds2401_id[1] = 0x1A;
00233       ds2401_id[2] = 0x4C;
00234       return 1; /* Success! */
00235     }
00236   } else {
00237     SREG = sreg;    /* Enable interrupts. */
00238   }
00239 
00240 fail:
00241   memset(ds2401_id, 0x0, sizeof(ds2401_id));
00242   return 0;  /* Fail! */
00243 }
00244 /*---------------------------------------------------------------------------*/