📄 twif.c
字号:
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 + -