Exemplo n.º 1
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  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;
  }
}