⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 twif.c

📁 含有完整TCP/IP PPP协议的嵌入式操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2001-2005 by egnite Software GmbH. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of *    contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ * *//* * $Log: twif.c,v $ * Revision 1.3  2005/10/24 10:56:30  haraldkipp * Added const modifier to transmit data pointer in TwMasterTransact(). * * Revision 1.2  2005/10/07 22:03:29  hwmaier * Using __AVR_ENHANCED__ macro instead of __AVR_ATmega128__ to support also AT90CAN128 MCU * * Revision 1.1  2005/07/26 18:02:40  haraldkipp * Moved from dev. * * Revision 1.9  2005/01/24 21:12:05  freckle * renamed NutEventPostFromIRQ into NutEventPostFromIrq * * Revision 1.8  2005/01/21 16:49:46  freckle * Seperated calls to NutEventPostAsync between Threads and IRQs * * Revision 1.7  2004/12/16 08:40:35  haraldkipp * Late increment fixes ICCAVR bug. * * Revision 1.6  2004/11/08 18:12:59  haraldkipp * Soooo many fixes, but I'm tired...really. * * Revision 1.5  2004/09/08 10:19:14  haraldkipp * *** empty log message *** * * Revision 1.4  2003/11/03 17:03:53  haraldkipp * Many new comments added * * Revision 1.3  2003/07/20 18:28:10  haraldkipp * Explain how to disable timeout. * * Revision 1.2  2003/07/17 09:38:07  haraldkipp * Setting different speeds is now supported. * * Revision 1.1.1.1  2003/05/09 14:40:53  haraldkipp * Initial using 3.2.1 * * Revision 1.2  2003/03/31 14:53:08  harald * Prepare release 3.1 * * Revision 1.1  2003/02/04 17:54:59  harald * *** empty log message *** * */#include <string.h>#include <dev/irqreg.h>#include <sys/event.h>#include <sys/atom.h>#include <sys/timer.h>#include <sys/thread.h>#include <sys/heap.h>#include <dev/twif.h>#ifdef __AVR_ENHANCED__static volatile u_char tw_if_bsy;   /* Set while interface is busy. */HANDLE tw_mm_mutex;          /* Exclusive master access. */HANDLE tw_mm_que;            /* Threads waiting for master transfer done. */HANDLE tw_sr_que;            /* Threads waiting for slave receive. */HANDLE tw_st_que;            /* Threads waiting for slave transmit done. */static u_char tw_mm_sla;            /* Destination slave address. */static volatile u_char tw_mm_err;   /* Current master mode error. */static u_char tw_mm_error;          /* Last master mode error. */static CONST u_char *tw_mt_buf;     /* Pointer to the master transmit buffer. */static volatile u_short tw_mt_len;  /* Number of bytes to transmit in master mode. */static volatile u_short tw_mt_idx;  /* Current master transmit buffer index. */static u_char *tw_mr_buf;           /* Pointer to the master receive buffer. */static volatile u_short tw_mr_siz;  /* Size of the master receive buffer. */static volatile u_short tw_mr_idx;  /* Current master receive buffer index. */static volatile u_char tw_sm_sla;   /* Slave address received. */static volatile u_char tw_sm_err;   /* Current slave mode error. */static u_char tw_sm_error;          /* Last slave mode error. */static u_char *tw_st_buf;           /* Pointer to the slave transmit buffer. */static volatile u_short tw_st_len;  /* Number of bytes to transmit in slave mode. */static volatile u_short tw_st_idx;  /* Current slave transmit buffer index. */static u_char *tw_sr_buf;           /* Pointer to the slave receive buffer. */static volatile u_short tw_sr_siz;  /* Size of the master receive buffer. */static volatile u_short tw_sr_idx;  /* Current slave receive buffer index. *//*TWINT TWEA TWSTA TWSTO TWWC TWEN  0  TWIE  C                      R        R*/#define TWGO    (_BV(TWINT) | _BV(TWEN) | _BV(TWIE))/* * TWI interrupt handler. */static void TwInterrupt(void *arg){    u_char twsr;    register u_char twcr = inb(TWCR);    /*     * Read the status and interpret its contents.     */    twsr = inb(TWSR) & 0xF8;    switch (twsr) {    /*     * 0x08: Start condition has been transmitted.     * 0x10: Repeated start condition has been transmitted.     */    case TW_START:    case TW_REP_START:        /* We are entering the master mode. Mark the interface busy. */        tw_if_bsy = 1;        tw_mt_idx = 0;        tw_mr_idx = 0;        /*         * If outgoing data is available, transmit SLA+W. Logic is in         * master transmit mode.         */        if (tw_mt_len) {            outb(TWDR, tw_mm_sla);        }        /*         * If outgoing data not available, transmit SLA+R. Logic will         * switch to master receiver mode.         */        else {            outb(TWDR, tw_mm_sla | 1);        }        outb(TWCR, TWGO | (twcr & _BV(TWEA)));        break;    /*     * 0x18: SLA+W has been transmitted and ACK has been received.     * 0x28: Data byte has been transmitted and ACK has been received.     */    case TW_MT_SLA_ACK:    case TW_MT_DATA_ACK:        /*         * If outgoing data left to send, put the next byte in the data         * register.         */        if (tw_mt_idx < tw_mt_len) {            outb(TWDR, tw_mt_buf[tw_mt_idx]);            /* Late increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */            tw_mt_idx++;            outb(TWCR, TWGO | (twcr & _BV(TWEA)));            break;        }        /*         * All outgoing data has been sent. If a response is expected,         * transmit a repeated start condition.         */        tw_mt_len = 0;        if (tw_mr_siz) {            outb(TWCR, TWGO | (twcr & _BV(TWEA)) | _BV(TWSTA));            break;        }    /*     * 0x20: SLA+W has been transmitted, but not acknowledged.     * 0x30: Data byte has been transmitted, but not acknowledged.     * 0x48: SLA+R has been transmitted, but not acknowledged.     */    case TW_MT_SLA_NACK:    case TW_MT_DATA_NACK:    case TW_MR_SLA_NACK:        /* Set unique error code. */        if (twsr == TW_MT_SLA_NACK || twsr == TW_MR_SLA_NACK) {            tw_mm_err = TWERR_SLA_NACK;            tw_mt_len = 0;            tw_mr_siz = 0;        }        /* Wake up the application. */        NutEventPostFromIrq(&tw_mm_que);        /*         * Send a stop condition. If we have a listener, generate         * an acknowlegde on an incoming address byte.         */        if(tw_sr_siz) {            outb(TWCR, TWGO | _BV(TWEA) | _BV(TWSTO));        }        else {            outb(TWCR, TWGO | _BV(TWSTO));        }        /* The interface is idle. */        tw_if_bsy = 0;        break;    /*     * 0x38: Arbitration lost while in master mode.     */    case TW_MT_ARB_LOST:        /*         * The start condition will be automatically resend after         * the bus becomes available.         */        sbi(TWCR, TWSTA);        /* The interface is idle. */        tw_if_bsy = 0;        break;    /*     * 0x50: Data byte has been received and acknowledged.     */    case TW_MR_DATA_ACK:        /*         * Store the data byte in the master receive buffer.         */        tw_mr_buf[tw_mr_idx] = inb(TWDR);        /* Late increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */        tw_mr_idx++;    /*     * 0x40: SLA+R has been transmitted and ACK has been received.     */    case TW_MR_SLA_ACK:        /*         * Acknowledge next data bytes except the last one.         */        if (tw_mr_idx + 1 < tw_mr_siz) {            outb(TWCR, TWGO | _BV(TWEA));        }        else {            outb(TWCR, TWGO);        }        break;    /*     * 0x58: Data byte has been received, but not acknowledged.     */    case TW_MR_DATA_NACK:        /*         * Store the last data byte.         */        tw_mr_buf[tw_mr_idx] = inb(TWDR);        /* Late increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */        tw_mr_idx++;        tw_mr_siz = 0;        /* Wake up the application. */        NutEventPostFromIrq(&tw_mm_que);        /*         * Send a stop condition. If we have a listener, generate         * an acknowlegde on an incoming address byte.         */        if(tw_sr_siz) {            outb(TWCR, TWGO | _BV(TWEA) | _BV(TWSTO));        }        else {            outb(TWCR, TWGO | _BV(TWSTO));        }        /* The interface is idle. */        tw_if_bsy = 0;        break;    /*     * 0x60: Own SLA+W has been received and acknowledged.     * 0x68: Arbitration lost as master. Own SLA+W has been received     *       and acknowledged.     * 0x70: General call address has been received and acknowledged.     * 0x78: Arbitration lost as master. General call address has been     *       received and acknowledged.     */    case TW_SR_SLA_ACK:    case TW_SR_ARB_LOST_SLA_ACK:    case TW_SR_GCALL_ACK:    case TW_SR_ARB_LOST_GCALL_ACK:        /*         * Do only acknowledge incoming data bytes, if we got receive         * buffer space. Fetch the slave address from the data register         * and reset the receive index.         */        if (tw_sr_siz) {            /* We are entering the slave receive mode. Mark the interface busy. */            tw_if_bsy = 1;            tw_sm_sla = inb(TWDR);            outb(TWCR, TWGO | _BV(TWEA));            tw_sr_idx = 0;        }        /*         * Do not acknowledge incoming data.         */        else {            outb(TWCR, TWGO);        }        break;    /*     * 0x80: Data byte for own SLA has been received and acknowledged.     * 0x90: Data byte for general call address has been received and     *       acknowledged.     */    case TW_SR_DATA_ACK:    case TW_SR_GCALL_DATA_ACK:        /*         * If the receive buffer isn't filled up, store data byte.         */        if (tw_sr_idx < tw_sr_siz) {            tw_sr_buf[tw_sr_idx] = inb(TWDR);            /* Late increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */            tw_sr_idx++;        }        else {            tw_sr_siz = 0;        }        /*         * If more space is available for incoming data, then continue         * receiving. Otherwise do not acknowledge new data bytes.         */        if (tw_sr_siz) {            outb(TWCR, TWGO | _BV(TWEA));            break;        }    /*     * 0x88: Data byte received, but not acknowledged.     * 0x98: Data byte for general call address received, but not     *       acknowledged.     */    case TW_SR_DATA_NACK:    case TW_SR_GCALL_DATA_NACK:        /*         * Continue not accepting more data.         */        if (tw_mt_len || tw_mr_siz) {            outb(TWCR, inb(TWCR) | _BV(TWEA) | _BV(TWSTA));        }        else {            outb(TWCR, inb(TWCR) | _BV(TWEA));        }        break;    /*     * 0xA0: Stop condition or repeated start condition received.     */    case TW_SR_STOP:        /*         * Wake up the application. If successful, do nothing. This         * will keep SCL low and thus block the bus. The application         * must now setup the transmit buffer and re-enable the         * interface.         */        if (NutEventPostFromIrq(&tw_sr_que) == 0 || tw_sm_err) {            /*             * If no one has been waiting on the queue, the application             * probably gave up waiting. So we continue on our own, either             * in idle mode or switching to master mode if a master             * request is waiting.             */            if (tw_mt_len || tw_mr_siz) {                outb(TWCR, TWGO | _BV(TWSTA));            }            else {                outb(TWCR, TWGO);            }            tw_if_bsy = 0;        }        else {            tw_sr_siz = 0;            outb(TWCR, twcr & ~(_BV(TWINT) | _BV(TWIE)));        }        break;    /*     * 0xA8: Own SLA+R has been received and acknowledged.     * 0xB0: Arbitration lost in master mode. Own SLA has been received     *       and acknowledged.     */    case TW_ST_SLA_ACK:    case TW_ST_ARB_LOST_SLA_ACK:        /* Not idle. */        tw_if_bsy = 1;        /* Reset transmit index and fall through for outgoing data. */        tw_st_idx = 0;    /*     * 0xB8: Data bytes has been transmitted and acknowledged.     */    case TW_ST_DATA_ACK:        /*         * If outgoing data left to send, put the next byte in the         * data register. Otherwise transmit a dummy byte.         */        if (tw_st_idx < tw_st_len) {            outb(TWDR, tw_st_buf[tw_st_idx]);            /* Do not set acknowledge on the last data byte. */            /* Early increment fixes ICCAVR bug. Thanks to Andreas Siebert and Michael Fischer. */            ++tw_st_idx;            if (tw_st_idx < tw_st_len) {                outb(TWCR, TWGO | _BV(TWEA));            }            else {                tw_st_len = 0;                outb(TWCR, TWGO);            }            break;        }        /* No more data. Continue sending dummies. */        outb(TWDR, 0);        outb(TWCR, TWGO);        break;    /*     * 0xC0: Data byte has been transmitted, but not acknowledged.     * 0xC8: Last data byte has been transmitted and acknowledged.     */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -