Exemplo n.º 1
0
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
{
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);
    int timeout;
    int count;
    int value;

    if (length == 0) return 0;

    /* update CR2 register */
    i2c->CR2 = (i2c->CR2 & (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)))
               | (uint32_t)(((uint32_t)address & I2C_CR2_SADD) | (((uint32_t)length << 16) & I2C_CR2_NBYTES) | (uint32_t)I2C_SOFTEND_MODE | (uint32_t)I2C_GENERATE_START_READ);

    // Read all bytes
    for (count = 0; count < length; count++) {
        value = i2c_byte_read(obj, 0);
        data[count] = (char)value;
    }

    // Wait transfer complete
    timeout = LONG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TC) == RESET) {
        timeout--;
        if (timeout == 0) {
            return 0;
        }
    }

    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_TC);

    // If not repeated start, send stop.
    if (stop) {
        i2c_stop(obj);
        /* Wait until STOPF flag is set */
        timeout = FLAG_TIMEOUT;
        while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_STOPF) == RESET) {
            timeout--;
            if (timeout == 0) {
                return 0;
            }
        }
        /* Clear STOP Flag */
        __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_STOPF);
    }

    return length;
}
Exemplo n.º 2
0
inline int i2c_start(i2c_t *obj) {
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);

    // Clear Acknowledge failure flag
    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_AF);

    // Wait the STOP condition has been previously correctly sent
    timeout = FLAG_TIMEOUT;
    while ((i2c->CR2 & I2C_CR2_STOP) == I2C_CR2_STOP){
        if ((timeout--) == 0) {
            return 1;
        }
    }

    // Generate the START condition
    i2c->CR2 |= I2C_CR2_START;

    // Wait the START condition has been correctly sent
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == RESET) {
        if ((timeout--) == 0) {
            return 1;
        }
    }

    return 0;
}
Exemplo n.º 3
0
inline int i2c_start(i2c_t *obj)
{
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);

    // Clear Acknowledge failure flag
    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_AF);

    // Wait the STOP condition has been previously correctly sent
	// This timeout can be avoid in some specific cases by simply clearing the STOP bit
    timeout = FLAG_TIMEOUT;
    while ((i2c->CR1 & I2C_CR1_STOP) == I2C_CR1_STOP) {
        if ((timeout--) == 0) {
            return 1;
        }
    }

    // Generate the START condition
    i2c->CR1 |= I2C_CR1_START;

    // Wait the START condition has been correctly sent
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_SB) == RESET) {
        if ((timeout--) == 0) {
            return 1;
        }
    }

    return 0;
}
Exemplo n.º 4
0
// this function is based on STM code
STATIC int send_addr_byte(I2C_HandleTypeDef *hi2c, uint8_t addr_byte, uint32_t Timeout, uint32_t Tickstart) {
    /* Generate Start */
    hi2c->Instance->CR1 |= I2C_CR1_START;

    /* Wait until SB flag is set */
    if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart)) {
        return -MP_ETIMEDOUT;
    }

    /* Send slave address */
    hi2c->Instance->DR = addr_byte;

    /* Wait until ADDR flag is set */
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == RESET) {
        if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) {
            // nack received for addr, release the bus cleanly
            hi2c->Instance->CR1 |= I2C_CR1_STOP;
            __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
            return -MP_ENODEV;
        }

        /* Check for the Timeout */
        if (Timeout != HAL_MAX_DELAY) {
            if ((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) {
                return -MP_ETIMEDOUT;
            }
        }
    }

    return 0;
}
Exemplo n.º 5
0
int i2c_slave_write(i2c_t *obj, const char *data, int length) {
    uint32_t Timeout;
    int size = 0;

    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);

    while (length > 0) {
        /* Wait until TXE flag is set */
        Timeout = FLAG_TIMEOUT;
        while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TXE) == RESET) {
            Timeout--;
            if (Timeout == 0) {
                return -1;
            }
        }


        /* Write data to DR */
        I2cHandle.Instance->DR = (*data++);
        length--;
        size++;

        if ((__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BTF) == SET) && (length != 0)) {
            /* Write data to DR */
            I2cHandle.Instance->DR = (*data++);
            length--;
            size++;
        }
    }

    /* Wait until AF flag is set */
    Timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_AF) == RESET) {
        Timeout--;
        if (Timeout == 0) {
            return -1;
        }
    }


    /* Clear AF flag */
    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_AF);


    /* Wait until BUSY flag is reset */
    Timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == SET) {
        Timeout--;
        if (Timeout == 0) {
            return -1;
        }
    }

    I2cHandle.State = HAL_I2C_STATE_READY;

    /* Process Unlocked */
    __HAL_UNLOCK(&I2cHandle);

    return size;
}
Exemplo n.º 6
0
// this function is based on STM code
STATIC bool I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c) {
    if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) {
        /* Clear NACKF Flag */
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
        return true;
    }
    return false;
}
Exemplo n.º 7
0
/**
  * @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 == 0)||((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;
}
Exemplo n.º 8
0
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
{
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);
    int timeout;
    int count;

    // Update CR2 register
    i2c->CR2 = (i2c->CR2 & (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)))
               | (uint32_t)(((uint32_t)address & I2C_CR2_SADD) | (((uint32_t)length << 16) & I2C_CR2_NBYTES) | (uint32_t)I2C_SOFTEND_MODE | (uint32_t)I2C_GENERATE_START_WRITE);

    for (count = 0; count < length; count++) {
        i2c_byte_write(obj, data[count]);
    }

    // Wait transfer complete
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TC) == RESET) {
        timeout--;
        if (timeout == 0) {
            return -1;
        }
    }
    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_TC);

    // If not repeated start, send stop
    if (stop) {
        i2c_stop(obj);
        // Wait until STOPF flag is set
        timeout = FLAG_TIMEOUT;
        while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_STOPF) == RESET) {
            timeout--;
            if (timeout == 0) {
                return -1;
            }
        }
        // Clear STOP Flag
        __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_STOPF);
    }

    return count;
}
Exemplo n.º 9
0
/**
  * @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 = 0x00;
  }

  /* Flush TX register if not empty */
  if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET)
  {
    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_TXE);
  }
}
Exemplo n.º 10
0
int i2c_slave_receive(i2c_t *obj) {
    int retValue = NoData;

    if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == 1) {
        if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_ADDR) == 1) {
            if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TRA) == 1)
                retValue = ReadAddressed;
            else
                retValue = WriteAddressed;

            __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_ADDR);
        }
    }

    return (retValue);
}
Exemplo n.º 11
0
int i2c_slave_receive(i2c_t *obj) {
    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);
    int retValue = NoData;

    if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == 1) {
        if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_ADDR) == 1) {
            if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_DIR) == 1)
                retValue = ReadAddressed;
            else
                retValue = WriteAddressed;
            __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_ADDR);
        }
    }

    return (retValue);
}
Exemplo n.º 12
0
// this function is based on STM code
STATIC int I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart) {
    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET) {
        /* Check if a STOPF is detected */
        if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET) {
            /* Clear STOP Flag */
            __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
            return -MP_EBUSY;
        }

        /* Check for the Timeout */
        if ((Timeout == 0U) || ((HAL_GetTick()-Tickstart) > Timeout)) {
            return -MP_ETIMEDOUT;
        }
    }
    return 0;
}
/**
  * @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;
}
Exemplo n.º 14
0
inline int i2c_start(i2c_t *obj)
{
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);

    // Clear Acknowledge failure flag
    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_AF);

    // Generate the START condition and remove an eventual pending STOP bit
    i2c->CR1 = ((i2c->CR1 & ~I2C_CR1_STOP) | I2C_CR1_START);

    // Wait the START condition has been correctly sent
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_SB) == RESET) {
        if ((timeout--) == 0) {
            return 1;
        }
    }

    return 0;
}
Exemplo n.º 15
0
void i2c_er_irq_handler(mp_uint_t i2c_id) {
    I2C_HandleTypeDef *hi2c;

    switch (i2c_id) {
        #if defined(MICROPY_HW_I2C1_SCL)
        case 1:
            hi2c = &I2CHandle1;
            break;
        #endif
        #if defined(MICROPY_HW_I2C2_SCL)
        case 2:
            hi2c = &I2CHandle2;
            break;
        #endif
        #if defined(MICROPY_HW_I2C3_SCL)
        case 3:
            hi2c = &I2CHandle3;
            break;
        #endif
        #if defined(MICROPY_HW_I2C4_SCL)
        case 4:
            hi2c = &I2CHandle4;
            break;
        #endif
        default:
            return;
    }

    #if defined(MCU_SERIES_F4)

    uint32_t sr1 = hi2c->Instance->SR1;

    // I2C Bus error
    if (sr1 & I2C_FLAG_BERR) {
        hi2c->ErrorCode |= HAL_I2C_ERROR_BERR;
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR);
    }

    // I2C Arbitration Loss error
    if (sr1 & I2C_FLAG_ARLO) {
        hi2c->ErrorCode |= HAL_I2C_ERROR_ARLO;
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO);
    }

    // I2C Acknowledge failure
    if (sr1 & I2C_FLAG_AF) {
        hi2c->ErrorCode |= HAL_I2C_ERROR_AF;
        SET_BIT(hi2c->Instance->CR1,I2C_CR1_STOP);
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
    }

    // I2C Over-Run/Under-Run
    if (sr1 & I2C_FLAG_OVR) {
        hi2c->ErrorCode |= HAL_I2C_ERROR_OVR;
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR);
    }

    #else

    // if not an F4 MCU, use the HAL's IRQ handler
    HAL_I2C_ER_IRQHandler(hi2c);

    #endif
}
Exemplo n.º 16
0
unsigned long TWI_MasterWriteRead(new_twi* TwiStruct, unsigned int TransmitBytes, unsigned int ReceiveBytes)
{
	uint32_t tickstart = 0;
	I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef *)TwiStruct->udata;
    /* Init tickstart for timeout management*/
    tickstart = HAL_GetTick();

    if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK)
    {
    	I2C_SoftwareResetCmd(hi2c);
      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  = TwiStruct->TxBuff;
    hi2c->XferCount = TransmitBytes;
    hi2c->XferISR   = NULL;

    /* Set NBYTES to write and reload if hi2c->XferCount > MAX_NBYTE_SIZE */
    if(hi2c->XferCount > MAX_NBYTE_SIZE)
    {
    	hi2c->XferSize = MAX_NBYTE_SIZE;
    	I2C_TransferConfig(hi2c, TwiStruct->MasterSlaveAddr, hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_WRITE);
    }
    else
    {
		if(ReceiveBytes != 0)
		{
			hi2c->XferSize = hi2c->XferCount;
			I2C_TransferConfig(hi2c, TwiStruct->MasterSlaveAddr, hi2c->XferSize, I2C_SOFTEND_MODE, I2C_GENERATE_START_WRITE);
		}
		else
		{
			hi2c->XferSize = hi2c->XferCount;
			I2C_TransferConfig(hi2c, TwiStruct->MasterSlaveAddr, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_WRITE);
		}
    }

	do
	{
	    tickstart = HAL_GetTick();
	      /* 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;
	        }
	      }

		/* Read data from RXDR */
	    hi2c->Instance->TXDR = (*hi2c->pBuffPtr++);
	    hi2c->XferCount--;
	    hi2c->XferSize--;

		if((hi2c->XferSize == 0) && (hi2c->XferCount != 0))
		{
			/* 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, TwiStruct->MasterSlaveAddr, hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
			}
			else
			{
				if(ReceiveBytes != 0)
				{
					hi2c->XferSize = hi2c->XferCount;
					I2C_TransferConfig(hi2c, TwiStruct->MasterSlaveAddr, hi2c->XferSize, I2C_SOFTEND_MODE, I2C_NO_STARTSTOP);
				}
				else
				{
					hi2c->XferSize = hi2c->XferCount;
					I2C_TransferConfig(hi2c, TwiStruct->MasterSlaveAddr, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
				}
			}
		}
	}while(hi2c->XferCount > 0);
	if(ReceiveBytes == 0)
	{
		/* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */
		/* Wait until STOPF flag is reset */
		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);
		/* Clear Configuration Register 2 */
		I2C_RESET_CR2(hi2c);
		hi2c->State = HAL_I2C_STATE_READY;
		hi2c->Mode  = HAL_I2C_MODE_NONE;
		/* Process Unlocked */
		__HAL_UNLOCK(hi2c);
		return HAL_OK;
	}

    tickstart = HAL_GetTick();

    /* Wait until TCR flag is set */
    if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TC, RESET, Timeout, 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  = TwiStruct->RxBuff;
    hi2c->XferCount = ReceiveBytes;
    hi2c->XferISR   = NULL;

    /* Set NBYTES to write and reload if hi2c->XferCount > MAX_NBYTE_SIZE */
    if(hi2c->XferCount > MAX_NBYTE_SIZE)
    {
    	hi2c->XferSize = MAX_NBYTE_SIZE;
    	I2C_TransferConfig(hi2c, TwiStruct->MasterSlaveAddr | 1, hi2c->XferSize, I2C_RELOAD_MODE, I2C_GENERATE_START_READ);
    }
    else
    {
    	hi2c->XferSize = hi2c->XferCount;
    	I2C_TransferConfig(hi2c, TwiStruct->MasterSlaveAddr | 1, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_GENERATE_START_READ);
    }

	do
	{
	    tickstart = HAL_GetTick();
		/* Wait until RXNE flag is set */
		if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_RXNE, RESET, Timeout, tickstart) != HAL_OK)
		{
			return HAL_TIMEOUT;
		}

		/* Read data from RXDR */
	    (*hi2c->pBuffPtr++) = hi2c->Instance->RXDR;
	    hi2c->XferSize--;
	    hi2c->XferCount--;

		if((hi2c->XferSize == 0) && (hi2c->XferCount != 0))
		{
			/* 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, TwiStruct->MasterSlaveAddr | 1, hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
			}
			else
			{
				hi2c->XferSize = hi2c->XferCount;
				I2C_TransferConfig(hi2c, TwiStruct->MasterSlaveAddr | 1, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
			}
		}
	}while(hi2c->XferCount > 0);
	/* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */
	/* Wait until STOPF flag is reset */
	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);

	/* Clear Configuration Register 2 */
	I2C_RESET_CR2(hi2c);

	hi2c->State = HAL_I2C_STATE_READY;
	hi2c->Mode  = HAL_I2C_MODE_NONE;

	/* Process Unlocked */
	__HAL_UNLOCK(hi2c);

	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;
  }
}