/** * @brief This function handles I2C Communication Timeout for specific usage of TXIS flag. * @param hi2c: Pointer to a I2C_HandleTypeDef structure that contains * the configuration information for the specified I2C. * @param Timeout: Timeout duration * @param Tickstart: Tick start value * @retval HAL status */ static HAL_StatusTypeDef I2C_WaitOnTXISFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) { while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) == RESET) { /* Check if a NACK is detected */ if(I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK) { return HAL_ERROR; } /* Check for the Timeout */ if(Timeout != HAL_MAX_DELAY) { if((Timeout == 0)||((HAL_GetTick() - Tickstart) > Timeout)) { hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; hi2c->State= HAL_I2C_STATE_READY; hi2c->Mode = HAL_I2C_MODE_NONE; /* Process Unlocked */ __HAL_UNLOCK(hi2c); return HAL_TIMEOUT; } } } return HAL_OK; }
/** * @brief This function handles I2C Communication Timeout for specific usage of RXNE flag. * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains * the configuration information for the specified I2C. * @param Timeout Timeout duration * @param Tickstart Tick start value * @retval HAL status */ static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart, uint8_t prev_mode) { while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) { /* Check if a NACK is detected */ if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK) { return HAL_NACK; } /* * FIXME: need to re-check if what is supposed to be a RESTART is not also * triggering a STOP along... */ /* Check if a STOPF is detected */ if (prev_mode != HAL_I2C_MODE_MASTER_SEL && __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) { /* Clear STOP Flag */ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); /* Clear Configuration Register 2 */ I2C_RESET_CR2(hi2c); hi2c->ErrorCode = HAL_I2C_ERROR_NONE; hi2c->State = HAL_I2C_STATE_READY; hi2c->Mode = HAL_I2C_MODE_NONE; /* Process Unlocked */ __HAL_UNLOCK(hi2c); return HAL_ERROR; } /* Check for the Timeout */ if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout)) { hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT; hi2c->State = HAL_I2C_STATE_READY; /* Process Unlocked */ __HAL_UNLOCK(hi2c); return HAL_TIMEOUT; } } return HAL_OK; }
// this function is based on STM code int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) { machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)self_in; I2C_HandleTypeDef *hi2c = self->pyb->i2c; uint32_t Timeout = *self->timeout; /* Init tickstart for timeout management*/ uint32_t tickstart = HAL_GetTick(); #if 0 // TODO: for multi-master, here we could wait for the bus to be free // we'd need a flag to tell if we were in the middle of a set of transactions // (ie didn't send a stop bit in the last call) /* Wait until BUSY flag is reset */ if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart)) { return -MP_EBUSY; } #endif /* Check if the I2C is already enabled */ if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) { /* Enable I2C peripheral */ __HAL_I2C_ENABLE(hi2c); } /* Disable Pos */ hi2c->Instance->CR1 &= ~I2C_CR1_POS; /* Send Slave Address */ int ret = send_addr_byte(hi2c, I2C_7BIT_ADD_WRITE(addr << 1), Timeout, tickstart); if (ret != 0) { return ret; } /* Clear ADDR flag */ __HAL_I2C_CLEAR_ADDRFLAG(hi2c); int num_acks = 0; while (len > 0U) { /* Wait until TXE flag is set */ while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) { /* Check if a NACK is detected */ if (I2C_IsAcknowledgeFailed(hi2c)) { goto nack; } /* Check for the Timeout */ if (Timeout != HAL_MAX_DELAY) { if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) { goto timeout; } } } /* Write data to DR */ hi2c->Instance->DR = *src++; len--; /* Wait until BTF flag is set */ while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET) { /* Check if a NACK is detected */ if (I2C_IsAcknowledgeFailed(hi2c)) { goto nack; } /* Check for the Timeout */ if (Timeout != HAL_MAX_DELAY) { if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) { goto timeout; } } } ++num_acks; } nack: /* Generate Stop */ if (stop) { hi2c->Instance->CR1 |= I2C_CR1_STOP; } return num_acks; timeout: // timeout, release the bus cleanly hi2c->Instance->CR1 |= I2C_CR1_STOP; return -MP_ETIMEDOUT; }