twif.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2005 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 
00034 /*
00035  * $Log: twif.c,v $
00036  * Revision 1.6  2007/07/26 13:03:05  freckle
00037  * Reduced critical section in TwSlaveListen
00038  *
00039  * Revision 1.5  2006/10/08 16:48:08  haraldkipp
00040  * Documentation fixed
00041  *
00042  * Revision 1.4  2006/06/28 14:31:24  haraldkipp
00043  * NutEventPostFromIrq() doesn't return a result anymore. We directly
00044  * inspect the queue's root.
00045  *
00046  * Revision 1.3  2005/10/24 10:56:30  haraldkipp
00047  * Added const modifier to transmit data pointer in TwMasterTransact().
00048  *
00049  * Revision 1.2  2005/10/07 22:03:29  hwmaier
00050  * Using __AVR_ENHANCED__ macro instead of __AVR_ATmega128__ to support also AT90CAN128 MCU
00051  *
00052  * Revision 1.1  2005/07/26 18:02:40  haraldkipp
00053  * Moved from dev.
00054  *
00055  * Revision 1.9  2005/01/24 21:12:05  freckle
00056  * renamed NutEventPostFromIRQ into NutEventPostFromIrq
00057  *
00058  * Revision 1.8  2005/01/21 16:49:46  freckle
00059  * Seperated calls to NutEventPostAsync between Threads and IRQs
00060  *
00061  * Revision 1.7  2004/12/16 08:40:35  haraldkipp
00062  * Late increment fixes ICCAVR bug.
00063  *
00064  * Revision 1.6  2004/11/08 18:12:59  haraldkipp
00065  * Soooo many fixes, but I'm tired...really.
00066  *
00067  * Revision 1.5  2004/09/08 10:19:14  haraldkipp
00068  * *** empty log message ***
00069  *
00070  * Revision 1.4  2003/11/03 17:03:53  haraldkipp
00071  * Many new comments added
00072  *
00073  * Revision 1.3  2003/07/20 18:28:10  haraldkipp
00074  * Explain how to disable timeout.
00075  *
00076  * Revision 1.2  2003/07/17 09:38:07  haraldkipp
00077  * Setting different speeds is now supported.
00078  *
00079  * Revision 1.1.1.1  2003/05/09 14:40:53  haraldkipp
00080  * Initial using 3.2.1
00081  *
00082  * Revision 1.2  2003/03/31 14:53:08  harald
00083  * Prepare release 3.1
00084  *
00085  * Revision 1.1  2003/02/04 17:54:59  harald
00086  * *** empty log message ***
00087  *
00088  */
00089 
00090 #include <string.h>
00091 
00092 #include <dev/irqreg.h>
00093 
00094 #include <sys/event.h>
00095 #include <sys/atom.h>
00096 #include <sys/timer.h>
00097 #include <sys/thread.h>
00098 #include <sys/heap.h>
00099 
00100 #include <dev/twif.h>
00101 
00102 #ifdef __AVR_ENHANCED__
00103 
00104 static volatile u_char tw_if_bsy;   /* Set while interface is busy. */
00105 
00106 HANDLE tw_mm_mutex;          /* Exclusive master access. */
00107 HANDLE tw_mm_que;            /* Threads waiting for master transfer done. */
00108 HANDLE tw_sr_que;            /* Threads waiting for slave receive. */
00109 HANDLE tw_st_que;            /* Threads waiting for slave transmit done. */
00110 
00111 static u_char tw_mm_sla;            /* Destination slave address. */
00112 static volatile u_char tw_mm_err;   /* Current master mode error. */
00113 static u_char tw_mm_error;          /* Last master mode error. */
00114 
00115 static CONST u_char *tw_mt_buf;     /* Pointer to the master transmit buffer. */
00116 static volatile u_short tw_mt_len;  /* Number of bytes to transmit in master mode. */
00117 static volatile u_short tw_mt_idx;  /* Current master transmit buffer index. */
00118 
00119 static u_char *tw_mr_buf;           /* Pointer to the master receive buffer. */
00120 static volatile u_short tw_mr_siz;  /* Size of the master receive buffer. */
00121 static volatile u_short tw_mr_idx;  /* Current master receive buffer index. */
00122 
00123 static volatile u_char tw_sm_sla;   /* Slave address received. */
00124 static volatile u_char tw_sm_err;   /* Current slave mode error. */
00125 static u_char tw_sm_error;          /* Last slave mode error. */
00126 
00127 static u_char *tw_st_buf;           /* Pointer to the slave transmit buffer. */
00128 static volatile u_short tw_st_len;  /* Number of bytes to transmit in slave mode. */
00129 static volatile u_short tw_st_idx;  /* Current slave transmit buffer index. */
00130 
00131 static u_char *tw_sr_buf;           /* Pointer to the slave receive buffer. */
00132 static volatile u_short tw_sr_siz;  /* Size of the master receive buffer. */
00133 static volatile u_short tw_sr_idx;  /* Current slave receive buffer index. */
00134 
00135 /*
00136 TWINT TWEA TWSTA TWSTO TWWC TWEN  0  TWIE
00137   C                      R        R
00138 */
00139 
00140 #define TWGO    (_BV(TWINT) | _BV(TWEN) | _BV(TWIE))
00141 
00142 /*
00143  * TWI interrupt handler.
00144  */
00145 static void TwInterrupt(void *arg)
00146 {
00147     u_char twsr;
00148     register u_char twcr = inb(TWCR);
00149 
00150     /*
00151      * Read the status and interpret its contents.
00152      */
00153     twsr = inb(TWSR) & 0xF8;
00154     switch (twsr) {
00155 
00156     /*
00157      * 0x08: Start condition has been transmitted.
00158      * 0x10: Repeated start condition has been transmitted.
00159      */
00160     case TW_START:
00161     case TW_REP_START:
00162         /* We are entering the master mode. Mark the interface busy. */
00163         tw_if_bsy = 1;
00164         tw_mt_idx = 0;
00165         tw_mr_idx = 0;
00166 
00167         /*
00168          * If outgoing data is available, transmit SLA+W. Logic is in
00169          * master transmit mode.
00170          */
00171         if (tw_mt_len) {
00172             outb(TWDR, tw_mm_sla);
00173         }
00174 
00175         /*
00176          * If outgoing data not available, transmit SLA+R. Logic will
00177          * switch to master receiver mode.
00178          */
00179         else {
00180             outb(TWDR, tw_mm_sla | 1);
00181         }
00182         outb(TWCR, TWGO | (twcr & _BV(TWEA)));
00183         break;
00184 
00185     /*
00186      * 0x18: SLA+W has been transmitted and ACK has been received.
00187      * 0x28: Data byte has been transmitted and ACK has been received.
00188      */
00189     case TW_MT_SLA_ACK:
00190     case TW_MT_DATA_ACK:
00191         /*
00192          * If outgoing data left to send, put the next byte in the data
00193          * register.
00194          */
00195         if (tw_mt_idx < tw_mt_len) {
00196             outb(TWDR, tw_mt_buf[tw_mt_idx]);
00197             /* Late increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */
00198             tw_mt_idx++;
00199             outb(TWCR, TWGO | (twcr & _BV(TWEA)));
00200             break;
00201         }
00202 
00203         /*
00204          * All outgoing data has been sent. If a response is expected,
00205          * transmit a repeated start condition.
00206          */
00207         tw_mt_len = 0;
00208         if (tw_mr_siz) {
00209             outb(TWCR, TWGO | (twcr & _BV(TWEA)) | _BV(TWSTA));
00210             break;
00211         }
00212 
00213     /*
00214      * 0x20: SLA+W has been transmitted, but not acknowledged.
00215      * 0x30: Data byte has been transmitted, but not acknowledged.
00216      * 0x48: SLA+R has been transmitted, but not acknowledged.
00217      */
00218     case TW_MT_SLA_NACK:
00219     case TW_MT_DATA_NACK:
00220     case TW_MR_SLA_NACK:
00221         /* Set unique error code. */
00222         if (twsr == TW_MT_SLA_NACK || twsr == TW_MR_SLA_NACK) {
00223             tw_mm_err = TWERR_SLA_NACK;
00224             tw_mt_len = 0;
00225             tw_mr_siz = 0;
00226         }
00227 
00228         /* Wake up the application. */
00229         NutEventPostFromIrq(&tw_mm_que);
00230 
00231         /*
00232          * Send a stop condition. If we have a listener, generate
00233          * an acknowlegde on an incoming address byte.
00234          */
00235         if(tw_sr_siz) {
00236             outb(TWCR, TWGO | _BV(TWEA) | _BV(TWSTO));
00237         }
00238         else {
00239             outb(TWCR, TWGO | _BV(TWSTO));
00240         }
00241 
00242         /* The interface is idle. */
00243         tw_if_bsy = 0;
00244         break;
00245 
00246     /*
00247      * 0x38: Arbitration lost while in master mode.
00248      */
00249     case TW_MT_ARB_LOST:
00250         /*
00251          * The start condition will be automatically resend after
00252          * the bus becomes available.
00253          */
00254         sbi(TWCR, TWSTA);
00255         /* The interface is idle. */
00256         tw_if_bsy = 0;
00257         break;
00258 
00259     /*
00260      * 0x50: Data byte has been received and acknowledged.
00261      */
00262     case TW_MR_DATA_ACK:
00263         /*
00264          * Store the data byte in the master receive buffer.
00265          */
00266         tw_mr_buf[tw_mr_idx] = inb(TWDR);
00267         /* Late increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */
00268         tw_mr_idx++;
00269 
00270     /*
00271      * 0x40: SLA+R has been transmitted and ACK has been received.
00272      */
00273     case TW_MR_SLA_ACK:
00274         /*
00275          * Acknowledge next data bytes except the last one.
00276          */
00277         if (tw_mr_idx + 1 < tw_mr_siz) {
00278             outb(TWCR, TWGO | _BV(TWEA));
00279         }
00280         else {
00281             outb(TWCR, TWGO);
00282         }
00283         break;
00284 
00285     /*
00286      * 0x58: Data byte has been received, but not acknowledged.
00287      */
00288     case TW_MR_DATA_NACK:
00289         /*
00290          * Store the last data byte.
00291          */
00292         tw_mr_buf[tw_mr_idx] = inb(TWDR);
00293         /* Late increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */
00294         tw_mr_idx++;
00295         tw_mr_siz = 0;
00296 
00297         /* Wake up the application. */
00298         NutEventPostFromIrq(&tw_mm_que);
00299 
00300         /*
00301          * Send a stop condition. If we have a listener, generate
00302          * an acknowlegde on an incoming address byte.
00303          */
00304         if(tw_sr_siz) {
00305             outb(TWCR, TWGO | _BV(TWEA) | _BV(TWSTO));
00306         }
00307         else {
00308             outb(TWCR, TWGO | _BV(TWSTO));
00309         }
00310 
00311         /* The interface is idle. */
00312         tw_if_bsy = 0;
00313         break;
00314 
00315     /*
00316      * 0x60: Own SLA+W has been received and acknowledged.
00317      * 0x68: Arbitration lost as master. Own SLA+W has been received
00318      *       and acknowledged.
00319      * 0x70: General call address has been received and acknowledged.
00320      * 0x78: Arbitration lost as master. General call address has been
00321      *       received and acknowledged.
00322      */
00323     case TW_SR_SLA_ACK:
00324     case TW_SR_ARB_LOST_SLA_ACK:
00325     case TW_SR_GCALL_ACK:
00326     case TW_SR_ARB_LOST_GCALL_ACK:
00327         /*
00328          * Do only acknowledge incoming data bytes, if we got receive
00329          * buffer space. Fetch the slave address from the data register
00330          * and reset the receive index.
00331          */
00332         if (tw_sr_siz) {
00333             /* We are entering the slave receive mode. Mark the interface busy. */
00334             tw_if_bsy = 1;
00335 
00336             tw_sm_sla = inb(TWDR);
00337             outb(TWCR, TWGO | _BV(TWEA));
00338             tw_sr_idx = 0;
00339         }
00340 
00341         /*
00342          * Do not acknowledge incoming data.
00343          */
00344         else {
00345             outb(TWCR, TWGO);
00346         }
00347         break;
00348 
00349     /*
00350      * 0x80: Data byte for own SLA has been received and acknowledged.
00351      * 0x90: Data byte for general call address has been received and
00352      *       acknowledged.
00353      */
00354     case TW_SR_DATA_ACK:
00355     case TW_SR_GCALL_DATA_ACK:
00356         /*
00357          * If the receive buffer isn't filled up, store data byte.
00358          */
00359         if (tw_sr_idx < tw_sr_siz) {
00360             tw_sr_buf[tw_sr_idx] = inb(TWDR);
00361             /* Late increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */
00362             tw_sr_idx++;
00363         }
00364         else {
00365             tw_sr_siz = 0;
00366         }
00367 
00368         /*
00369          * If more space is available for incoming data, then continue
00370          * receiving. Otherwise do not acknowledge new data bytes.
00371          */
00372         if (tw_sr_siz) {
00373             outb(TWCR, TWGO | _BV(TWEA));
00374             break;
00375         }
00376 
00377     /*
00378      * 0x88: Data byte received, but not acknowledged.
00379      * 0x98: Data byte for general call address received, but not
00380      *       acknowledged.
00381      */
00382     case TW_SR_DATA_NACK:
00383     case TW_SR_GCALL_DATA_NACK:
00384         /*
00385          * Continue not accepting more data.
00386          */
00387         if (tw_mt_len || tw_mr_siz) {
00388             outb(TWCR, inb(TWCR) | _BV(TWEA) | _BV(TWSTA));
00389         }
00390         else {
00391             outb(TWCR, inb(TWCR) | _BV(TWEA));
00392         }
00393         break;
00394 
00395     /*
00396      * 0xA0: Stop condition or repeated start condition received.
00397      */
00398     case TW_SR_STOP:
00399         /*
00400          * Wake up the application. If successful, do nothing. This
00401          * will keep SCL low and thus block the bus. The application
00402          * must now setup the transmit buffer and re-enable the
00403          * interface.
00404          */
00405         if (tw_sr_que == 0 || tw_sm_err) {
00406             /*
00407              * If no one has been waiting on the queue, the application
00408              * probably gave up waiting. So we continue on our own, either
00409              * in idle mode or switching to master mode if a master
00410              * request is waiting.
00411              */
00412             if (tw_mt_len || tw_mr_siz) {
00413                 outb(TWCR, TWGO | _BV(TWSTA));
00414             }
00415             else {
00416                 outb(TWCR, TWGO);
00417             }
00418             tw_if_bsy = 0;
00419         }
00420         else {
00421             NutEventPostFromIrq(&tw_sr_que);
00422             tw_sr_siz = 0;
00423             outb(TWCR, twcr & ~(_BV(TWINT) | _BV(TWIE)));
00424         }
00425         break;
00426 
00427     /*
00428      * 0xA8: Own SLA+R has been received and acknowledged.
00429      * 0xB0: Arbitration lost in master mode. Own SLA has been received
00430      *       and acknowledged.
00431      */
00432     case TW_ST_SLA_ACK:
00433     case TW_ST_ARB_LOST_SLA_ACK:
00434         /* Not idle. */
00435         tw_if_bsy = 1;
00436         /* Reset transmit index and fall through for outgoing data. */
00437         tw_st_idx = 0;
00438 
00439     /*
00440      * 0xB8: Data bytes has been transmitted and acknowledged.
00441      */
00442     case TW_ST_DATA_ACK:
00443         /*
00444          * If outgoing data left to send, put the next byte in the
00445          * data register. Otherwise transmit a dummy byte.
00446          */
00447         if (tw_st_idx < tw_st_len) {
00448             outb(TWDR, tw_st_buf[tw_st_idx]);
00449             /* Do not set acknowledge on the last data byte. */
00450             /* Early increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */
00451             ++tw_st_idx;
00452             if (tw_st_idx < tw_st_len) {
00453                 outb(TWCR, TWGO | _BV(TWEA));
00454             }
00455             else {
00456                 tw_st_len = 0;
00457                 outb(TWCR, TWGO);
00458             }
00459             break;
00460         }
00461 
00462         /* No more data. Continue sending dummies. */
00463         outb(TWDR, 0);
00464         outb(TWCR, TWGO);
00465         break;
00466 
00467     /*
00468      * 0xC0: Data byte has been transmitted, but not acknowledged.
00469      * 0xC8: Last data byte has been transmitted and acknowledged.
00470      */
00471     case TW_ST_DATA_NACK:
00472     case TW_ST_LAST_DATA:
00473         NutEventPostFromIrq(&tw_st_que);
00474 
00475         /* Transmit start condition, if a master transfer is waiting. */
00476         if (tw_mt_len || tw_mr_siz) {
00477             outb(TWCR, TWGO | _BV(TWSTA) |  _BV(TWEA));
00478         }
00479         /* Otherwise enter idle state. */
00480         else {
00481             outb(TWCR, TWGO | _BV(TWEA));
00482         }
00483         tw_if_bsy = 0;
00484         break;
00485 
00486     /*
00487      * 0x00: Bus error.
00488      */
00489     case TW_BUS_ERROR:
00490         outb(TWCR, inb(TWCR) | _BV(TWSTO));
00491 #if 1
00492         tw_if_bsy = 0;
00493         tw_mm_err = TWERR_BUS;
00494         tw_sm_err = TWERR_BUS;
00495         NutEventPostFromIrq(&tw_sr_que);
00496         NutEventPostFromIrq(&tw_st_que);
00497         NutEventPostFromIrq(&tw_mm_que);
00498 #endif
00499         break;
00500     }
00501 }
00502 
00503 #endif /* __AVR_ENHANCED__ */
00504 
00532 int TwMasterTransact(u_char sla, CONST void *txdata, u_short txlen, void *rxdata, u_short rxsiz, u_long tmo)
00533 {
00534     int rc = -1;
00535 
00536 #ifdef __AVR_ENHANCED__
00537     /* This routine is marked reentrant, so lock the interface. */
00538     if(NutEventWait(&tw_mm_mutex, 500)) {
00539         tw_mm_err = TWERR_IF_LOCKED;
00540         NutEventPost(&tw_mm_mutex);
00541         return -1;
00542     }
00543 
00544     while(tw_if_bsy) {
00545         NutSleep(63);
00546     }
00547     NutEnterCritical();
00548     /*
00549      * Set all parameters for master mode.
00550      */
00551     tw_mm_sla = sla << 1;
00552     tw_mm_err = 0;
00553     tw_mt_len = txlen;
00554     tw_mt_buf = txdata;
00555     tw_mr_siz = rxsiz;
00556     tw_mr_buf = rxdata;
00557 
00558     /*
00559      * Send a start condition if the interface is idle. If busy, then
00560      * the interrupt routine will automatically initiate the transfer
00561      * as soon as the interface becomes ready again.
00562      */
00563     if(tw_if_bsy == 0) {
00564         u_char twcr = inb(TWCR);
00565         u_char twsr = inb(TWSR);
00566         if((twsr & 0xF8) == TW_NO_INFO) {
00567             if(tw_sr_siz) {
00568                 outb(TWCR, _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWSTA) | (twcr & _BV(TWSTO)));
00569             }
00570             else {
00571                 outb(TWCR, _BV(TWEN) | _BV(TWIE) | _BV(TWSTA) | (twcr & _BV(TWSTO)));
00572             }
00573         }
00574     }
00575 
00576     /* Clear the queue. */
00577     //*broken?! NutEventBroadcastAsync(&tw_mm_que);
00578     if (tw_mm_que == SIGNALED) {
00579         tw_mm_que = 0;
00580     }
00581     NutExitCritical();
00582 
00583     /*
00584      * Wait for master transmission done.
00585      */
00586     rc = -1;
00587     if (NutEventWait(&tw_mm_que, tmo)) {
00588         tw_mm_error = TWERR_TIMEOUT;
00589     } else {
00590         NutEnterCritical();
00591         if (tw_mm_err) {
00592             tw_mm_error = tw_mm_err;
00593         } else {
00594             rc = tw_mr_idx;
00595         }
00596         NutExitCritical();
00597     }
00598 
00599     /*
00600      * Release the interface.
00601      */
00602     NutEventPost(&tw_mm_mutex);
00603 
00604 #endif /* __AVR_ENHANCED__ */
00605     return rc;
00606 }
00607 
00617 int TwMasterError(void)
00618 {
00619 #ifndef __AVR_ENHANCED__
00620     return -1;
00621 #else
00622     int rc = (int) tw_mm_error;
00623     tw_mm_error = 0;
00624     return rc;
00625 #endif
00626 }
00627 
00650 int TwSlaveListen(u_char * sla, void *rxdata, u_short rxsiz, u_long tmo)
00651 {
00652 #ifndef __AVR_ENHANCED__
00653     return -1;
00654 #else
00655     int rc = -1;
00656 
00657     NutEnterCritical();
00658 
00659     /* Initialize parameters for slave receive. */
00660     tw_sm_err = 0;
00661     tw_sr_siz = rxsiz;
00662     tw_sr_buf = rxdata;
00663 
00664     /*
00665      * If the interface is currently not busy then enable it for
00666      * address recognition.
00667      */
00668     if(tw_if_bsy == 0) {
00669         u_char twsr = inb(TWSR);
00670         if((twsr & 0xF8) == TW_NO_INFO) {
00671             if(tw_mt_len || tw_mr_siz)
00672                 outb(TWCR, _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA));
00673             else
00674                 outb(TWCR, _BV(TWEA) | _BV(TWEN) | _BV(TWIE));
00675         }
00676     }
00677 
00678     /* Clear the queue. */
00679     //*broken?! NutEventBroadcastAsync(&tw_sr_que);
00680     if (tw_sr_que == SIGNALED) {
00681         tw_sr_que = 0;
00682     }
00683 
00684     NutExitCritical();
00685 
00686     /* Wait for a frame on the slave mode queue. */
00687     if (NutEventWait(&tw_sr_que, tmo)) {
00688         NutEnterCritical();
00689         tw_sm_err = TWERR_TIMEOUT;
00690         tw_sr_siz = 0;
00691         NutExitCritical();
00692     }
00693 
00694     /*
00695      * Return the number of bytes received and the destination slave
00696      * address, if no slave error occured. In this case the bus is
00697      * blocked.
00698      */
00699     if(tw_sm_err == 0) {
00700         rc = tw_sr_idx;
00701         *sla = tw_sm_sla;
00702     }
00703     return rc;
00704 #endif /* __AVR_ENHANCED__ */
00705 }
00706 
00724 int TwSlaveRespond(void *txdata, u_short txlen, u_long tmo)
00725 {
00726     int rc = -1;
00727 #ifdef __AVR_ENHANCED__
00728 
00729     /* The bus is blocked. No critical section required. */
00730     tw_st_buf = txdata;
00731     tw_st_len = txlen;
00732 
00733     /*
00734      * If there is anything to transmit, start the interface.
00735      */
00736     if (txlen) {
00737         NutEnterCritical();
00738         /* Clear the queue. */
00739         //*broken?! NutEventBroadcastAsync(&tw_st_que);
00740         if (tw_st_que == SIGNALED) {
00741             tw_st_que = 0;
00742         }
00743 
00744         /* Release the bus, accepting SLA+R. */
00745         outb(TWCR, TWGO | _BV(TWEA));
00746 
00747         NutExitCritical();
00748         if (NutEventWait(&tw_st_que, tmo)) {
00749             tw_sm_err = TWERR_TIMEOUT;
00750         }
00751 
00752         NutEnterCritical();
00753         tw_st_len = 0;
00754         if (tw_sm_err) {
00755             tw_sm_error = tw_sm_err;
00756         } else {
00757             rc = tw_st_idx;
00758         }
00759         NutExitCritical();
00760     }
00761 
00762     /*
00763      * Nothing to transmit.
00764      */
00765     else {
00766         u_char twcr;
00767         u_char twsr;
00768         rc = 0;
00769         /* Release the bus, not accepting SLA+R. */
00770 
00771         NutEnterCritical();
00772         twcr = inb(TWCR);
00773         twsr = inb(TWSR);
00774         /* Transmit start condition, if a master transfer is waiting. */
00775         if (tw_mt_len || tw_mr_siz) {
00776             outb(TWCR, TWGO | _BV(TWSTA));
00777         }
00778         /* Otherwise enter idle state. */
00779         else {
00780             tw_if_bsy = 0;
00781             outb(TWCR, TWGO);
00782         }
00783 
00784         NutExitCritical();
00785     }
00786 #endif /* __AVR_ENHANCED__ */
00787     return rc;
00788 }
00789 
00799 int TwSlaveError(void)
00800 {
00801 #ifndef __AVR_ENHANCED__
00802     return -1;
00803 #else
00804     int rc = (int) tw_sm_error;
00805     tw_sm_error = 0;
00806     return rc;
00807 #endif
00808 }
00809 
00827 int TwIOCtl(int req, void *conf)
00828 {
00829 #ifndef __AVR_ENHANCED__
00830     return -1;
00831 #else
00832     int rc = 0;
00833     u_long lval;
00834 
00835     switch (req) {
00836     case TWI_SETSLAVEADDRESS:
00837         TWAR = (*((u_char *) conf) << 1) | 1;
00838         break;
00839     case TWI_GETSLAVEADDRESS:
00840         *((u_char *) conf) = TWAR;
00841         break;
00842 
00843     case TWI_SETSPEED:
00844         lval = ((2UL * NutGetCpuClock() / (*((u_long *) conf)) + 1UL) / 2UL - 16UL) / 2UL;
00845         if (lval > 1020UL) {
00846             lval /= 16UL;
00847             sbi(TWSR, TWPS1);
00848         } else {
00849             cbi(TWSR, TWPS1);
00850         }
00851         if (lval > 255UL) {
00852             lval /= 4UL;
00853             sbi(TWSR, TWPS0);
00854         } else {
00855             cbi(TWSR, TWPS0);
00856         }
00857         if (lval > 9UL && lval < 256UL) {
00858             outb(TWBR, (u_char) lval);
00859         } else {
00860             rc = -1;
00861         }
00862         break;
00863     case TWI_GETSPEED:
00864         lval = 2UL;
00865         if (bit_is_set(TWSR, TWPS0)) {
00866             lval *= 4UL;
00867         }
00868         if (bit_is_set(TWSR, TWPS1)) {
00869             lval *= 16UL;
00870         }
00871         *((u_long *) conf) = NutGetCpuClock() / (16UL + lval * (u_long) inb(TWBR));
00872         break;
00873 
00874     case TWI_GETSTATUS:
00875         break;
00876     case TWI_SETSTATUS:
00877         break;
00878 
00879     default:
00880         rc = -1;
00881         break;
00882     }
00883     return rc;
00884 #endif /* __AVR_ENHANCED__ */
00885 }
00886 
00899 int TwInit(u_char sla)
00900 {
00901 #ifndef __AVR_ENHANCED__
00902     return -1;
00903 #else
00904     u_long speed = 2400;
00905 
00906     if (NutRegisterIrqHandler(&sig_2WIRE_SERIAL, TwInterrupt, 0)) {
00907         return -1;
00908     }
00909 
00910     /*
00911      * Set address register, enable general call address, set transfer
00912      * speed and enable interface.
00913      */
00914     outb(TWAR, (sla << 1) | 1);
00915     TwIOCtl(TWI_SETSPEED, &speed);
00916     outb(TWCR, _BV(TWINT));
00917     outb(TWCR, _BV(TWEN) | _BV(TWIE));
00918 
00919     /*
00920      * Initialize mutex semaphores.
00921      */
00922     NutEventPost(&tw_mm_mutex);
00923 
00924     return 0;
00925 #endif /* __AVR_ENHANCED__ */
00926 }

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