/** * @brief Receives data from the I2C bus. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] addr slave device address (7 bits) without R/W bit * @param[out] rxbuf pointer to receive buffer * @param[in] rxbytes number of bytes to be received * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_INFINITE no timeout. * . * * @return The operation status. * @retval RDY_OK if the function succeeded. * @retval RDY_RESET if one or more I2C errors occurred, the errors can * be retrieved using @p i2cGetErrors(). * @retval RDY_TIMEOUT if a timeout occurred before operation end. * * @api */ msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp, i2caddr_t addr, uint8_t *rxbuf, size_t rxbytes, systime_t timeout){ msg_t rdymsg; chDbgCheck((i2cp != NULL) && (addr != 0) && (rxbytes > 0) && (rxbuf != NULL) && (timeout != TIME_IMMEDIATE), "i2cMasterReceiveTimeout"); chDbgAssert(i2cp->state == I2C_READY, "i2cMasterReceive(), #1", "not ready"); chSysLock(); i2cp->errors = I2CD_NO_ERROR; i2cp->state = I2C_ACTIVE_RX; rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout); if (rdymsg == RDY_TIMEOUT) i2cp->state = I2C_LOCKED; else i2cp->state = I2C_READY; chSysUnlock(); return rdymsg; }
/** * @brief Receives data from the I2C bus. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] addr slave device address (7 bits) without R/W bit * @param[out] rxbuf pointer to receive buffer * @param[in] rxbytes number of bytes to be received * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_INFINITE no timeout. * . * * @return The operation status. * @retval MSG_OK if the function succeeded. * @retval MSG_RESET if one or more I2C errors occurred, the errors can * be retrieved using @p i2cGetErrors(). * @retval MSG_TIMEOUT if a timeout occurred before operation end. * * @api */ msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp, i2caddr_t addr, uint8_t *rxbuf, size_t rxbytes, sysinterval_t timeout) { msg_t rdymsg; osalDbgCheck((i2cp != NULL) && (addr != 0U) && (rxbytes > 0U) && (rxbuf != NULL) && (timeout != TIME_IMMEDIATE)); osalDbgAssert(i2cp->state == I2C_READY, "not ready"); osalSysLock(); i2cp->errors = I2C_NO_ERROR; i2cp->state = I2C_ACTIVE_RX; rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout); if (rdymsg == MSG_TIMEOUT) { i2cp->state = I2C_LOCKED; } else { i2cp->state = I2C_READY; } osalSysUnlock(); return rdymsg; }
/** * @brief Transmits data via the I2C bus as master. * @details When performing reading through write you can not write more than * 3 bytes of data to I2C slave. This is SAM7 platform limitation. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] addr slave device address * @param[in] txbuf pointer to the transmit buffer * @param[in] txbytes number of bytes to be transmitted * @param[out] rxbuf pointer to the receive buffer * @param[in] rxbytes number of bytes to be received * @param[in] timeout this value is ignored on SAM7 platform. * . * @return The operation status. * @retval RDY_OK if the function succeeded. * @retval RDY_RESET if one or more I2C errors occurred, the errors can * be retrieved using @p i2cGetErrors(). * * @notapi */ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, const uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, size_t rxbytes, systime_t timeout) { (void)timeout; /* SAM7 specific check */ chDbgCheck(((rxbytes == 0) || ((txbytes > 0) && (txbytes < 4) && (rxbuf != NULL))), "i2c_lld_master_transmit_timeout"); /* prepare to read through write operation */ if (rxbytes > 0){ AT91C_BASE_TWI->TWI_MMR |= txbytes << 8; /* store internal slave address in TWI_IADR registers */ AT91C_BASE_TWI->TWI_IADR = 0; while (txbytes > 0){ AT91C_BASE_TWI->TWI_IADR = (AT91C_BASE_TWI->TWI_IADR << 8); AT91C_BASE_TWI->TWI_IADR |= *(txbuf++); txbytes--; } /* Internal address of I2C slave was set in special Atmel registers. * Now we must call read function. The I2C cell automatically sends * bytes from IADR register to bus and issues repeated start. */ return i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout); } else{ if (txbytes == 1){ /* In single data byte master read or write, the START and STOP * must both be set. */ AT91C_BASE_TWI->TWI_CR |= AT91C_TWI_STOP; } AT91C_BASE_TWI->TWI_MMR = 0; AT91C_BASE_TWI->TWI_MMR |= addr << 16; /* enable just needed interrupts */ AT91C_BASE_TWI->TWI_IER = AT91C_TWI_TXRDY | AT91C_TWI_NACK; /* correct size and pointer because first byte will be written * for issue start condition */ i2cp->txbuf = txbuf + 1; i2cp->txbytes = txbytes - 1; /* According to datasheet there is no need to set START manually * we just need to write first byte in THR */ AT91C_BASE_TWI->TWI_THR = txbuf[0]; /* Waits for the operation completion.*/ i2cp->thread = chThdSelf(); chSchGoSleepS(THD_STATE_SUSPENDED); return chThdSelf()->p_u.rdymsg; } }
/** * @brief Master transmission. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] addr slave device address (7 bits) without R/W bit * @param[in] txbuf transmit data buffer pointer * @param[in] txbytes number of bytes to be transmitted * @param[out] rxbuf receive data buffer pointer * @param[in] rxbytes number of bytes to be received * @param[in] timeout the number of ticks before the operation timeouts, * the following special values are allowed: * - @a TIME_INFINITE no timeout. * . * * @notapi */ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, const uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, const uint8_t rxbytes, systime_t timeout) { VirtualTimer vt; /* Global timeout for the whole operation.*/ if (timeout != TIME_INFINITE) chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp); i2cp->addr = addr; i2cp->txbuf = txbuf; i2cp->txbytes = txbytes; i2cp->txidx = 0; i2cp->rxbuf = rxbuf; i2cp->rxbytes = rxbytes; i2cp->rxidx = 0; bscdevice_t *device = i2cp->device; device->slaveAddress = addr; device->dataLength = txbytes; device->status = CLEAR_STATUS; /* Enable Interrupts and start transfer.*/ device->control |= (BSC_INTT | BSC_INTD | START_WRITE); /* Is this really needed? there is an outer lock already */ chSysLock(); i2cp->thread = chThdSelf(); chSchGoSleepS(THD_STATE_SUSPENDED); if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) chVTResetI(&vt); chSysUnlock(); msg_t status = chThdSelf()->p_u.rdymsg; if (status == RDY_OK && rxbytes > 0) { /* The TIMEOUT_INFINITE prevents receive from setting up it's own timer.*/ status = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, TIME_INFINITE); if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt)) chVTResetI(&vt); } return status; }