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

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