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

📄 twif.c

📁 avr上的RTOS
💻 C
📖 第 1 页 / 共 2 页
字号:
    case TW_ST_DATA_NACK:    case TW_ST_LAST_DATA:        NutEventPostFromIrq(&tw_st_que);        /* Transmit start condition, if a master transfer is waiting. */        if (tw_mt_len || tw_mr_siz) {            outb(TWCR, TWGO | _BV(TWSTA) | /**/ _BV(TWEA));        }        /* Otherwise enter idle state. */        else {            outb(TWCR, TWGO | _BV(TWEA));        }        tw_if_bsy = 0;        break;    /*     * 0x00: Bus error.     */    case TW_BUS_ERROR:        outb(TWCR, inb(TWCR) | _BV(TWSTO));#if 1        tw_if_bsy = 0;        tw_mm_err = TWERR_BUS;        tw_sm_err = TWERR_BUS;        NutEventPostFromIrq(&tw_sr_que);        NutEventPostFromIrq(&tw_st_que);        NutEventPostFromIrq(&tw_mm_que);#endif        break;    }}#endif /* __AVR_ENHANCED__ *//*! * \brief Transmit and/or receive data as a master. * * The two-wire serial interface must have been initialized by calling * TwInit() before this function can be used. * * \note This function is only available on ATmega128 systems. * * \param sla    Slave address of the destination. This slave address *               must be specified as a 7-bit address. For example, the *               PCF8574A may be configured to slave addresses from 0x38 *               to 0x3F. * \param txdata Points to the data to transmit. Ignored, if the number *               of data bytes to transmit is zero. * \param txlen  Number of data bytes to transmit. If zero, then the *               interface will not send any data to the slave device *               and will directly enter the master receive mode. * \param rxdata Points to a buffer, where the received data will be *               stored. Ignored, if the maximum number of bytes to *               receive is zero. * \param rxsiz  Maximum number of bytes to receive. Set to zero, if *               no bytes are expected from the slave device. * \param tmo    Timeout in milliseconds. To disable timeout, set this *               parameter to NUT_WAIT_INFINITE. * * \return The number of bytes received, -1 in case of an error or timeout. * * \bug Joel Dotreppe reported, that TwMasterTransact() doesn't work when *      passing 0 for txdata and txlen. Though, I'm not able to verify this. */int TwMasterTransact(u_char sla, CONST void *txdata, u_short txlen, void *rxdata, u_short rxsiz, u_long tmo){    int rc = -1;#ifdef __AVR_ENHANCED__    /* This routine is marked reentrant, so lock the interface. */    if(NutEventWait(&tw_mm_mutex, 500)) {        tw_mm_err = TWERR_IF_LOCKED;        NutEventPost(&tw_mm_mutex);        return -1;    }    while(tw_if_bsy) {        NutSleep(63);    }    NutEnterCritical();    /*     * Set all parameters for master mode.     */    tw_mm_sla = sla << 1;    tw_mm_err = 0;    tw_mt_len = txlen;    tw_mt_buf = txdata;    tw_mr_siz = rxsiz;    tw_mr_buf = rxdata;    /*     * Send a start condition if the interface is idle. If busy, then     * the interrupt routine will automatically initiate the transfer     * as soon as the interface becomes ready again.     */    if(tw_if_bsy == 0) {        u_char twcr = inb(TWCR);        u_char twsr = inb(TWSR);        if((twsr & 0xF8) == TW_NO_INFO) {            if(tw_sr_siz) {                outb(TWCR, _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWSTA) | (twcr & _BV(TWSTO)));            }            else {                outb(TWCR, _BV(TWEN) | _BV(TWIE) | _BV(TWSTA) | (twcr & _BV(TWSTO)));            }        }    }    /* Clear the queue. */    //*broken?! NutEventBroadcastAsync(&tw_mm_que);    if (tw_mm_que == SIGNALED) {        tw_mm_que = 0;    }    NutExitCritical();    /*     * Wait for master transmission done.     */    rc = -1;    if (NutEventWait(&tw_mm_que, tmo)) {        tw_mm_error = TWERR_TIMEOUT;    } else {        NutEnterCritical();        if (tw_mm_err) {            tw_mm_error = tw_mm_err;        } else {            rc = tw_mr_idx;        }        NutExitCritical();    }    /*     * Release the interface.     */    NutEventPost(&tw_mm_mutex);#endif /* __AVR_ENHANCED__ */    return rc;}/*! * \brief Get last master mode error. * * You may call this function to determine the specific cause * of an error after TwMasterTransact() failed. * * \note This function is only available on ATmega128 systems. * */int TwMasterError(void){#ifndef __AVR_ENHANCED__    return -1;#else    int rc = (int) tw_mm_error;    tw_mm_error = 0;    return rc;#endif}/*! * \brief Listen for incoming data from a master. * * If this function returns without error, the bus is blocked. The caller * must immediately process the request and return a response by calling * TwSlaveRespond(). * * \note This function is only available on ATmega128 systems. The *       function is not reentrant. * * \param sla    Points to a byte variable, which receives the slave *               address sent by the master. This can be used by the *               caller to determine whether the the interface has been *               addressed by a general call or its individual address. * \param rxdata Points to a data buffer where the received data bytes *               are stored. * \param rxsize Specifies the maximum number of data bytes to receive. * \param tmo	 Timeout in milliseconds. To disable timeout, *               set this parameter to NUT_WAIT_INFINITE. * * \return The number of bytes received, -1 in case of an error or timeout. */int TwSlaveListen(u_char * sla, void *rxdata, u_short rxsiz, u_long tmo){#ifndef __AVR_ENHANCED__    return -1;#else    int rc = -1;    NutEnterCritical();    /* Initialize parameters for slave receive. */    tw_sm_err = 0;    tw_sr_siz = rxsiz;    tw_sr_buf = rxdata;    /*     * If the interface is currently not busy then enable it for     * address recognition.     */    if(tw_if_bsy == 0) {        u_char twsr = inb(TWSR);        if((twsr & 0xF8) == TW_NO_INFO) {            if(tw_mt_len || tw_mr_siz)                outb(TWCR, _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA));            else                outb(TWCR, _BV(TWEA) | _BV(TWEN) | _BV(TWIE));        }    }    /* Clear the queue. */    //*broken?! NutEventBroadcastAsync(&tw_sr_que);    if (tw_sr_que == SIGNALED) {        tw_sr_que = 0;    }    /* Wait for a frame on the slave mode queue. */    if (NutEventWait(&tw_sr_que, tmo)) {        NutEnterCritical();        tw_sm_err = TWERR_TIMEOUT;        tw_sr_siz = 0;        NutExitCritical();    }    NutExitCritical();    /*     * Return the number of bytes received and the destination slave     * address, if no slave error occured. In this case the bus is     * blocked.     */    if(tw_sm_err == 0) {        rc = tw_sr_idx;        *sla = tw_sm_sla;    }    return rc;#endif /* __AVR_ENHANCED__ */}/*! * \brief Send response to a master. * * This function must be called as soon as possible after TwSlaveListen() * returned successfully, even if no data needs to be returned. Not doing * so will completely block the bus. * * \note This function is only available on ATmega128 systems. * * \param txdata Points to the data to transmit. Ignored, if the *      		 number of bytes to transmit is zero. * \param txlen  Number of data bytes to transmit. * \param tmo	 Timeout in milliseconds. To disable timeout, *               set this parameter to NUT_WAIT_INFINITE. * * \return The number of bytes transmitted, -1 in case of an error or timeout. */int TwSlaveRespond(void *txdata, u_short txlen, u_long tmo){    int rc = -1;#ifdef __AVR_ENHANCED__    /* The bus is blocked. No critical section required. */    tw_st_buf = txdata;    tw_st_len = txlen;    /*     * If there is anything to transmit, start the interface.     */    if (txlen) {        NutEnterCritical();        /* Clear the queue. */        //*broken?! NutEventBroadcastAsync(&tw_st_que);        if (tw_st_que == SIGNALED) {            tw_st_que = 0;        }        /* Release the bus, accepting SLA+R. */        outb(TWCR, TWGO | _BV(TWEA));        NutExitCritical();        if (NutEventWait(&tw_st_que, tmo)) {            tw_sm_err = TWERR_TIMEOUT;        }        NutEnterCritical();        tw_st_len = 0;        if (tw_sm_err) {            tw_sm_error = tw_sm_err;        } else {            rc = tw_st_idx;        }        NutExitCritical();    }    /*     * Nothing to transmit.     */    else {        u_char twcr;        u_char twsr;        rc = 0;        /* Release the bus, not accepting SLA+R. */        NutEnterCritical();        twcr = inb(TWCR);        twsr = inb(TWSR);        /* Transmit start condition, if a master transfer is waiting. */        if (tw_mt_len || tw_mr_siz) {            outb(TWCR, TWGO | _BV(TWSTA));        }        /* Otherwise enter idle state. */        else {            tw_if_bsy = 0;            outb(TWCR, TWGO);        }        NutExitCritical();    }#endif /* __AVR_ENHANCED__ */    return rc;}/*! * \brief Get last slave mode error. * * You may call this function to determine the specific cause * of an error after TwSlaveListen() or TwSlaveRespond() failed. * * \note This function is only available on ATmega128 systems. * */int TwSlaveError(void){#ifndef __AVR_ENHANCED__    return -1;#else    int rc = (int) tw_sm_error;    tw_sm_error = 0;    return rc;#endif}/*! * \brief Perform TWI control functions. * * This function is only available on ATmega128 systems. * * \param req  Requested control function. May be set to one of the *	       following constants: *	       - TWI_SETSPEED, if conf points to an u_long value containing the bitrate. *	       - TWI_GETSPEED, if conf points to an u_long value receiving the current bitrate. * \param conf Points to a buffer that contains any data required for *	       the given control function or receives data from that *	       function. * \return 0 on success, -1 otherwise. * * \note Timeout is limited to the granularity of the system timer. * */int TwIOCtl(int req, void *conf){#ifndef __AVR_ENHANCED__    return -1;#else    int rc = 0;    u_long lval;    switch (req) {    case TWI_SETSLAVEADDRESS:        TWAR = (*((u_char *) conf) << 1) | 1;        break;    case TWI_GETSLAVEADDRESS:        *((u_char *) conf) = TWAR;        break;    case TWI_SETSPEED:        lval = ((2UL * NutGetCpuClock() / (*((u_long *) conf)) + 1UL) / 2UL - 16UL) / 2UL;        if (lval > 1020UL) {            lval /= 16UL;            sbi(TWSR, TWPS1);        } else {            cbi(TWSR, TWPS1);        }        if (lval > 255UL) {            lval /= 4UL;            sbi(TWSR, TWPS0);        } else {            cbi(TWSR, TWPS0);        }        if (lval > 9UL && lval < 256UL) {            outb(TWBR, (u_char) lval);        } else {            rc = -1;        }        break;    case TWI_GETSPEED:        lval = 2UL;        if (bit_is_set(TWSR, TWPS0)) {            lval *= 4UL;        }        if (bit_is_set(TWSR, TWPS1)) {            lval *= 16UL;        }        *((u_long *) conf) = NutGetCpuClock() / (16UL + lval * (u_long) inb(TWBR));        break;    case TWI_GETSTATUS:        break;    case TWI_SETSTATUS:        break;    default:        rc = -1;        break;    }    return rc;#endif /* __AVR_ENHANCED__ */}/*! * \brief Initialize TWI interface. * * The specified slave address is used only, if the local system * is running as a slave. Anyway, care must be taken that it doesn't * conflict with another connected device. * * \note This function is only available on ATmega128 systems. * * \param sla Slave address, must be specified as a 7-bit address, *            always lower than 128. */int TwInit(u_char sla){#ifndef __AVR_ENHANCED__    return -1;#else    u_long speed = 2400;    if (NutRegisterIrqHandler(&sig_2WIRE_SERIAL, TwInterrupt, 0)) {        return -1;    }    /*     * Set address register, enable general call address, set transfer     * speed and enable interface.     */    outb(TWAR, (sla << 1) | 1);    TwIOCtl(TWI_SETSPEED, &speed);    outb(TWCR, _BV(TWINT));    outb(TWCR, _BV(TWEN) | _BV(TWIE));    /*     * Initialize mutex semaphores.     */    NutEventPost(&tw_mm_mutex);    return 0;#endif /* __AVR_ENHANCED__ */}

⌨️ 快捷键说明

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