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 
00079 #include <cfg/os.h>
00080 #include <cfg/twi.h>
00081 #include <cfg/arch/gpio.h>
00082 
00083 #include <dev/twif.h>
00084 
00085 #if defined(__arm__)
00086 
00087 #include <arch/arm.h>
00088 
00094 #if !defined(TWI_PIO_ID)
00095 #if defined(MCU_AT91SAM7X256)
00096 #define TWI_PIO_ID  PIOA_ID
00097 #elif defined(MCU_AT91SAM9260)
00098 #define TWI_PIO_ID  PIOB_ID
00099 #else
00100 #define TWI_PIO_ID  PIO_ID
00101 #endif
00102 #endif
00103 
00109 #ifndef TWI_SDA_BIT
00110 #if defined(MCU_AT91SAM9260)
00111 #define TWI_SDA_BIT     12
00112 #else
00113 #define TWI_SDA_BIT     10
00114 #endif
00115 #endif
00116 
00120 #ifndef TWI_DELAY
00121 #if defined(MCU_AT91SAM9260)
00122 #define TWI_DELAY   16
00123 #else
00124 #define TWI_DELAY   8
00125 #endif
00126 #endif
00127 
00133 #ifndef TWI_SCL_BIT
00134 #if defined(MCU_AT91SAM9260)
00135 #define TWI_SCL_BIT     13
00136 #else
00137 #define TWI_SCL_BIT     11
00138 #endif
00139 #endif
00140 
00146 #if TWI_PIO_ID == PIOA_ID
00147 
00148 #ifndef TWI_SDA_PE_REG
00149 #define TWI_SDA_PE_REG  PIOA_PER
00150 #endif
00151 #ifndef TWI_SDA_OE_REG
00152 #define TWI_SDA_OE_REG  PIOA_OER
00153 #endif
00154 #ifndef TWI_SDA_OD_REG
00155 #define TWI_SDA_OD_REG  PIOA_ODR
00156 #endif
00157 #ifndef TWI_SDA_COD_REG
00158 #define TWI_SDA_COD_REG PIOA_CODR
00159 #endif
00160 #ifndef TWI_SDA_SOD_REG
00161 #define TWI_SDA_SOD_REG PIOA_SODR
00162 #endif
00163 #ifndef TWI_SDA_PDS_REG
00164 #define TWI_SDA_PDS_REG PIOA_PDSR
00165 #endif
00166 
00167 #ifndef TWI_SCL_PE_REG
00168 #define TWI_SCL_PE_REG  PIOA_PER
00169 #endif
00170 #ifndef TWI_SCL_OE_REG
00171 #define TWI_SCL_OE_REG  PIOA_OER
00172 #endif
00173 #ifndef TWI_SCL_OD_REG
00174 #define TWI_SCL_OD_REG  PIOA_ODR
00175 #endif
00176 #ifndef TWI_SCL_COD_REG
00177 #define TWI_SCL_COD_REG PIOA_CODR
00178 #endif
00179 #ifndef TWI_SCL_SOD_REG
00180 #define TWI_SCL_SOD_REG PIOA_SODR
00181 #endif
00182 #ifndef TWI_SCL_PDS_REG
00183 #define TWI_SCL_PDS_REG PIOA_PDSR
00184 #endif
00185 
00186 #elif TWI_PIO_ID == PIOB_ID
00187 
00188 #ifndef TWI_SDA_PE_REG
00189 #define TWI_SDA_PE_REG  PIOB_PER
00190 #endif
00191 #ifndef TWI_SDA_OE_REG
00192 #define TWI_SDA_OE_REG  PIOB_OER
00193 #endif
00194 #ifndef TWI_SDA_OD_REG
00195 #define TWI_SDA_OD_REG  PIOB_ODR
00196 #endif
00197 #ifndef TWI_SDA_COD_REG
00198 #define TWI_SDA_COD_REG PIOB_CODR
00199 #endif
00200 #ifndef TWI_SDA_SOD_REG
00201 #define TWI_SDA_SOD_REG PIOB_SODR
00202 #endif
00203 #ifndef TWI_SDA_PDS_REG
00204 #define TWI_SDA_PDS_REG PIOB_PDSR
00205 #endif
00206 
00207 #ifndef TWI_SCL_PE_REG
00208 #define TWI_SCL_PE_REG  PIOB_PER
00209 #endif
00210 #ifndef TWI_SCL_OE_REG
00211 #define TWI_SCL_OE_REG  PIOB_OER
00212 #endif
00213 #ifndef TWI_SCL_OD_REG
00214 #define TWI_SCL_OD_REG  PIOB_ODR
00215 #endif
00216 #ifndef TWI_SCL_COD_REG
00217 #define TWI_SCL_COD_REG PIOB_CODR
00218 #endif
00219 #ifndef TWI_SCL_SOD_REG
00220 #define TWI_SCL_SOD_REG PIOB_SODR
00221 #endif
00222 #ifndef TWI_SCL_PDS_REG
00223 #define TWI_SCL_PDS_REG PIOB_PDSR
00224 #endif
00225 
00226 #elif TWI_PIO_ID == PIOC_ID
00227 
00228 #ifndef TWI_SDA_PE_REG
00229 #define TWI_SDA_PE_REG  PIOC_PER
00230 #endif
00231 #ifndef TWI_SDA_OE_REG
00232 #define TWI_SDA_OE_REG  PIOC_OER
00233 #endif
00234 #ifndef TWI_SDA_OD_REG
00235 #define TWI_SDA_OD_REG  PIOC_ODR
00236 #endif
00237 #ifndef TWI_SDA_COD_REG
00238 #define TWI_SDA_COD_REG PIOC_CODR
00239 #endif
00240 #ifndef TWI_SDA_SOD_REG
00241 #define TWI_SDA_SOD_REG PIOC_SODR
00242 #endif
00243 #ifndef TWI_SDA_PDS_REG
00244 #define TWI_SDA_PDS_REG PIOC_PDSR
00245 #endif
00246 
00247 #ifndef TWI_SCL_PE_REG
00248 #define TWI_SCL_PE_REG  PIOC_PER
00249 #endif
00250 #ifndef TWI_SCL_OE_REG
00251 #define TWI_SCL_OE_REG  PIOC_OER
00252 #endif
00253 #ifndef TWI_SCL_OD_REG
00254 #define TWI_SCL_OD_REG  PIOC_ODR
00255 #endif
00256 #ifndef TWI_SCL_COD_REG
00257 #define TWI_SCL_COD_REG PIOC_CODR
00258 #endif
00259 #ifndef TWI_SCL_SOD_REG
00260 #define TWI_SCL_SOD_REG PIOC_SODR
00261 #endif
00262 #ifndef TWI_SCL_PDS_REG
00263 #define TWI_SCL_PDS_REG PIOC_PDSR
00264 #endif
00265 
00266 #else
00267 
00268 #ifndef TWI_SDA_PE_REG
00269 #define TWI_SDA_PE_REG  PIO_PER
00270 #endif
00271 #ifndef TWI_SDA_OE_REG
00272 #define TWI_SDA_OE_REG  PIO_OER
00273 #endif
00274 #ifndef TWI_SDA_OD_REG
00275 #define TWI_SDA_OD_REG  PIO_ODR
00276 #endif
00277 #ifndef TWI_SDA_COD_REG
00278 #define TWI_SDA_COD_REG PIO_CODR
00279 #endif
00280 #ifndef TWI_SDA_SOD_REG
00281 #define TWI_SDA_SOD_REG PIO_SODR
00282 #endif
00283 #ifndef TWI_SDA_PDS_REG
00284 #define TWI_SDA_PDS_REG PIO_PDSR
00285 #endif
00286 
00287 #ifndef TWI_SCL_PE_REG
00288 #define TWI_SCL_PE_REG  PIO_PER
00289 #endif
00290 #ifndef TWI_SCL_OE_REG
00291 #define TWI_SCL_OE_REG  PIO_OER
00292 #endif
00293 #ifndef TWI_SCL_OD_REG
00294 #define TWI_SCL_OD_REG  PIO_ODR
00295 #endif
00296 #ifndef TWI_SCL_COD_REG
00297 #define TWI_SCL_COD_REG PIO_CODR
00298 #endif
00299 #ifndef TWI_SCL_SOD_REG
00300 #define TWI_SCL_SOD_REG PIO_SODR
00301 #endif
00302 #ifndef TWI_SCL_PDS_REG
00303 #define TWI_SCL_PDS_REG PIO_PDSR
00304 #endif
00305 
00306 #endif
00307 
00308 #define TWI_ENABLE() { \
00309     outr(TWI_SDA_COD_REG, _BV(TWI_SDA_BIT)); \
00310     outr(TWI_SCL_COD_REG, _BV(TWI_SCL_BIT)); \
00311     outr(TWI_SDA_PE_REG, _BV(TWI_SDA_BIT)); \
00312     outr(TWI_SCL_PE_REG, _BV(TWI_SCL_BIT)); \
00313 }
00314 
00315 #define SDA_LOW() { \
00316     outr(TWI_SDA_COD_REG, _BV(TWI_SDA_BIT)); \
00317     outr(TWI_SDA_OE_REG, _BV(TWI_SDA_BIT)); \
00318 }
00319 
00320 #define SDA_HIGH() { \
00321     outr(TWI_SDA_SOD_REG, _BV(TWI_SDA_BIT)); \
00322     outr(TWI_SDA_OD_REG, _BV(TWI_SDA_BIT)); \
00323 }
00324 
00325 #define SDA_STAT()      (inr(TWI_SDA_PDS_REG) & _BV(TWI_SDA_BIT))
00326 
00327 #define SCL_LOW() { \
00328     outr(TWI_SCL_COD_REG, _BV(TWI_SCL_BIT)); \
00329     outr(TWI_SCL_OE_REG, _BV(TWI_SCL_BIT)); \
00330 }
00331 
00332 #define SCL_HIGH() { \
00333     outr(TWI_SCL_SOD_REG, _BV(TWI_SCL_BIT)); \
00334     outr(TWI_SCL_OD_REG, _BV(TWI_SCL_BIT)); \
00335 }
00336 
00337 #elif defined(__AVR__)
00338 
00339 /*
00340  * AVR not yet tested.
00341  */
00342 #include <cfg/arch/avr.h>
00343 
00344 #ifndef TWI_SDA_BIT
00345 #define TWI_SDA_BIT     0
00346 #endif
00347 
00348 #if (TWI_SDA_AVRPORT == AVRPORTD)
00349 #define TWI_SDA_PORT    PORTD
00350 #define TWI_SDA_PIN     PIND
00351 #define TWI_SDA_DDR     DDRD
00352 #elif (TWI_SDA_AVRPORT == AVRPORTE)
00353 #define TWI_SDA_PORT    PORTE
00354 #define TWI_SDA_PIN     PINE
00355 #define TWI_SDA_DDR     DDRE
00356 #elif (TWI_SDA_AVRPORT == AVRPORTF)
00357 #define TWI_SDA_PORT    PORTF
00358 #define TWI_SDA_PIN     PINF
00359 #define TWI_SDA_DDR     DDRF
00360 #else
00361 #define TWI_SDA_PORT    PORTB
00362 #define TWI_SDA_PIN     PINB
00363 #define TWI_SDA_DDR     DDRB
00364 #endif
00365 
00366 #ifndef TWI_SCL_BIT
00367 #define TWI_SCL_BIT     1
00368 #endif
00369 
00370 #if (TWI_SCL_AVRPORT == AVRPORTD)
00371 #define TWI_SCL_PORT    PORTD
00372 #define TWI_SCL_DDR     DDRD
00373 #elif (TWI_SCL_AVRPORT == AVRPORTE)
00374 #define TWI_SCL_PORT    PORTE
00375 #define TWI_SCL_DDR     DDRE
00376 #elif (TWI_SCL_AVRPORT == AVRPORTF)
00377 #define TWI_SCL_PORT    PORTF
00378 #define TWI_SCL_DDR     DDRF
00379 #else
00380 #define TWI_SCL_PORT    PORTB
00381 #define TWI_SCL_DDR     DDRB
00382 #endif
00383 
00384 #define TWI_ENABLE() {              \
00385     cbi(TWI_SDA_PORT, TWI_SDA_BIT); \
00386     cbi(TWI_SCL_PORT, TWI_SCL_BIT); \
00387 }
00388 
00389 #define SDA_LOW()   sbi(TWI_SDA_DDR, TWI_SDA_BIT)
00390 #define SDA_HIGH()  cbi(TWI_SDA_DDR, TWI_SDA_BIT)
00391 #define SDA_STAT()  bit_is_set(TWI_SDA_PIN, TWI_SDA_BIT)
00392 
00393 #define SCL_LOW()   sbi(TWI_SCL_DDR, TWI_SCL_BIT)
00394 #define SCL_HIGH()  cbi(TWI_SCL_DDR, TWI_SCL_BIT)
00395 
00396 #ifndef TWI_DELAY
00397 #define TWI_DELAY   8
00398 #endif
00399 
00400 #endif                          /* __AVR__ */
00401 
00402 
00403 static u_char tw_mm_error;      /* Last master mode error. */
00404 static int twibb_initialized;
00405 
00406 /*
00407  * Short delay. 
00408  * 
00409  * Our bit banging code relies on pull-up resistors. The I/O ports mimic
00410  * open collector outputs by switching to input mode for high level and
00411  * switching to output mode for low level. This is much slower than
00412  * switching an output between low to high. Thus we need some delay.
00413  */
00414 static void TwDelay(int nops)
00415 {
00416     while (nops--) {
00417         _NOP();
00418     }
00419 }
00420 
00421 /*
00422  * Falling edge on the data line while the clock line is high indicates
00423  * a start condition.
00424  *
00425  * Entry: SCL any, SDA any
00426  * Exit: SCL low, SDA low
00427  */
00428 static void TwStart(void)
00429 {
00430     SDA_HIGH();
00431     TwDelay(TWI_DELAY);
00432     SCL_HIGH();
00433     TwDelay(TWI_DELAY);
00434     SDA_LOW();
00435     TwDelay(TWI_DELAY);
00436     SCL_LOW();
00437     TwDelay(TWI_DELAY);
00438 }
00439 
00440 /*
00441  * Rising edge on the data line while the clock line is high indicates
00442  * a stop condition.
00443  *
00444  * Entry: SCL low, SDA any
00445  * Exit: SCL high, SDA high
00446  */
00447 static void TwStop(void)
00448 {
00449     SDA_LOW();
00450     TwDelay(TWI_DELAY);
00451     SCL_HIGH();
00452     TwDelay(2 * TWI_DELAY);
00453     SDA_HIGH();
00454     TwDelay(8 * TWI_DELAY);
00455 }
00456 
00457 /*
00458  * Toggles out a single byte in master mode.
00459  *
00460  * Entry: SCL low, SDA any
00461  * Exit: SCL low, SDA high
00462  */
00463 static int TwPut(u_char octet)
00464 {
00465     int i;
00466 
00467     for (i = 0x80; i; i >>= 1) {
00468         /* Set the data bit. */
00469         if (octet & i) {
00470             SDA_HIGH();
00471         } else {
00472             SDA_LOW();
00473         }
00474         /* Wait for data to stabelize. */
00475         TwDelay(TWI_DELAY);
00476         /* Toggle the clock. */
00477         SCL_HIGH();
00478         TwDelay(2 * TWI_DELAY);
00479         SCL_LOW();
00480         TwDelay(TWI_DELAY);
00481     }
00482 
00483     /* Set data line high to receive the ACK bit. */
00484     SDA_HIGH();
00485 
00486     /* ACK should appear shortly after the clock's rising edge. */
00487     SCL_HIGH();
00488     TwDelay(2 * TWI_DELAY);
00489     if (SDA_STAT()) {
00490         i = -1;
00491     } else {
00492         i = 0;
00493     }
00494     SCL_LOW();
00495 
00496     return i;
00497 }
00498 
00499 /*
00500  * Toggles in a single byte in master mode.
00501  *
00502  * Entry: SCL low, SDA any
00503  * Exit: SCL low, SDA high
00504  */
00505 static u_char TwGet(void)
00506 {
00507     u_char rc = 0;
00508     int i;
00509 
00510     /* SDA is input. */
00511     SDA_HIGH();
00512     TwDelay(TWI_DELAY);
00513     for (i = 0x80; i; i >>= 1) {
00514         TwDelay(TWI_DELAY);
00515         /* Data should appear shortly after the clock's rising edge. */
00516         SCL_HIGH();
00517         TwDelay(2 * TWI_DELAY);
00518         /* SDA read. */
00519         if (SDA_STAT()) {
00520             rc |= i;
00521         }
00522         SCL_LOW();
00523     }
00524     return rc;
00525 }
00526 
00527 /*
00528  * Toggles out an acknowledge bit in master mode.
00529  *
00530  * Entry: SCL low, SDA any
00531  * Exit: SCL low, SDA high
00532  */
00533 static void TwAck(void)
00534 {
00535     SDA_LOW();
00536     TwDelay(TWI_DELAY);
00537     SCL_HIGH();
00538     TwDelay(2 * TWI_DELAY);
00539     SCL_LOW();
00540     TwDelay(TWI_DELAY);
00541     SDA_HIGH();
00542 }
00543 
00571 int TwMasterTransact(u_char sla, CONST void *txdata, u_short txlen, void *rxdata, u_short rxsiz, u_long tmo)
00572 {
00573     int rc = 0;
00574     u_char *cp;
00575 
00576     if (!twibb_initialized) {
00577         TwInit(0);
00578     }
00579 
00580     if (txlen) {
00581         TwStart();
00582         /* Send SLA+W and check for ACK. */
00583         if ((rc = TwPut(sla << 1)) == 0) {
00584             for (cp = (u_char *)txdata; txlen--; cp++) {
00585                 if ((rc = TwPut(*cp)) != 0) {
00586                     break;
00587                 }
00588             }
00589         }
00590     }
00591     if (rc == 0 && rxsiz) {
00592         TwStart();
00593         /* Send SLA+R and check for ACK. */
00594         if ((rc = TwPut((sla << 1) | 1)) == 0) {
00595             for (cp = rxdata;; cp++) {
00596                 *cp = TwGet();
00597                 if (++rc >= rxsiz) {
00598                     break;
00599                 }
00600                 TwAck();
00601             }
00602         }
00603     }
00604     TwStop();
00605 
00606     if (rc == -1) {
00607         tw_mm_error = TWERR_SLA_NACK;
00608     }
00609     return rc;
00610 }
00611 
00620 int TwMasterError(void)
00621 {
00622     int rc = (int) tw_mm_error;
00623     tw_mm_error = 0;
00624 
00625     return rc;
00626 }
00627 
00651 int TwSlaveListen(u_char * sla, void *rxdata, u_short rxsiz, u_long tmo)
00652 {
00653     return -1;
00654 }
00655 
00674 int TwSlaveRespond(void *txdata, u_short txlen, u_long tmo)
00675 {
00676     return -1;
00677 }
00678 
00690 int TwSlaveError(void)
00691 {
00692     return TWERR_BUS;
00693 }
00694 
00707 int TwIOCtl(int req, void *conf)
00708 {
00709     return 0;
00710 }
00711 
00727 int TwInit(u_char sla)
00728 {
00729     SDA_HIGH();
00730     SCL_HIGH();
00731     TWI_ENABLE();
00732     twibb_initialized = 1;
00733 
00734     return 0;
00735 }

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