twbbif.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005-2007 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
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 copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00082 #include <cfg/os.h>
00083 #include <cfg/twi.h>
00084 #include <cfg/arch/gpio.h>
00085 
00086 #include <dev/twif.h>
00087 
00088 #if defined(__arm__)
00089 
00090 #include <arch/arm.h>
00091 
00097 #if !defined(TWI_PIO_ID)
00098 #if defined(MCU_AT91SAM7X256) || defined(MCU_AT91SAM7S256)
00099 #define TWI_PIO_ID  PIOA_ID
00100 #elif defined(MCU_AT91SAM9260)
00101 #define TWI_PIO_ID  PIOB_ID
00102 #else
00103 #define TWI_PIO_ID  PIO_ID
00104 #endif
00105 #endif
00106 
00112 #ifndef TWI_SDA_BIT
00113 #if defined(MCU_AT91SAM9260)
00114 #define TWI_SDA_BIT     12
00115 #else
00116 #define TWI_SDA_BIT     10
00117 #endif
00118 #endif
00119 
00123 #ifndef TWI_DELAY
00124 #if defined(MCU_AT91SAM9260)
00125 #define TWI_DELAY   16
00126 #else
00127 #define TWI_DELAY   8
00128 #endif
00129 #endif
00130 
00136 #ifndef TWI_SCL_BIT
00137 #if defined(MCU_AT91SAM9260)
00138 #define TWI_SCL_BIT     13
00139 #else
00140 #define TWI_SCL_BIT     11
00141 #endif
00142 #endif
00143 
00149 #if TWI_PIO_ID == PIOA_ID
00150 
00151 #ifndef TWI_SDA_PE_REG
00152 #define TWI_SDA_PE_REG  PIOA_PER
00153 #endif
00154 #ifndef TWI_SDA_OE_REG
00155 #define TWI_SDA_OE_REG  PIOA_OER
00156 #endif
00157 #ifndef TWI_SDA_OD_REG
00158 #define TWI_SDA_OD_REG  PIOA_ODR
00159 #endif
00160 #ifndef TWI_SDA_COD_REG
00161 #define TWI_SDA_COD_REG PIOA_CODR
00162 #endif
00163 #ifndef TWI_SDA_SOD_REG
00164 #define TWI_SDA_SOD_REG PIOA_SODR
00165 #endif
00166 #ifndef TWI_SDA_PDS_REG
00167 #define TWI_SDA_PDS_REG PIOA_PDSR
00168 #endif
00169 
00170 #ifndef TWI_SCL_PE_REG
00171 #define TWI_SCL_PE_REG  PIOA_PER
00172 #endif
00173 #ifndef TWI_SCL_OE_REG
00174 #define TWI_SCL_OE_REG  PIOA_OER
00175 #endif
00176 #ifndef TWI_SCL_OD_REG
00177 #define TWI_SCL_OD_REG  PIOA_ODR
00178 #endif
00179 #ifndef TWI_SCL_COD_REG
00180 #define TWI_SCL_COD_REG PIOA_CODR
00181 #endif
00182 #ifndef TWI_SCL_SOD_REG
00183 #define TWI_SCL_SOD_REG PIOA_SODR
00184 #endif
00185 #ifndef TWI_SCL_PDS_REG
00186 #define TWI_SCL_PDS_REG PIOA_PDSR
00187 #endif
00188 
00189 #elif TWI_PIO_ID == PIOB_ID
00190 
00191 #ifndef TWI_SDA_PE_REG
00192 #define TWI_SDA_PE_REG  PIOB_PER
00193 #endif
00194 #ifndef TWI_SDA_OE_REG
00195 #define TWI_SDA_OE_REG  PIOB_OER
00196 #endif
00197 #ifndef TWI_SDA_OD_REG
00198 #define TWI_SDA_OD_REG  PIOB_ODR
00199 #endif
00200 #ifndef TWI_SDA_COD_REG
00201 #define TWI_SDA_COD_REG PIOB_CODR
00202 #endif
00203 #ifndef TWI_SDA_SOD_REG
00204 #define TWI_SDA_SOD_REG PIOB_SODR
00205 #endif
00206 #ifndef TWI_SDA_PDS_REG
00207 #define TWI_SDA_PDS_REG PIOB_PDSR
00208 #endif
00209 
00210 #ifndef TWI_SCL_PE_REG
00211 #define TWI_SCL_PE_REG  PIOB_PER
00212 #endif
00213 #ifndef TWI_SCL_OE_REG
00214 #define TWI_SCL_OE_REG  PIOB_OER
00215 #endif
00216 #ifndef TWI_SCL_OD_REG
00217 #define TWI_SCL_OD_REG  PIOB_ODR
00218 #endif
00219 #ifndef TWI_SCL_COD_REG
00220 #define TWI_SCL_COD_REG PIOB_CODR
00221 #endif
00222 #ifndef TWI_SCL_SOD_REG
00223 #define TWI_SCL_SOD_REG PIOB_SODR
00224 #endif
00225 #ifndef TWI_SCL_PDS_REG
00226 #define TWI_SCL_PDS_REG PIOB_PDSR
00227 #endif
00228 
00229 #elif TWI_PIO_ID == PIOC_ID
00230 
00231 #ifndef TWI_SDA_PE_REG
00232 #define TWI_SDA_PE_REG  PIOC_PER
00233 #endif
00234 #ifndef TWI_SDA_OE_REG
00235 #define TWI_SDA_OE_REG  PIOC_OER
00236 #endif
00237 #ifndef TWI_SDA_OD_REG
00238 #define TWI_SDA_OD_REG  PIOC_ODR
00239 #endif
00240 #ifndef TWI_SDA_COD_REG
00241 #define TWI_SDA_COD_REG PIOC_CODR
00242 #endif
00243 #ifndef TWI_SDA_SOD_REG
00244 #define TWI_SDA_SOD_REG PIOC_SODR
00245 #endif
00246 #ifndef TWI_SDA_PDS_REG
00247 #define TWI_SDA_PDS_REG PIOC_PDSR
00248 #endif
00249 
00250 #ifndef TWI_SCL_PE_REG
00251 #define TWI_SCL_PE_REG  PIOC_PER
00252 #endif
00253 #ifndef TWI_SCL_OE_REG
00254 #define TWI_SCL_OE_REG  PIOC_OER
00255 #endif
00256 #ifndef TWI_SCL_OD_REG
00257 #define TWI_SCL_OD_REG  PIOC_ODR
00258 #endif
00259 #ifndef TWI_SCL_COD_REG
00260 #define TWI_SCL_COD_REG PIOC_CODR
00261 #endif
00262 #ifndef TWI_SCL_SOD_REG
00263 #define TWI_SCL_SOD_REG PIOC_SODR
00264 #endif
00265 #ifndef TWI_SCL_PDS_REG
00266 #define TWI_SCL_PDS_REG PIOC_PDSR
00267 #endif
00268 
00269 #else
00270 
00271 #ifndef TWI_SDA_PE_REG
00272 #define TWI_SDA_PE_REG  PIO_PER
00273 #endif
00274 #ifndef TWI_SDA_OE_REG
00275 #define TWI_SDA_OE_REG  PIO_OER
00276 #endif
00277 #ifndef TWI_SDA_OD_REG
00278 #define TWI_SDA_OD_REG  PIO_ODR
00279 #endif
00280 #ifndef TWI_SDA_COD_REG
00281 #define TWI_SDA_COD_REG PIO_CODR
00282 #endif
00283 #ifndef TWI_SDA_SOD_REG
00284 #define TWI_SDA_SOD_REG PIO_SODR
00285 #endif
00286 #ifndef TWI_SDA_PDS_REG
00287 #define TWI_SDA_PDS_REG PIO_PDSR
00288 #endif
00289 
00290 #ifndef TWI_SCL_PE_REG
00291 #define TWI_SCL_PE_REG  PIO_PER
00292 #endif
00293 #ifndef TWI_SCL_OE_REG
00294 #define TWI_SCL_OE_REG  PIO_OER
00295 #endif
00296 #ifndef TWI_SCL_OD_REG
00297 #define TWI_SCL_OD_REG  PIO_ODR
00298 #endif
00299 #ifndef TWI_SCL_COD_REG
00300 #define TWI_SCL_COD_REG PIO_CODR
00301 #endif
00302 #ifndef TWI_SCL_SOD_REG
00303 #define TWI_SCL_SOD_REG PIO_SODR
00304 #endif
00305 #ifndef TWI_SCL_PDS_REG
00306 #define TWI_SCL_PDS_REG PIO_PDSR
00307 #endif
00308 
00309 #endif
00310 
00311 #define TWI_ENABLE() { \
00312     outr(TWI_SDA_COD_REG, _BV(TWI_SDA_BIT)); \
00313     outr(TWI_SCL_COD_REG, _BV(TWI_SCL_BIT)); \
00314     outr(TWI_SDA_PE_REG, _BV(TWI_SDA_BIT)); \
00315     outr(TWI_SCL_PE_REG, _BV(TWI_SCL_BIT)); \
00316 }
00317 
00318 #define SDA_LOW() { \
00319     outr(TWI_SDA_COD_REG, _BV(TWI_SDA_BIT)); \
00320     outr(TWI_SDA_OE_REG, _BV(TWI_SDA_BIT)); \
00321 }
00322 
00323 #define SDA_HIGH() { \
00324     outr(TWI_SDA_SOD_REG, _BV(TWI_SDA_BIT)); \
00325     outr(TWI_SDA_OD_REG, _BV(TWI_SDA_BIT)); \
00326 }
00327 
00328 #define SDA_STAT()      (inr(TWI_SDA_PDS_REG) & _BV(TWI_SDA_BIT))
00329 
00330 #define SCL_LOW() { \
00331     outr(TWI_SCL_COD_REG, _BV(TWI_SCL_BIT)); \
00332     outr(TWI_SCL_OE_REG, _BV(TWI_SCL_BIT)); \
00333 }
00334 
00335 #define SCL_HIGH() { \
00336     outr(TWI_SCL_SOD_REG, _BV(TWI_SCL_BIT)); \
00337     outr(TWI_SCL_OD_REG, _BV(TWI_SCL_BIT)); \
00338 }
00339 
00340 #elif defined(__AVR__)
00341 
00342 /*
00343  * AVR not yet tested.
00344  */
00345 #include <cfg/arch/avr.h>
00346 
00347 #ifndef TWI_SDA_BIT
00348 #define TWI_SDA_BIT     0
00349 #endif
00350 
00351 #if (TWI_SDA_AVRPORT == AVRPORTD)
00352 #define TWI_SDA_PORT    PORTD
00353 #define TWI_SDA_PIN     PIND
00354 #define TWI_SDA_DDR     DDRD
00355 #elif (TWI_SDA_AVRPORT == AVRPORTE)
00356 #define TWI_SDA_PORT    PORTE
00357 #define TWI_SDA_PIN     PINE
00358 #define TWI_SDA_DDR     DDRE
00359 #elif (TWI_SDA_AVRPORT == AVRPORTF)
00360 #define TWI_SDA_PORT    PORTF
00361 #define TWI_SDA_PIN     PINF
00362 #define TWI_SDA_DDR     DDRF
00363 #else
00364 #define TWI_SDA_PORT    PORTB
00365 #define TWI_SDA_PIN     PINB
00366 #define TWI_SDA_DDR     DDRB
00367 #endif
00368 
00369 #ifndef TWI_SCL_BIT
00370 #define TWI_SCL_BIT     1
00371 #endif
00372 
00373 #if (TWI_SCL_AVRPORT == AVRPORTD)
00374 #define TWI_SCL_PORT    PORTD
00375 #define TWI_SCL_DDR     DDRD
00376 #elif (TWI_SCL_AVRPORT == AVRPORTE)
00377 #define TWI_SCL_PORT    PORTE
00378 #define TWI_SCL_DDR     DDRE
00379 #elif (TWI_SCL_AVRPORT == AVRPORTF)
00380 #define TWI_SCL_PORT    PORTF
00381 #define TWI_SCL_DDR     DDRF
00382 #else
00383 #define TWI_SCL_PORT    PORTB
00384 #define TWI_SCL_DDR     DDRB
00385 #endif
00386 
00387 #define TWI_ENABLE() {              \
00388     cbi(TWI_SDA_PORT, TWI_SDA_BIT); \
00389     cbi(TWI_SCL_PORT, TWI_SCL_BIT); \
00390 }
00391 
00392 #define SDA_LOW()   sbi(TWI_SDA_DDR, TWI_SDA_BIT)
00393 #define SDA_HIGH()  cbi(TWI_SDA_DDR, TWI_SDA_BIT)
00394 #define SDA_STAT()  bit_is_set(TWI_SDA_PIN, TWI_SDA_BIT)
00395 
00396 #define SCL_LOW()   sbi(TWI_SCL_DDR, TWI_SCL_BIT)
00397 #define SCL_HIGH()  cbi(TWI_SCL_DDR, TWI_SCL_BIT)
00398 
00399 #ifndef TWI_DELAY
00400 #define TWI_DELAY   8
00401 #endif
00402 
00403 #endif                          /* __AVR__ */
00404 
00405 
00406 static u_char tw_mm_error;      /* Last master mode error. */
00407 static int twibb_initialized;
00408 
00409 /*
00410  * Short delay. 
00411  * 
00412  * Our bit banging code relies on pull-up resistors. The I/O ports mimic
00413  * open collector outputs by switching to input mode for high level and
00414  * switching to output mode for low level. This is much slower than
00415  * switching an output between low to high. Thus we need some delay.
00416  */
00417 static void TwDelay(int nops)
00418 {
00419     while (nops--) {
00420         _NOP();
00421     }
00422 }
00423 
00424 /*
00425  * Falling edge on the data line while the clock line is high indicates
00426  * a start condition.
00427  *
00428  * Entry: SCL any, SDA any
00429  * Exit: SCL low, SDA low
00430  */
00431 static void TwStart(void)
00432 {
00433     SDA_HIGH();
00434     TwDelay(TWI_DELAY);
00435     SCL_HIGH();
00436     TwDelay(TWI_DELAY);
00437     SDA_LOW();
00438     TwDelay(TWI_DELAY);
00439     SCL_LOW();
00440     TwDelay(TWI_DELAY);
00441 }
00442 
00443 /*
00444  * Rising edge on the data line while the clock line is high indicates
00445  * a stop condition.
00446  *
00447  * Entry: SCL low, SDA any
00448  * Exit: SCL high, SDA high
00449  */
00450 static void TwStop(void)
00451 {
00452     SDA_LOW();
00453     TwDelay(TWI_DELAY);
00454     SCL_HIGH();
00455     TwDelay(2 * TWI_DELAY);
00456     SDA_HIGH();
00457     TwDelay(8 * TWI_DELAY);
00458 }
00459 
00460 /*
00461  * Toggles out a single byte in master mode.
00462  *
00463  * Entry: SCL low, SDA any
00464  * Exit: SCL low, SDA high
00465  */
00466 static int TwPut(u_char octet)
00467 {
00468     int i;
00469 
00470     for (i = 0x80; i; i >>= 1) {
00471         /* Set the data bit. */
00472         if (octet & i) {
00473             SDA_HIGH();
00474         } else {
00475             SDA_LOW();
00476         }
00477         /* Wait for data to stabelize. */
00478         TwDelay(TWI_DELAY);
00479         /* Toggle the clock. */
00480         SCL_HIGH();
00481         TwDelay(2 * TWI_DELAY);
00482         SCL_LOW();
00483         TwDelay(TWI_DELAY);
00484     }
00485 
00486     /* Set data line high to receive the ACK bit. */
00487     SDA_HIGH();
00488 
00489     /* ACK should appear shortly after the clock's rising edge. */
00490     SCL_HIGH();
00491     TwDelay(2 * TWI_DELAY);
00492     if (SDA_STAT()) {
00493         i = -1;
00494     } else {
00495         i = 0;
00496     }
00497     SCL_LOW();
00498 
00499     return i;
00500 }
00501 
00502 /*
00503  * Toggles in a single byte in master mode.
00504  *
00505  * Entry: SCL low, SDA any
00506  * Exit: SCL low, SDA high
00507  */
00508 static u_char TwGet(void)
00509 {
00510     u_char rc = 0;
00511     int i;
00512 
00513     /* SDA is input. */
00514     SDA_HIGH();
00515     TwDelay(TWI_DELAY);
00516     for (i = 0x80; i; i >>= 1) {
00517         TwDelay(TWI_DELAY);
00518         /* Data should appear shortly after the clock's rising edge. */
00519         SCL_HIGH();
00520         TwDelay(2 * TWI_DELAY);
00521         /* SDA read. */
00522         if (SDA_STAT()) {
00523             rc |= i;
00524         }
00525         SCL_LOW();
00526     }
00527     return rc;
00528 }
00529 
00530 /*
00531  * Toggles out an acknowledge bit in master mode.
00532  *
00533  * Entry: SCL low, SDA any
00534  * Exit: SCL low, SDA high
00535  */
00536 static void TwAck(void)
00537 {
00538     SDA_LOW();
00539     TwDelay(TWI_DELAY);
00540     SCL_HIGH();
00541     TwDelay(2 * TWI_DELAY);
00542     SCL_LOW();
00543     TwDelay(TWI_DELAY);
00544     SDA_HIGH();
00545 }
00546 
00574 int TwMasterTransact(u_char sla, CONST void *txdata, u_short txlen, void *rxdata, u_short rxsiz, u_long tmo)
00575 {
00576     int rc = 0;
00577     u_char *cp;
00578 
00579     if (!twibb_initialized) {
00580         TwInit(0);
00581     }
00582 
00583     if (txlen) {
00584         TwStart();
00585         /* Send SLA+W and check for ACK. */
00586         if ((rc = TwPut(sla << 1)) == 0) {
00587             for (cp = (u_char *)txdata; txlen--; cp++) {
00588                 if ((rc = TwPut(*cp)) != 0) {
00589                     break;
00590                 }
00591             }
00592         }
00593     }
00594     if (rc == 0 && rxsiz) {
00595         TwStart();
00596         /* Send SLA+R and check for ACK. */
00597         if ((rc = TwPut((sla << 1) | 1)) == 0) {
00598             for (cp = rxdata;; cp++) {
00599                 *cp = TwGet();
00600                 if (++rc >= rxsiz) {
00601                     break;
00602                 }
00603                 TwAck();
00604             }
00605         }
00606     }
00607     TwStop();
00608 
00609     if (rc == -1) {
00610         tw_mm_error = TWERR_SLA_NACK;
00611     }
00612     return rc;
00613 }
00614 
00623 int TwMasterError(void)
00624 {
00625     int rc = (int) tw_mm_error;
00626     tw_mm_error = 0;
00627 
00628     return rc;
00629 }
00630 
00654 int TwSlaveListen(u_char * sla, void *rxdata, u_short rxsiz, u_long tmo)
00655 {
00656     return -1;
00657 }
00658 
00677 int TwSlaveRespond(void *txdata, u_short txlen, u_long tmo)
00678 {
00679     return -1;
00680 }
00681 
00693 int TwSlaveError(void)
00694 {
00695     return TWERR_BUS;
00696 }
00697 
00710 int TwIOCtl(int req, void *conf)
00711 {
00712     return 0;
00713 }
00714 
00730 int TwInit(u_char sla)
00731 {
00732     SDA_HIGH();
00733     SCL_HIGH();
00734     TWI_ENABLE();
00735     twibb_initialized = 1;
00736 
00737     return 0;
00738 }

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/