/** * @brief Transmits data via the I2C bus as master. * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x. * This is hardware restriction. * * @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 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. <b>After a * timeout the driver must be stopped and restarted * because the bus is in an uncertain state</b>. * * @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)i2cp; (void)addr; (void)txbuf; (void)txbytes; (void)rxbuf; (void)rxbytes; (void)timeout; i2cdef_t i2c = i2cp->i2c; uint32_t status; /* Set write mode, slave address and 3 internal address byte lengths */ i2c->TWI_MMR = 0; i2c->TWI_MMR = TWI_MMR_DADR(addr->chip) | ((addr->len << TWI_MMR_IADRSZ_Pos) & TWI_MMR_IADRSZ_Msk); /* Set internal address for remote chip */ i2c->TWI_IADR = 0; i2c->TWI_IADR = twi_mk_addr(addr->addr, addr->len); /* Send all bytes */ while (txbytes > 0) { status = i2c->TWI_SR; if (status & TWI_SR_NACK) { return RDY_RESET; } if (!(status & TWI_SR_TXRDY)) { continue; } i2c->TWI_THR = *txbuf++; txbytes--; } while (1) { status = i2c->TWI_SR; if (status & TWI_SR_NACK) { return RDY_RESET; } if (status & TWI_SR_TXRDY) { break; } } i2c->TWI_CR = TWI_CR_STOP; while (!(i2c->TWI_SR & TWI_SR_TXCOMP)) { } return RDY_OK; }
/** * \brief Read multiple bytes from a TWI compatible slave device. * * \note This function will NOT return until all data has been read or error occurs. * * \param p_twi Pointer to a TWI instance. * \param p_packet Packet information and data (see \ref twi_packet_t). * * \return TWI_SUCCESS if all bytes were read, error code otherwise. */ uint32_t twi_master_read(Twi *p_twi, twi_packet_t *p_packet) { uint32_t status; uint32_t cnt = p_packet->length; uint8_t *buffer = p_packet->buffer; uint8_t stop_sent = 0; /* Check argument */ if (cnt == 0) { return TWI_INVALID_ARGUMENT; } /* Set read mode, slave address and 3 internal address byte lengths */ p_twi->TWI_MMR = 0; p_twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(p_packet->chip) | ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) & TWI_MMR_IADRSZ_Msk); /* Set internal address for remote chip */ p_twi->TWI_IADR = 0; p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length); /* Send a START condition */ if (cnt == 1) { p_twi->TWI_CR = TWI_CR_START | TWI_CR_STOP; stop_sent = 1; } else { p_twi->TWI_CR = TWI_CR_START; stop_sent = 0; } while (cnt > 0) { status = p_twi->TWI_SR; if (status & TWI_SR_NACK) { return TWI_RECEIVE_NACK; } /* Last byte ? */ if (cnt == 1 && !stop_sent) { p_twi->TWI_CR = TWI_CR_STOP; stop_sent = 1; } if (!(status & TWI_SR_RXRDY)) { continue; } *buffer++ = p_twi->TWI_RHR; cnt--; } while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) { } p_twi->TWI_SR; return TWI_SUCCESS; }
/** * \brief Write multiple bytes to a TWI compatible slave device. * * \note This function will NOT return until all data has been written or error occurred. * * \param p_twi Pointer to a TWI instance. * \param p_packet Packet information and data (see \ref twi_packet_t). * * \return TWI_SUCCESS if all bytes were written, error code otherwise. */ uint32_t twi_master_write(Twi *p_twi, twi_packet_t *p_packet) { uint32_t status; uint32_t cnt = p_packet->length; uint8_t *buffer = p_packet->buffer; /* Check argument */ if (cnt == 0) { return TWI_INVALID_ARGUMENT; } /* Set write mode, slave address and 3 internal address byte lengths */ p_twi->TWI_MMR = 0; p_twi->TWI_MMR = TWI_MMR_DADR(p_packet->chip) | ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) & TWI_MMR_IADRSZ_Msk); /* Set internal address for remote chip */ p_twi->TWI_IADR = 0; p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length); /* Send all bytes */ while (cnt > 0) { status = p_twi->TWI_SR; if (status & TWI_SR_NACK) { return TWI_RECEIVE_NACK; } if (!(status & TWI_SR_TXRDY)) { continue; } p_twi->TWI_THR = *buffer++; cnt--; } while (1) { status = p_twi->TWI_SR; if (status & TWI_SR_NACK) { return TWI_RECEIVE_NACK; } if (status & TWI_SR_TXRDY) { break; } } p_twi->TWI_CR = TWI_CR_STOP; while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) { } return TWI_SUCCESS; }
/** * @brief Receives data via the I2C bus as master. * @details Number of receiving bytes must be more than 1 on STM32F1x. This is * hardware restriction. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] addr slave device address * @param[out] rxbuf pointer to the 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. <b>After a * timeout the driver must be stopped and restarted * because the bus is in an uncertain state</b>. * * @notapi */ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, uint8_t *rxbuf, size_t rxbytes, systime_t timeout) { (void)i2cp; (void)addr; (void)rxbuf; (void)rxbytes; (void)timeout; uint32_t status; uint32_t stop_sent; i2cdef_t i2c = i2cp->i2c; /* Set read mode, slave address and 3 internal address byte lengths */ i2c->TWI_MMR = 0; i2c->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(addr->chip) | ((addr->len << TWI_MMR_IADRSZ_Pos) & TWI_MMR_IADRSZ_Msk); /* Set internal address for remote chip */ i2c->TWI_IADR = 0; i2c->TWI_IADR = twi_mk_addr(addr->addr, addr->len); /* Send a START condition */ if (rxbytes = 1) { i2c->TWI_CR = TWI_CR_START | TWI_CR_STOP; while (!(i2c->TWI_SR & TWI_SR_RXRDY)); *rxbuf = i2c->TWI_RHR; } else { i2c->TWI_PTCR = TWI_PTCR_RXTDIS | TWI_PTCR_TXTDIS; i2c->TWI_IER = TWI_IER_ENDRX | TWI_IER_NACK | TWI_IER_OVRE; chSysLock(); i2cp->thread = chThdSelf(); i2c->TWI_RNPR = 0; i2c->TWI_RNCR = 0; i2c->TWI_RPR = (uint32_t) rxbuf; i2c->TWI_RCR = rxbytes - 2; i2c->TWI_PTCR = TWI_PTCR_RXTEN; i2cp->curbuf = rxbuf + (rxbytes - 2); i2c->TWI_CR = TWI_CR_START; chSchGoSleepS(THD_STATE_SUSPENDED); return chThdSelf()->p_u.rdymsg; } return RDY_OK; }
//! This function is not blocking. int twi_master_write_ex(volatile avr32_twi_t *twi, const twi_package_t *package) { int status = TWI_SUCCESS; if( twi_nack ) status = TWI_RECEIVE_NACK; // Previous transaction returns a NACK else if( twi_tx_nb_bytes ) return TWI_BUSY; // Still transmitting... // No data to send if (package->length == 0) { return TWI_INVALID_ARGUMENT; } twi_nack = false; // Enable master transfer, disable slave twi->cr = AVR32_TWI_CR_MSEN_MASK #ifndef AVR32_TWI_180_H_INCLUDED | AVR32_TWI_CR_SVDIS_MASK #endif ; // set write mode, slave address and 3 internal address byte length twi->mmr = (0 << AVR32_TWI_MMR_MREAD_OFFSET) | (package->chip << AVR32_TWI_MMR_DADR_OFFSET) | ((package->addr_length << AVR32_TWI_MMR_IADRSZ_OFFSET) & AVR32_TWI_MMR_IADRSZ_MASK); // Set pointer to TWIM instance for IT twi_inst = twi; // set internal address for remote chip twi->iadr = twi_mk_addr(package->addr, package->addr_length); // get a pointer to applicative data twi_tx_data = package->buffer; // get a copy of nb bytes to write twi_tx_nb_bytes = package->length; // put the first byte in the Transmit Holding Register twi->thr = *twi_tx_data++; // mask NACK and TXRDY interrupts twi_it_mask = AVR32_TWI_IER_NACK_MASK | AVR32_TWI_IER_TXRDY_MASK; // update IMR through IER twi->ier = twi_it_mask; return status; }
int twi_master_read(volatile avr32_twi_t *twi, const twi_package_t *package) { // check argument if (package->length == 0) { return TWI_INVALID_ARGUMENT; } while( twi_is_busy() ) { cpu_relax(); }; twi_nack = false; twi_busy = true; // set read mode, slave address and 3 internal address byte length twi->mmr = (package->chip << AVR32_TWI_MMR_DADR_OFFSET) | ((package->addr_length << AVR32_TWI_MMR_IADRSZ_OFFSET) & AVR32_TWI_MMR_IADRSZ_MASK) | (1 << AVR32_TWI_MMR_MREAD_OFFSET); // Set pointer to TWIM instance for IT twi_inst = twi; // set internal address for remote chip twi->iadr = twi_mk_addr(package->addr, package->addr_length); // get a pointer to applicative data twi_rx_data = package->buffer; // get a copy of nb bytes to read twi_rx_nb_bytes = package->length; // Enable master transfer twi->cr = AVR32_TWI_CR_MSEN_MASK; // Send start condition twi->cr = AVR32_TWI_START_MASK; // only one byte to receive if(twi_rx_nb_bytes == 1) { // set stop bit twi->cr = AVR32_TWI_STOP_MASK; } // mask NACK and RXRDY interrupts twi_it_mask = AVR32_TWI_IER_NACK_MASK | AVR32_TWI_IER_RXRDY_MASK; // update IMR through IER twi->ier = twi_it_mask; // get data while( twi_is_busy() ) { cpu_relax(); } // Disable master transfer twi->cr = AVR32_TWI_CR_MSDIS_MASK; if( twi_nack ) return TWI_RECEIVE_NACK; return TWI_SUCCESS; }
int twi_master_write(volatile avr32_twi_t *twi, const twi_package_t *package) { // No data to send if (package->length == 0) { return TWI_INVALID_ARGUMENT; } while (twi_is_busy()) { cpu_relax(); }; twi_nack = false; twi_busy = true; SCOPE_0_ON; // Enable master transfer, disable slave twi->cr = AVR32_TWI_CR_MSEN_MASK #ifndef AVR32_TWI_180_H_INCLUDED | AVR32_TWI_CR_SVDIS_MASK #endif ; // set write mode, slave address and 3 internal address byte length twi->mmr = (0 << AVR32_TWI_MMR_MREAD_OFFSET) | (package->chip << AVR32_TWI_MMR_DADR_OFFSET) | ((package->addr_length << AVR32_TWI_MMR_IADRSZ_OFFSET) & AVR32_TWI_MMR_IADRSZ_MASK); // Set pointer to TWI instance for IT twi_inst = twi; // set internal address for remote chip twi->iadr = twi_mk_addr(package->addr, package->addr_length); // get a pointer to applicative data twi_tx_data = package->buffer; // get a copy of nb bytes to write twi_tx_nb_bytes = package->length; // put the first byte in the Transmit Holding Register twi->thr = *twi_tx_data++; // mask NACK and TXRDY interrupts twi_it_mask = AVR32_TWI_IER_NACK_MASK | AVR32_TWI_IER_TXRDY_MASK; // update IMR through IER twi->ier = twi_it_mask; // send data while (twi_is_busy()) { cpu_relax(); } // Disable master transfer twi->cr = AVR32_TWI_CR_MSDIS_MASK; if (twi_nack) { return TWI_RECEIVE_NACK; } return TWI_SUCCESS; }