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
This commit is contained in:
parent
afc023a222
commit
edfa9d2fae
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) \
|
||||
; \
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
return i2cGetAndClearFlags(i2cp);
|
||||
*errors = i2cp->errors;
|
||||
|
||||
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);
|
||||
*errors = i2cp->errors;
|
||||
|
||||
return rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
|
||||
chDbgCheck(i2cp != NULL, "i2cAddFlagsI");
|
||||
|
||||
i2cp->errors |= mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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__)
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue