diff --git a/os/hal/include/i2c.h b/os/hal/include/i2c.h index 31dcb53d5..1053712d0 100644 --- a/os/hal/include/i2c.h +++ b/os/hal/include/i2c.h @@ -51,7 +51,7 @@ #define I2CD_OVERRUN 0x08 /**< @brief Overrun/Underrun. */ #define I2CD_PEC_ERROR 0x10 /**< @brief PEC Error in reception. */ -#define I2CD_TIMEOUT 0x20 /**< @brief Timeout Error. */ +#define I2CD_TIMEOUT 0x20 /**< @brief Hardware timeout. */ #define I2CD_SMB_ALERT 0x40 /**< @brief SMBus Alert. */ /** @} */ @@ -91,85 +91,10 @@ typedef enum { #include "i2c_lld.h" - /*===========================================================================*/ /* Driver macros. */ /*===========================================================================*/ -/** - * @brief Waits for operation completion. - * @details This function waits for the driver to complete the current - * operation. - * @pre An operation must be running while the function is invoked. - * @note No more than one thread can wait on a I2C driver using - * this function. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -#define _i2c_wait_s(i2cp, timeout, rdymsg) { \ - chDbgAssert((i2cp)->id_thread == NULL, \ - "_i2c_wait(), #1", "already waiting"); \ - chSysLock(); \ - (i2cp)->id_thread = chThdSelf(); \ - rdymsg = chSchGoSleepTimeoutS(THD_STATE_SUSPENDED, timeout); \ - chSysUnlock(); \ -} - -/** - * @brief Wakes up the waiting thread. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -#define _i2c_wakeup_isr(i2cp) { \ - if ((i2cp)->id_thread != NULL) { \ - Thread *tp = (i2cp)->id_thread; \ - (i2cp)->id_thread = NULL; \ - chSysLockFromIsr(); \ - chSchReadyI(tp); \ - chSysUnlockFromIsr(); \ - } \ -} - -/** - * @brief Common ISR code. - * @details This code handles the portable part of the ISR code: - * - Waiting thread wakeup. - * - Driver state transitions. - * - * @note This macro is meant to be used in the low level drivers - * implementation only. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -#define _i2c_isr_code(i2cp, i2cscfg) { \ - (i2cp)->id_state = I2C_READY; \ - _i2c_wakeup_isr(i2cp); \ -} - -/** - * @brief Error ISR code. - * @details This code handles the portable part of the ISR code: - * - Waiting thread wakeup. - * - Driver state transitions. - * - * @note This macro is meant to be used in the low level drivers - * implementation only. - * - * @param[in] i2cp pointer to the @p I2CDriver object - * - * @notapi - */ -#define _i2c_isr_err_code(i2cp, i2cscfg) { \ - (i2cp)->id_state = I2C_READY; \ - _i2c_wakeup_isr(i2cp); \ -} - /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ @@ -181,16 +106,16 @@ extern "C" { void i2cObjectInit(I2CDriver *i2cp); void i2cStart(I2CDriver *i2cp, const I2CConfig *config); void i2cStop(I2CDriver *i2cp); - msg_t i2cMasterTransmit(I2CDriver *i2cp, - uint8_t slave_addr, - uint8_t *txbuf, size_t txbytes, - uint8_t *rxbuf, size_t rxbytes, - i2cflags_t *errors, systime_t timeout); - msg_t i2cMasterReceive(I2CDriver *i2cp, - uint8_t slave_addr, - uint8_t *rxbuf, size_t rxbytes, - i2cflags_t *errors, systime_t timeout); - + i2cflags_t i2cGetErrors(I2CDriver *i2cp); + msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp, + i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout); + msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp, + i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + systime_t timeout); #if I2C_USE_MUTUAL_EXCLUSION void i2cAcquireBus(I2CDriver *i2cp); void i2cReleaseBus(I2CDriver *i2cp); diff --git a/os/hal/src/i2c.c b/os/hal/src/i2c.c index c67f3a8c6..28dd99762 100644 --- a/os/hal/src/i2c.c +++ b/os/hal/src/i2c.c @@ -132,111 +132,132 @@ void i2cStop(I2CDriver *i2cp) { chSysUnlock(); } +/** + * @brief Returns the errors mask associated to the previous operation. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @return The errors mask. + * + * @api + */ +i2cflags_t i2cGetErrors(I2CDriver *i2cp) { + + chDbgCheck(i2cp != NULL, "i2cGetErrors"); + + return i2c_lld_get_errors(i2cp); +} + /** * @brief Sends data via the I2C bus. * @details Function designed to realize "read-through-write" transfer * paradigm. If you want transmit data without any further read, * than set @b rxbytes field to 0. * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] slave_addr Slave device address (7 bits) without R/W bit - * @param[in] txbuf pointer to transmit buffer - * @param[in] txbytes number of bytes to be transmitted - * @param[in] rxbuf pointer to receive buffer - * @param[in] rxbytes number of bytes to be received, set it to 0 if - * you want transmit only - * @param[in] errors pointer to variable to store error code, zero means - * no error. - * @param[in] timeout operation timeout + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address (7 bits) without R/W bit + * @param[in] txbuf pointer to transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[in] rxbuf pointer to receive buffer + * @param[in] rxbytes number of bytes to be received, set it to 0 if + * you want transmit only + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . * - * @return timeout status - * @retval RDY_OK if timeout not reached - * @retval RDY_TIMEOUT if a timeout occurs + * @return The number of received bytes or an exit code. + * @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 i2cMasterTransmit(I2CDriver *i2cp, - uint8_t slave_addr, - uint8_t *txbuf, - size_t txbytes, - uint8_t *rxbuf, - size_t rxbytes, - i2cflags_t *errors, - systime_t timeout) { +msg_t i2cMasterTransmitTimeout(I2CDriver *i2cp, + i2caddr_t addr, + const uint8_t *txbuf, + size_t txbytes, + uint8_t *rxbuf, + size_t rxbytes, + systime_t timeout) { msg_t rdymsg; - chDbgCheck((i2cp != NULL) && (slave_addr != 0) && + chDbgCheck((i2cp != NULL) && (addr != 0) && (txbytes > 0) && (txbuf != NULL) && ((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL))) && - (timeout > TIME_IMMEDIATE) && (errors != NULL), - "i2cMasterTransmit"); + (timeout != TIME_IMMEDIATE), + "i2cMasterTransmitTimeout"); - i2c_lld_wait_bus_free(i2cp); - i2cp->errors = I2CD_NO_ERROR; /* clear error flags from previous run */ chDbgAssert(i2cp->id_state == I2C_READY, - "i2cMasterTransmit(), #1", "not ready"); + "i2cMasterTransmitTimeout(), #1", "not ready"); + chSysLock(); + i2cp->errors = I2CD_NO_ERROR; i2cp->id_state = I2C_ACTIVE_TRANSMIT; - i2c_lld_master_transmit(i2cp, slave_addr, txbuf, txbytes, rxbuf, rxbytes); - _i2c_wait_s(i2cp, timeout, rdymsg); - - *errors = i2cp->errors; - + rdymsg = i2c_lld_master_transmit_timeout(i2cp, addr, txbuf, txbytes, + rxbuf, rxbytes, timeout); + i2cp->id_state = I2C_READY; + chSysUnlock(); return rdymsg; } /** * @brief Receives data from the I2C bus. * - * @param[in] i2cp pointer to the @p I2CDriver object - * @param[in] slave_addr slave device address (7 bits) without R/W bit - * @param[in] rxbytes number of bytes to be received - * @param[in] rxbuf pointer to receive buffer - * @param[in] errors pointer to variable to store error code, zero means - * no error. - * @param[in] timeout operation timeout + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address (7 bits) without R/W bit + * @param[in] rxbytes number of bytes to be received + * @param[in] rxbuf pointer to receive buffer + * @param[in] errors pointer to variable to store error code, zero means + * no error. + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . * - * @return timeout status - * @retval RDY_OK if timeout not reached - * @retval RDY_TIMEOUT if a timeout occurs + * @return The number of received bytes or an exit code. + * @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 i2cMasterReceive(I2CDriver *i2cp, - uint8_t slave_addr, - uint8_t *rxbuf, - size_t rxbytes, - i2cflags_t *errors, - systime_t timeout){ +msg_t i2cMasterReceiveTimeout(I2CDriver *i2cp, + i2caddr_t slave_addr, + uint8_t *rxbuf, + size_t rxbytes, + systime_t timeout){ msg_t rdymsg; - chDbgCheck((i2cp != NULL) && (slave_addr != 0) && + chDbgCheck((i2cp != NULL) && (addr != 0) && (rxbytes > 0) && (rxbuf != NULL) && - (timeout > TIME_IMMEDIATE) && (errors != NULL), - "i2cMasterReceive"); + (timeout != TIME_IMMEDIATE), + "i2cMasterReceiveTimeout"); - i2c_lld_wait_bus_free(i2cp); - i2cp->errors = I2CD_NO_ERROR; /* clear error flags from previous run */ chDbgAssert(i2cp->id_state == I2C_READY, "i2cMasterReceive(), #1", "not ready"); + chSysLock(); + i2cp->errors = I2CD_NO_ERROR; i2cp->id_state = I2C_ACTIVE_RECEIVE; - i2c_lld_master_receive(i2cp, slave_addr, rxbuf, rxbytes); - _i2c_wait_s(i2cp, timeout, rdymsg); - - *errors = i2cp->errors; - + rdymsg = i2c_lld_master_receive_timeout(i2cp, addr, rxbuf, rxbytes, timeout); + i2cp->id_state = I2C_READY; + chSysUnlock(); return rdymsg; } - #if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) /** - * @brief Gains exclusive access to the I2C bus. - * @details This function tries to gain ownership to the I2C bus, if the bus + * @brief Gains exclusive access to the I2C bus. + * @details This function tries to gain ownership to the SPI bus, if the bus * is already being used then the invoking thread is queued. + * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION + * must be enabled. * * @param[in] i2cp pointer to the @p I2CDriver object * - * @note This function is only available when the @p I2C_USE_MUTUAL_EXCLUSION - * option is set to @p TRUE. + * @api */ void i2cAcquireBus(I2CDriver *i2cp) { @@ -250,12 +271,13 @@ void i2cAcquireBus(I2CDriver *i2cp) { } /** - * @brief Releases exclusive access to the I2C bus. + * @brief Releases exclusive access to the I2C bus. + * @pre In order to use this function the option @p I2C_USE_MUTUAL_EXCLUSION + * must be enabled. * * @param[in] i2cp pointer to the @p I2CDriver object * - * @note This function is only available when the @p I2C_USE_MUTUAL_EXCLUSION - * option is set to @p TRUE. + * @api */ void i2cReleaseBus(I2CDriver *i2cp) {