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 /*---------------------------------------------------------------------------*/