From edfa9d2fae1d667b3f71a8e61aa954ac2233e493 Mon Sep 17 00:00:00 2001 From: barthess Date: Thu, 8 Dec 2011 19:24:21 +0000 Subject: I2C. Added timeout in functions. Code clean ups. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3583 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/include/i2c.h | 17 ++++---- os/hal/platforms/STM32/i2c_lld.c | 25 +++-------- os/hal/platforms/STM32/i2c_lld.h | 15 ++----- os/hal/src/i2c.c | 94 +++++++++++++++------------------------- 4 files changed, 55 insertions(+), 96 deletions(-) diff --git a/os/hal/include/i2c.h b/os/hal/include/i2c.h index f412e8a97..31dcb53d5 100644 --- a/os/hal/include/i2c.h +++ b/os/hal/include/i2c.h @@ -108,12 +108,12 @@ typedef enum { * * @notapi */ -#define _i2c_wait_s(i2cp) { \ +#define _i2c_wait_s(i2cp, timeout, rdymsg) { \ chDbgAssert((i2cp)->id_thread == NULL, \ "_i2c_wait(), #1", "already waiting"); \ chSysLock(); \ (i2cp)->id_thread = chThdSelf(); \ - chSchGoSleepS(THD_STATE_SUSPENDED); \ + rdymsg = chSchGoSleepTimeoutS(THD_STATE_SUSPENDED, timeout); \ chSysUnlock(); \ } @@ -181,14 +181,15 @@ extern "C" { void i2cObjectInit(I2CDriver *i2cp); void i2cStart(I2CDriver *i2cp, const I2CConfig *config); void i2cStop(I2CDriver *i2cp); - i2cflags_t i2cMasterTransmit(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 i2cMasterReceive(I2CDriver *i2cp, - uint8_t slave_addr, uint8_t *rxbuf, size_t rxbytes); - void i2cAddFlagsI(I2CDriver *i2cp, i2cflags_t mask); - i2cflags_t i2cGetAndClearFlags(I2CDriver *i2cp); + 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); #if I2C_USE_MUTUAL_EXCLUSION void i2cAcquireBus(I2CDriver *i2cp); diff --git a/os/hal/platforms/STM32/i2c_lld.c b/os/hal/platforms/STM32/i2c_lld.c index bda0ba17b..84decd64f 100644 --- a/os/hal/platforms/STM32/i2c_lld.c +++ b/os/hal/platforms/STM32/i2c_lld.c @@ -131,7 +131,7 @@ static volatile uint16_t dbgCR2 = 0; /** * @brief Return the last event value from I2C status registers. - * @details Important but implicit function is clearing interrpts flags. + * @details Important but implicit function is clearing interrupts flags. * @note Internal use only. * * @param[in] i2cp pointer to the @p I2CDriver object @@ -160,8 +160,6 @@ static void i2c_serve_event_interrupt(I2CDriver *i2cp) { switch(i2c_get_event(i2cp)){ case I2C_EV5_MASTER_MODE_SELECT: - /* catch start generated event */ - i2cp->flags &= ~I2C_FLG_HEADER_SENT; dp->DR = i2cp->slave_addr; break; @@ -176,7 +174,7 @@ static void i2c_serve_event_interrupt(I2CDriver *i2cp) { break; case I2C_EV8_2_MASTER_BYTE_TRANSMITTED: - /* catch BTF event after the end of trasmission */ + /* catch BTF event after the end of transmission */ if (i2cp->rxbytes > 1){ /* start "read after write" operation */ i2c_lld_master_receive(i2cp, (i2cp->slave_addr >> 1), @@ -224,7 +222,6 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp){ */ static void i2c_serve_error_interrupt(I2CDriver *i2cp) { i2cflags_t errors; - I2C_TypeDef *reg; chSysLockFromIsr(); /* clear interrupt falgs just to be safe */ @@ -234,7 +231,7 @@ static void i2c_serve_error_interrupt(I2CDriver *i2cp) { dmaStreamClearInterrupt(i2cp->dmarx); chSysUnlockFromIsr(); - reg = i2cp->id_i2c; + #define reg (i2cp->id_i2c) errors = I2CD_NO_ERROR; if(reg->SR1 & I2C_SR1_BERR) { /* Bus error */ @@ -268,11 +265,10 @@ static void i2c_serve_error_interrupt(I2CDriver *i2cp) { } if(errors != I2CD_NO_ERROR) { /* send communication end signal */ - chSysLockFromIsr(); - i2cAddFlagsI(i2cp, errors); - chSysUnlockFromIsr(); + i2cp->errors |= errors; _i2c_isr_err_code(i2cp, i2cp->id_slave_config); } + #undef reg } @@ -455,7 +451,7 @@ void i2c_lld_start(I2CDriver *i2cp) { dmaStreamSetPeripheral(i2cp->dmarx, &i2cp->id_i2c->DR); dmaStreamSetPeripheral(i2cp->dmatx, &i2cp->id_i2c->DR); - i2cp->id_i2c->CR1 = I2C_CR1_SWRST; /* reset i2c peripherial */ + i2cp->id_i2c->CR1 = I2C_CR1_SWRST; /* reset i2c peripheral */ i2cp->id_i2c->CR1 = 0; i2c_lld_set_clock(i2cp); i2c_lld_set_opmode(i2cp); @@ -509,10 +505,6 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr, i2cp->slave_addr = (slave_addr << 1) | 0x01; /* LSB = 1 -> receive */ i2cp->rxbytes = rxbytes; i2cp->rxbuf = rxbuf; - i2cp->flags = 0; - - /* setting flags and register bits */ - i2cp->flags |= I2C_FLG_MASTER_RECEIVER; i2cp->errors = 0; mode = STM32_DMA_CR_DIR_P2M; @@ -521,7 +513,7 @@ void i2c_lld_master_receive(I2CDriver *i2cp, uint8_t slave_addr, dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes); dmaStreamSetMode(i2cp->dmarx, ((i2cp->dmamode) | mode)); - /* wait stop bit from previouse transaction*/ + /* wait stop bit from previous transaction*/ while(i2cp->id_i2c->CR1 & I2C_CR1_STOP) ; @@ -558,9 +550,6 @@ void i2c_lld_master_transmit(I2CDriver *i2cp, uint8_t slave_addr, i2cp->rxbytes = rxbytes; i2cp->txbuf = txbuf; i2cp->rxbuf = rxbuf; - - /* setting flags and register bits */ - i2cp->flags = 0; i2cp->errors = 0; mode = STM32_DMA_CR_DIR_M2P; diff --git a/os/hal/platforms/STM32/i2c_lld.h b/os/hal/platforms/STM32/i2c_lld.h index 4e9051e39..378b3a335 100644 --- a/os/hal/platforms/STM32/i2c_lld.h +++ b/os/hal/platforms/STM32/i2c_lld.h @@ -176,9 +176,6 @@ #define I2C_EV8_2_MASTER_BYTE_TRANSMITTED ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) | I2C_SR1_BTF | I2C_SR1_TXE)) /* TRA, BUSY, MSL, TXE and BTF flags */ #define I2C_EV_MASK 0x00FFFFFF /* First byte zeroed because there is no need of PEC register part from SR2 */ -#define I2C_FLG_MASTER_RECEIVER 0x10 -#define I2C_FLG_HEADER_SENT 0x80 - /** @brief error checks */ #if STM32_I2C_USE_I2C1 && !STM32_HAS_I2C1 #error "I2C1 not present in the selected device" @@ -309,7 +306,6 @@ struct I2CDriver{ uint8_t *txbuf; /*!< @brief Pointer to transmit buffer.*/ __IO i2cflags_t errors; /*!< @brief Error flags.*/ - __IO i2cflags_t flags; /*!< @brief State flags.*/ uint8_t slave_addr; /*!< @brief Current slave address without R/W bit. */ @@ -327,16 +323,11 @@ struct I2CDriver{ /* Driver macros. */ /*===========================================================================*/ -#define i2c_lld_bus_is_busy(i2cp) \ - (i2cp->id_i2c->SR2 & I2C_SR2_BUSY) - - -/* Wait until BUSY flag is reset. Normally this wait function - * does not block thread, only if slave not response it does. +/** + * Wait until BUSY flag is reset. */ #define i2c_lld_wait_bus_free(i2cp) { \ - uint32_t tmo = 0xfffff; \ - while((i2cp->id_i2c->SR2 & I2C_SR2_BUSY) && tmo--) \ + while(i2cp->id_i2c->SR2 & I2C_SR2_BUSY) \ ; \ } diff --git a/os/hal/src/i2c.c b/os/hal/src/i2c.c index 63c03565a..f7f7c335e 100644 --- a/os/hal/src/i2c.c +++ b/os/hal/src/i2c.c @@ -145,33 +145,40 @@ void i2cStop(I2CDriver *i2cp) { * @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 * - * @return Zero if no errors, otherwise return error code. + * @return timeout status + * @retval RDY_OK if timeout not reached + * @retval RDY_TIMEOUT if a timeout occurs */ -i2cflags_t i2cMasterTransmit(I2CDriver *i2cp, +msg_t i2cMasterTransmit(I2CDriver *i2cp, uint8_t slave_addr, uint8_t *txbuf, size_t txbytes, uint8_t *rxbuf, - size_t rxbytes) { + size_t rxbytes, + i2cflags_t *errors, + systime_t timeout) { + msg_t rdymsg; chDbgCheck((i2cp != NULL) && (slave_addr != 0) && (txbytes > 0) && (txbuf != NULL) && - ((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL))), + ((rxbytes == 0) || ((rxbytes > 0) && (rxbuf != NULL))) && + (timeout > TIME_IMMEDIATE) && (errors != NULL), "i2cMasterTransmit"); - - i2c_lld_wait_bus_free(i2cp); - - chDbgAssert(!(i2c_lld_bus_is_busy(i2cp)), - "i2cMasterReceive(), #1", "time is out"); + i2cp->errors = I2CD_NO_ERROR; /* clear error flags from previous run */ chDbgAssert(i2cp->id_state == I2C_READY, "i2cMasterTransmit(), #1", "not ready"); i2cp->id_state = I2C_ACTIVE_TRANSMIT; i2c_lld_master_transmit(i2cp, slave_addr, txbuf, txbytes, rxbuf, rxbytes); - _i2c_wait_s(i2cp); + _i2c_wait_s(i2cp, timeout, rdymsg); + + *errors = i2cp->errors; - return i2cGetAndClearFlags(i2cp); + return rdymsg; } /** @@ -181,69 +188,40 @@ i2cflags_t i2cMasterTransmit(I2CDriver *i2cp, * @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 * - * @return Zero if no errors, otherwise return error code. + * @return timeout status + * @retval RDY_OK if timeout not reached + * @retval RDY_TIMEOUT if a timeout occurs */ -i2cflags_t i2cMasterReceive(I2CDriver *i2cp, +msg_t i2cMasterReceive(I2CDriver *i2cp, uint8_t slave_addr, uint8_t *rxbuf, - size_t rxbytes){ + size_t rxbytes, + i2cflags_t *errors, + systime_t timeout){ + + msg_t rdymsg; chDbgCheck((i2cp != NULL) && (slave_addr != 0) && - (rxbytes > 0) && (rxbuf != NULL), + (rxbytes > 0) && (rxbuf != NULL) && + (timeout > TIME_IMMEDIATE) && (errors != NULL), "i2cMasterReceive"); - - i2c_lld_wait_bus_free(i2cp); - - chDbgAssert(!(i2c_lld_bus_is_busy(i2cp)), - "i2cMasterReceive(), #1", "time is out"); + i2cp->errors = I2CD_NO_ERROR; /* clear error flags from previous run */ chDbgAssert(i2cp->id_state == I2C_READY, "i2cMasterReceive(), #1", "not ready"); i2cp->id_state = I2C_ACTIVE_RECEIVE; i2c_lld_master_receive(i2cp, slave_addr, rxbuf, rxbytes); - _i2c_wait_s(i2cp); + _i2c_wait_s(i2cp, timeout, rdymsg); - return i2cGetAndClearFlags(i2cp); -} - -/** - * @brief Handles communication events/errors. - * @details Must be called from the I/O interrupt service routine in order to - * notify I/O conditions as errors, signals change etc. - * - * @param[in] i2cp pointer to a @p I2CDriver structure - * @param[in] mask condition flags to be added to the mask - * - * @iclass - */ -void i2cAddFlagsI(I2CDriver *i2cp, i2cflags_t mask) { + *errors = i2cp->errors; - chDbgCheck(i2cp != NULL, "i2cAddFlagsI"); - - i2cp->errors |= mask; + return rdymsg; } -/** - * @brief Returns and clears the errors mask associated to the driver. - * - * @param[in] i2cp pointer to a @p I2CDriver structure - * @return The condition flags modified since last time this - * function was invoked. - * - * @api - */ -i2cflags_t i2cGetAndClearFlags(I2CDriver *i2cp) { - i2cflags_t mask; - - chDbgCheck(i2cp != NULL, "i2cGetAndClearFlags"); - - chSysLock(); - mask = i2cp->errors; - i2cp->errors = I2CD_NO_ERROR; - chSysUnlock(); - return mask; -} #if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) /** -- cgit v1.2.3