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