| /** |
| * <h2><center>© COPYRIGHT(c) 2016 STMicroelectronics</center></h2> |
| * |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * 3. Neither the name of STMicroelectronics nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| ****************************************************************************** |
| */ |
| |
| #include <os/os_time.h> |
| #include <mcu/stm32_hal.h> |
| #include <syscfg/syscfg.h> |
| |
| #if !MYNEWT_VAL(STM32_HAL_I2C_HAS_CLOCKSPEED) |
| |
| #define I2C_TIMEOUT_BUSY (25U) /*!< 25 ms */ |
| |
| #define MAX_NBYTE_SIZE 255U |
| |
| static const uint8_t HAL_I2C_MODE_MASTER_SEL = 0x11; |
| static const uint8_t HAL_NACK = HAL_TIMEOUT + 1; |
| |
| /** |
| * @brief This function handles I2C Communication Timeout. |
| * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains |
| * the configuration information for I2C module |
| * @param Flag specifies the I2C flag to check. |
| * @param Status The new Flag status (SET or RESET). |
| * @param Timeout Timeout duration |
| * @param Tickstart Tick start value |
| * @retval HAL status |
| */ |
| /* |
| * FIXME: this function is similar enough that it could be shared between |
| * both i2c drivers. |
| */ |
| static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, |
| uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart) |
| { |
| while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status) |
| { |
| /* Check for the Timeout */ |
| if (Timeout != HAL_MAX_DELAY) |
| { |
| if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > 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 Handles I2Cx communication when starting transfer or during transfer (TC or TCR flag are set). |
| * @param hi2c I2C handle. |
| * @param DevAddress Specifies the slave address to be programmed. |
| * @param Size Specifies the number of bytes to be programmed. |
| * This parameter must be a value between 0 and 255. |
| * @param Mode New state of the I2C START condition generation. |
| * This parameter can be one of the following values: |
| * @arg @ref I2C_RELOAD_MODE Enable Reload mode . |
| * @arg @ref I2C_AUTOEND_MODE Enable Automatic end mode. |
| * @arg @ref I2C_SOFTEND_MODE Enable Software end mode. |
| * @param Request New state of the I2C START condition generation. |
| * This parameter can be one of the following values: |
| * @arg @ref I2C_NO_STARTSTOP Don't Generate stop and start condition. |
| * @arg @ref I2C_GENERATE_STOP Generate stop condition (Size should be set to 0). |
| * @arg @ref I2C_GENERATE_START_READ Generate Restart for read request. |
| * @arg @ref I2C_GENERATE_START_WRITE Generate Restart for write request. |
| * @retval None |
| */ |
| static void I2C_TransferConfig(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t Size, uint32_t Mode, uint32_t Request) |
| { |
| uint32_t tmpreg = 0U; |
| |
| /* Check the parameters */ |
| assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance)); |
| assert_param(IS_TRANSFER_MODE(Mode)); |
| assert_param(IS_TRANSFER_REQUEST(Request)); |
| |
| /* Get the CR2 register value */ |
| tmpreg = hi2c->Instance->CR2; |
| |
| /* clear tmpreg specific bits */ |
| tmpreg &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP)); |
| |
| /* update tmpreg */ |
| tmpreg |= (uint32_t)(((uint32_t)DevAddress & I2C_CR2_SADD) | (((uint32_t)Size << 16) & I2C_CR2_NBYTES) | \ |
| (uint32_t)Mode | (uint32_t)Request); |
| |
| /* update CR2 register */ |
| hi2c->Instance->CR2 = tmpreg; |
| } |
| |
| /** |
| * @brief I2C Tx data register flush process. |
| * @param hi2c I2C handle. |
| * @retval None |
| */ |
| static void I2C_Flush_TXDR(I2C_HandleTypeDef *hi2c) |
| { |
| /* If a pending TXIS flag is set */ |
| /* Write a dummy data in TXDR to clear it */ |
| if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) != RESET) |
| { |
| hi2c->Instance->TXDR = 0x00U; |
| } |
| |
| /* Flush TX register if not empty */ |
| if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) |
| { |
| __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_TXE); |
| } |
| } |
| |
| /** |
| * @brief This function handles Acknowledge failed detection during an I2C Communication. |
| * @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_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) |
| { |
| if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) |
| { |
| /* Wait until STOP Flag is reset */ |
| /* AutoEnd should be initiate after AF */ |
| while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET) |
| { |
| /* Check for the Timeout */ |
| if (Timeout != HAL_MAX_DELAY) |
| { |
| if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout)) |
| { |
| hi2c->State = HAL_I2C_STATE_READY; |
| hi2c->Mode = HAL_I2C_MODE_NONE; |
| |
| /* Process Unlocked */ |
| __HAL_UNLOCK(hi2c); |
| return HAL_TIMEOUT; |
| } |
| } |
| } |
| |
| /* Clear NACKF Flag */ |
| __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); |
| |
| /* Clear STOP Flag */ |
| __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); |
| |
| /* Flush TX register */ |
| I2C_Flush_TXDR(hi2c); |
| |
| /* Clear Configuration Register 2 */ |
| I2C_RESET_CR2(hi2c); |
| |
| hi2c->ErrorCode = HAL_I2C_ERROR_AF; |
| hi2c->State = HAL_I2C_STATE_READY; |
| hi2c->Mode = HAL_I2C_MODE_NONE; |
| |
| /* Process Unlocked */ |
| __HAL_UNLOCK(hi2c); |
| |
| return HAL_ERROR; |
| } |
| return HAL_OK; |
| } |
| |
| /** |
| * @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 == 0U) || ((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 STOP 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_WaitOnSTOPFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) |
| { |
| while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET) |
| { |
| /* Check if a NACK is detected */ |
| if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK) |
| { |
| 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; |
| hi2c->Mode = HAL_I2C_MODE_NONE; |
| |
| /* Process Unlocked */ |
| __HAL_UNLOCK(hi2c); |
| |
| return HAL_TIMEOUT; |
| } |
| } |
| return HAL_OK; |
| } |
| |
| /** |
| * @brief Transmits in master mode an amount of data in blocking mode. |
| * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains |
| * the configuration information for the specified I2C. |
| * @param DevAddress Target device address The device 7 bits address value |
| * in datasheet must be shifted to the left before calling the interface |
| * @param pData Pointer to data buffer |
| * @param Size Amount of data to be sent |
| * @param Timeout Timeout duration |
| * @param LastOp If set sends STOP, otherwise no STOP |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_I2C_Master_Transmit_Custom(I2C_HandleTypeDef *hi2c, |
| uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout, |
| uint8_t LastOp) |
| { |
| uint32_t tickstart = 0U; |
| uint8_t prev_mode = 0; |
| |
| if (hi2c->State == HAL_I2C_STATE_READY) |
| { |
| /* Process Locked */ |
| __HAL_LOCK(hi2c); |
| |
| /* Init tickstart for timeout management*/ |
| tickstart = HAL_GetTick(); |
| |
| prev_mode = hi2c->Mode; |
| if (prev_mode != HAL_I2C_MODE_MASTER_SEL) |
| { |
| if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) |
| { |
| return HAL_TIMEOUT; |
| } |
| } |
| |
| hi2c->State = HAL_I2C_STATE_BUSY_TX; |
| hi2c->Mode = HAL_I2C_MODE_MASTER; |
| hi2c->ErrorCode = HAL_I2C_ERROR_NONE; |
| |
| /* Prepare transfer parameters */ |
| hi2c->pBuffPtr = pData; |
| hi2c->XferCount = Size; |
| hi2c->XferISR = NULL; |
| |
| /* Send Slave Address */ |
| /* Set NBYTES to write and reload if hi2c->XferCount > MAX_NBYTE_SIZE and generate RESTART */ |
| if (hi2c->XferCount > MAX_NBYTE_SIZE) |
| { |
| hi2c->XferSize = MAX_NBYTE_SIZE; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_WRITE); |
| } |
| else if (!LastOp) |
| { |
| hi2c->XferSize = hi2c->XferCount; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_SOFTEND_MODE, I2C_GENERATE_START_WRITE); |
| } |
| else |
| { |
| hi2c->XferSize = hi2c->XferCount; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_WRITE); |
| } |
| |
| /* |
| * Wait RESTART to be accepted |
| */ |
| if (prev_mode == HAL_I2C_MODE_MASTER_SEL) |
| { |
| if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TC, RESET, Timeout, tickstart) != HAL_OK) |
| { |
| return HAL_TIMEOUT; |
| } |
| } |
| |
| while (hi2c->XferCount > 0U) |
| { |
| /* Wait until TXIS flag is set */ |
| if (I2C_WaitOnTXISFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) |
| { |
| if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) |
| { |
| return HAL_ERROR; |
| } |
| else |
| { |
| return HAL_TIMEOUT; |
| } |
| } |
| /* Write data to TXDR */ |
| hi2c->Instance->TXDR = (*hi2c->pBuffPtr++); |
| hi2c->XferCount--; |
| hi2c->XferSize--; |
| |
| if ((hi2c->XferSize == 0U) && (hi2c->XferCount != 0U)) |
| { |
| /* Wait until TCR flag is set */ |
| if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK) |
| { |
| return HAL_TIMEOUT; |
| } |
| |
| if (hi2c->XferCount > MAX_NBYTE_SIZE) |
| { |
| hi2c->XferSize = MAX_NBYTE_SIZE; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); |
| } |
| else if (!LastOp) |
| { |
| hi2c->XferSize = hi2c->XferCount; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_SOFTEND_MODE, I2C_NO_STARTSTOP); |
| } |
| else |
| { |
| hi2c->XferSize = hi2c->XferCount; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); |
| } |
| } |
| } |
| |
| if (LastOp) |
| { |
| /* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */ |
| /* Wait until STOPF flag is set */ |
| if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) |
| { |
| if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) |
| { |
| return HAL_ERROR; |
| } |
| else |
| { |
| return HAL_TIMEOUT; |
| } |
| } |
| |
| /* Clear STOP Flag */ |
| __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); |
| } |
| else |
| { |
| /* No autoend/reload was requested, make sure transmission of last byte |
| * has finished... */ |
| if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TC, SET, Timeout, tickstart) != HAL_OK) |
| { |
| return HAL_TIMEOUT; |
| } |
| } |
| |
| /* Clear Configuration Register 2 */ |
| I2C_RESET_CR2(hi2c); |
| |
| hi2c->State = HAL_I2C_STATE_READY; |
| if (LastOp) |
| { |
| hi2c->Mode = HAL_I2C_MODE_NONE; |
| } |
| else |
| { |
| hi2c->Mode = HAL_I2C_MODE_MASTER_SEL; |
| } |
| |
| /* Process Unlocked */ |
| __HAL_UNLOCK(hi2c); |
| |
| return HAL_OK; |
| } |
| else |
| { |
| return HAL_BUSY; |
| } |
| } |
| |
| /** |
| * @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; |
| } |
| |
| /** |
| * @brief Receives in master mode an amount of data in blocking mode. |
| * @param hi2c Pointer to a I2C_HandleTypeDef structure that contains |
| * the configuration information for the specified I2C. |
| * @param DevAddress Target device address The device 7 bits address value |
| * in datasheet must be shifted to the left before calling the interface |
| * @param pData Pointer to data buffer |
| * @param Size Amount of data to be sent |
| * @param Timeout Timeout duration |
| * @param LastOp If set sends STOP, otherwise no STOP |
| * @retval HAL status |
| */ |
| HAL_StatusTypeDef HAL_I2C_Master_Receive_Custom(I2C_HandleTypeDef *hi2c, |
| uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout, |
| uint8_t LastOp) |
| { |
| uint32_t tickstart = 0U; |
| uint8_t prev_mode = 0; |
| HAL_StatusTypeDef rc; |
| |
| if (hi2c->State == HAL_I2C_STATE_READY) |
| { |
| /* Process Locked */ |
| __HAL_LOCK(hi2c); |
| |
| /* Init tickstart for timeout management */ |
| tickstart = HAL_GetTick(); |
| |
| prev_mode = hi2c->Mode; |
| if (prev_mode != HAL_I2C_MODE_MASTER_SEL) |
| { |
| if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK) |
| { |
| return HAL_TIMEOUT; |
| } |
| } |
| |
| hi2c->State = HAL_I2C_STATE_BUSY_RX; |
| hi2c->Mode = HAL_I2C_MODE_MASTER; |
| hi2c->ErrorCode = HAL_I2C_ERROR_NONE; |
| |
| /* Prepare transfer parameters */ |
| hi2c->pBuffPtr = pData; |
| hi2c->XferCount = Size; |
| hi2c->XferISR = NULL; |
| |
| /* Send Slave Address */ |
| /* Set NBYTES to write and reload if hi2c->XferCount > MAX_NBYTE_SIZE and generate RESTART */ |
| if (hi2c->XferCount > MAX_NBYTE_SIZE) |
| { |
| hi2c->XferSize = MAX_NBYTE_SIZE; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_READ); |
| } |
| else if (!LastOp) |
| { |
| hi2c->XferSize = hi2c->XferCount; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_SOFTEND_MODE, I2C_GENERATE_START_READ); |
| } |
| else |
| { |
| hi2c->XferSize = hi2c->XferCount; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_READ); |
| } |
| |
| while (hi2c->XferCount > 0U) |
| { |
| /* Wait until RXNE flag is set */ |
| rc = I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart, prev_mode); |
| if (rc != HAL_OK && rc != HAL_NACK) |
| { |
| if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) |
| { |
| return HAL_ERROR; |
| } |
| else |
| { |
| return HAL_TIMEOUT; |
| } |
| } |
| |
| /* Read data from RXDR */ |
| (*hi2c->pBuffPtr++) = hi2c->Instance->RXDR; |
| hi2c->XferSize--; |
| hi2c->XferCount--; |
| |
| if (rc == HAL_NACK) |
| { |
| break; |
| } |
| |
| if ((hi2c->XferSize == 0U) && (hi2c->XferCount != 0U)) |
| { |
| /* Wait until TCR flag is set */ |
| if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK) |
| { |
| return HAL_TIMEOUT; |
| } |
| |
| if (hi2c->XferCount > MAX_NBYTE_SIZE) |
| { |
| hi2c->XferSize = MAX_NBYTE_SIZE; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP); |
| } |
| else if (!LastOp) |
| { |
| hi2c->XferSize = hi2c->XferCount; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_SOFTEND_MODE, I2C_NO_STARTSTOP); |
| } |
| else |
| { |
| hi2c->XferSize = hi2c->XferCount; |
| I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP); |
| } |
| } |
| } |
| |
| if (LastOp) |
| { |
| /* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */ |
| /* Wait until STOPF flag is set */ |
| if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK) |
| { |
| if (hi2c->ErrorCode == HAL_I2C_ERROR_AF) |
| { |
| return HAL_ERROR; |
| } |
| else |
| { |
| return HAL_TIMEOUT; |
| } |
| } |
| |
| /* Clear STOP Flag */ |
| __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); |
| } |
| else |
| { |
| /* No autoend/reload was requested, make sure transmission of last byte |
| * has finished... */ |
| if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TC, SET, Timeout, tickstart) != HAL_OK) |
| { |
| return HAL_TIMEOUT; |
| } |
| } |
| |
| /* Clear Configuration Register 2 */ |
| I2C_RESET_CR2(hi2c); |
| |
| hi2c->State = HAL_I2C_STATE_READY; |
| if (LastOp) |
| { |
| hi2c->Mode = HAL_I2C_MODE_NONE; |
| } |
| else |
| { |
| hi2c->Mode = HAL_I2C_MODE_MASTER_SEL; |
| } |
| |
| /* Process Unlocked */ |
| __HAL_UNLOCK(hi2c); |
| |
| return HAL_OK; |
| } |
| else |
| { |
| return HAL_BUSY; |
| } |
| } |
| |
| #endif /* !MYNEWT_VAL(STM32_HAL_I2C_HAS_CLOCKSPEED) */ |