00001 /** 00002 * \file 00003 * EEPROM functions. 00004 * \author Adam Dunkels <adam@sics.se> 00005 */ 00006 00007 /* Copyright (c) 2004 Swedish Institute of Computer Science. 00008 * All rights reserved. 00009 * 00010 * Redistribution and use in source and binary forms, with or without modification, 00011 * are permitted provided that the following conditions are met: 00012 * 00013 * 1. Redistributions of source code must retain the above copyright notice, 00014 * this list of conditions and the following disclaimer. 00015 * 2. Redistributions in binary form must reproduce the above copyright notice, 00016 * this list of conditions and the following disclaimer in the documentation 00017 * and/or other materials provided with the distribution. 00018 * 3. The name of the author may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00024 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00026 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00029 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00030 * OF SUCH DAMAGE. 00031 * 00032 * $Id: eeprom.c,v 1.1 2006/06/18 07:49:33 adamdunkels Exp $ 00033 * 00034 * Author: Adam Dunkels <adam@sics.se> 00035 * 00036 */ 00037 00038 /* 00039 Copyright 2003/2004, Freie Universitaet Berlin. All rights reserved. 00040 00041 These sources were developed at the Freie Universit\x{FFFF}t Berlin, Computer 00042 Systems and Telematics group. 00043 00044 Redistribution and use in source and binary forms, with or without 00045 modification, are permitted provided that the following conditions are 00046 met: 00047 00048 - Redistributions of source code must retain the above copyright 00049 notice, this list of conditions and the following disclaimer. 00050 00051 - Redistributions in binary form must reproduce the above copyright 00052 notice, this list of conditions and the following disclaimer in the 00053 documentation and/or other materials provided with the distribution. 00054 00055 - Neither the name of Freie Universitaet Berlin (FUB) nor the names of its 00056 contributors may be used to endorse or promote products derived from 00057 this software without specific prior written permission. 00058 00059 This software is provided by FUB and the contributors on an "as is" 00060 basis, without any representations or warranties of any kind, express 00061 or implied including, but not limited to, representations or 00062 warranties of non-infringement, merchantability or fitness for a 00063 particular purpose. In no event shall FUB or contributors be liable 00064 for any direct, indirect, incidental, special, exemplary, or 00065 consequential damages (including, but not limited to, procurement of 00066 substitute goods or services; loss of use, data, or profits; or 00067 business interruption) however caused and on any theory of liability, 00068 whether in contract, strict liability, or tort (including negligence 00069 or otherwise) arising in any way out of the use of this software, even 00070 if advised of the possibility of such damage. 00071 00072 This implementation was developed by the CST group at the FUB. 00073 Contributors: Thomas Pietsch, Bjoern Lichtblau 00074 00075 For documentation and questions please use the web site 00076 http://www.scatterweb.net and the mailinglist 00077 scatterweb@lists.spline.inf.fu-berlin.de (subscription via the Website). 00078 Berlin, 2003/2004 00079 */ 00080 00081 #include <msp430x14x.h> 00082 #include <io.h> 00083 00084 #include "dev/eeprom.h" 00085 00086 /* Temporary switch for the eeprom address. */ 00087 #define EEPROMADDRESS (0x00) /* use 8k EEPROM, future versions will have only one 64k eeprom at this address */ 00088 /*#define EEPROMADDRESS (0x02)*/ /* use 64k EEPROM */ 00089 00090 /* must be set together with EEPROMADDRESS */ 00091 /*#define EEPROMPAGEMASK (0x1F) */ /* 8k EEPROM, 32b page writes possible */ 00092 #define EEPROMPAGEMASK (0x7F) /* 64k EEPROM, 128b page writes possible */ 00093 00094 00095 00096 /* 00097 * Macros for accessing the clock and data lines. Data is on P56 and 00098 * clock on P57. 00099 */ 00100 #define SDA_HIGH (P5OUT |= 0x04) /**< EEPROM data line high */ 00101 #define SDA_LOW (P5OUT &= 0xFB) /**< EEPROM data line low */ 00102 #define SCL_HIGH (P5OUT |= 0x08) /**< EEPROM clock line high */ 00103 #define SCL_LOW (P5OUT &= 0xF7) /**< EEPROM clock line low */ 00104 00105 00106 /*-----------------------------------------------------------------------------------*/ 00107 /** 00108 * \internal \name Basic functions for interfacing the i2c-like EEPROM bus. 00109 */ 00110 /** @{ */ 00111 00112 /** 00113 * \internal 00114 * Put start condition on the bus. 00115 */ 00116 static void 00117 start(void) 00118 { 00119 P5DIR |= 0x0C; /* ensure: P52(SDA), P53(SCL) output */ 00120 SCL_LOW; _NOP(); _NOP(); 00121 SDA_HIGH; _NOP(); _NOP(); 00122 SCL_HIGH; _NOP(); _NOP(); 00123 SDA_LOW; _NOP(); _NOP(); 00124 SCL_LOW; _NOP(); _NOP(); 00125 } 00126 00127 /*-----------------------------------------------------------------------------------*/ 00128 /** 00129 * \internal 00130 * Put stop condition on the bus. 00131 */ 00132 static void 00133 stop(void) 00134 { 00135 //P5DIR |= 0x0C; /* ensure: P52(SDA), P53(SCL) output */ 00136 SCL_LOW; _NOP(); _NOP(); 00137 SDA_LOW; _NOP(); _NOP(); 00138 SCL_HIGH; _NOP(); _NOP(); 00139 SDA_HIGH; _NOP(); _NOP(); 00140 SCL_LOW; _NOP(); _NOP(); 00141 P5DIR &= ~0x0C; 00142 } 00143 /*-----------------------------------------------------------------------------------*/ 00144 /** 00145 * \internal 00146 * Write a byte on the bus, return the acknowledge bit. 00147 */ 00148 static int 00149 write_bus(unsigned char byte) 00150 { 00151 int i, ack; 00152 00153 /* Write byte, one bit at a time. Start with the leftmost (most 00154 significant) bit and roll in bits from the right. */ 00155 for(i = 0; i < 8; ++i) { 00156 if(byte & 0x80) { 00157 SDA_HIGH; 00158 } else { 00159 SDA_LOW; 00160 } 00161 _NOP(); 00162 _NOP(); 00163 SCL_HIGH; 00164 _NOP(); 00165 _NOP(); 00166 byte = byte << 1; 00167 SCL_LOW; 00168 _NOP(); 00169 _NOP(); 00170 } 00171 00172 /* check ack */ 00173 P5DIR &= 0xFB; /* P52(SDA) input */ 00174 SCL_HIGH; 00175 _NOP(); 00176 _NOP(); 00177 if(P5IN & 0x04) { 00178 ack = 0; 00179 } else { 00180 ack = 1; /* test if ack=0, else error */ 00181 } 00182 SCL_LOW; 00183 _NOP(); 00184 _NOP(); 00185 P5DIR |= 0x04; /* P52(SDA) output */ 00186 _NOP(); 00187 _NOP(); 00188 _NOP(); 00189 return ack; 00190 } 00191 /*-----------------------------------------------------------------------------------*/ 00192 /** 00193 * \internal 00194 * Read one byte from the bus. 00195 * 00196 * \param ack If set, the ackbit after the received byte will be set. 00197 */ 00198 static unsigned char 00199 read_bus(unsigned char ack) 00200 { 00201 int i; 00202 unsigned char byte = 0; 00203 00204 P5DIR &= 0xFB; /* P52(SDA) input */ 00205 00206 for(i = 0; i < 8; ++i) { 00207 byte = byte << 1; 00208 SCL_HIGH; 00209 _NOP(); 00210 _NOP(); 00211 if(P5IN & 0x04) { 00212 byte |= 0x01; 00213 } else { 00214 byte &= 0xFE; 00215 } 00216 _NOP(); 00217 SCL_LOW; 00218 _NOP(); 00219 _NOP(); 00220 } 00221 00222 P5DIR |= 0x04; /* P52(SDA) output */ 00223 if(ack) { 00224 SDA_LOW; 00225 } else { 00226 SDA_HIGH; 00227 } 00228 _NOP(); 00229 SCL_HIGH; 00230 _NOP(); 00231 SCL_LOW; 00232 _NOP(); 00233 return byte; 00234 } 00235 /** @} */ 00236 /*-----------------------------------------------------------------------------------*/ 00237 /** 00238 * Read bytes from the EEPROM using sequential read. 00239 */ 00240 void 00241 eeprom_read(unsigned short addr, unsigned char *buf, int size) 00242 { 00243 unsigned int i; 00244 00245 if(size <= 0) { 00246 return; 00247 } 00248 00249 do { 00250 /* Wait if the writecycle has not finished. */ 00251 start(); 00252 /* 1010 control, 000 address, 0=write --- but only inits address */ 00253 } while(!write_bus(0xa0 | EEPROMADDRESS)); 00254 00255 00256 /* Write address to bus, low byte first. */ 00257 write_bus(addr >> 8); 00258 write_bus(addr & 0xff); 00259 start(); 00260 /* 1010 control, 000 address, 1=read */ 00261 write_bus(0xa1 | EEPROMADDRESS); 00262 00263 for(i = 0; i < (size - 1); ++i){ 00264 buf[i] = read_bus(1); 00265 } 00266 buf[size - 1] = read_bus(0); 00267 stop(); 00268 } 00269 /*-----------------------------------------------------------------------------------*/ 00270 /** 00271 * Write bytes to EEPROM using sequencial write. 00272 */ 00273 void 00274 eeprom_write(unsigned short addr, unsigned char *buf, 00275 int size) 00276 { 00277 unsigned int i = 0; 00278 unsigned int curaddr; 00279 00280 if(size <= 0) { 00281 return; 00282 } 00283 00284 /* Disable write protection. */ 00285 P5OUT &= 0xEF; 00286 00287 curaddr = addr; 00288 for(i = 0; i < size; ++i) { 00289 /* If we are writing the first byte or are on a 128b page boundary 00290 we have to start a new write. */ 00291 if(i == 0 || (curaddr & EEPROMPAGEMASK) == 0) { 00292 do { 00293 start(); 00294 /* 1010 control, 000 addresse, 0=write */ 00295 } while(!write_bus(0xa0 | EEPROMADDRESS)); 00296 00297 /* Write the new address to the bus. */ 00298 if(write_bus(curaddr >> 8) == 0) { 00299 return; 00300 } 00301 if(write_bus(curaddr) == 0) { 00302 return; 00303 } 00304 } 00305 00306 /* Write byte. */ 00307 if(write_bus(buf[i]) == 0) { 00308 return; 00309 } 00310 00311 /* If we are writing the last byte totally or of a 128b page 00312 generate a stop condition */ 00313 if(i == size - 1 || (curaddr & EEPROMPAGEMASK) == EEPROMPAGEMASK) { 00314 stop(); 00315 } 00316 00317 ++curaddr; 00318 } 00319 00320 /* Enable write protection. */ 00321 P5OUT |= 0x10; 00322 } 00323 00324 /*-----------------------------------------------------------------------------------*/