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

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