Using "*_B1_*" for first logical I2C bus and "*_B2_*" for second logical I2C bus (instead of less clear I2C and I2CX).
2146 lines
64 KiB
C++
2146 lines
64 KiB
C++
/*
|
|
* Copyright (C) EdgeTX
|
|
*
|
|
* Based on code named
|
|
* OpenTX - https://github.com/opentx/opentx
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* The content of this file partially stems from STM32F4 HAL by STMicroelectronics.
|
|
*/
|
|
|
|
#include "opentx.h"
|
|
#include "i2c_driver.h"
|
|
|
|
/* I2C MSP Initialization
|
|
* This function configures the hardware resources used in this example
|
|
* @param hi2c: I2C handle pointer
|
|
* @retval None
|
|
*/
|
|
void I2C_MspInit(I2C_HandleTypeDef* hi2c)
|
|
{
|
|
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
|
|
|
if (I2C_B1_GPIO == GPIOA)
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
else if (I2C_B1_GPIO == GPIOB)
|
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
|
else if (I2C_B1_GPIO == GPIOC)
|
|
__HAL_RCC_GPIOC_CLK_ENABLE();
|
|
else if (I2C_B1_GPIO == GPIOH)
|
|
__HAL_RCC_GPIOH_CLK_ENABLE();
|
|
else
|
|
TRACE("I2C B1 ERROR: HAL_I2C_MspInit() I2C_GPIO misconfiguration");
|
|
|
|
#if defined(IMU_LSM6DS33)
|
|
if (I2C_B2_GPIO == GPIOA)
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
else if (I2C_B2_GPIO == GPIOB)
|
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
|
else if (I2C_B2_GPIO == GPIOC)
|
|
__HAL_RCC_GPIOC_CLK_ENABLE();
|
|
else if (I2C_B2_GPIO == GPIOH)
|
|
__HAL_RCC_GPIOH_CLK_ENABLE();
|
|
else
|
|
TRACE("I2C B2 ERROR: HAL_I2C_MspInit() I2C_GPIO misconfiguration");
|
|
#endif
|
|
|
|
if ((hi2c->Instance==I2C1) || (hi2c->Instance==I2C3)) // TP
|
|
{
|
|
GPIO_PinAFConfig(I2C_B1_GPIO, I2C_B1_SCL_GPIO_PinSource, I2C_B1_GPIO_AF);
|
|
GPIO_PinAFConfig(I2C_B1_GPIO, I2C_B1_SDA_GPIO_PinSource, I2C_B1_GPIO_AF);
|
|
|
|
GPIO_InitStruct.GPIO_Pin = I2C_B1_SCL_GPIO_PIN | I2C_B1_SDA_GPIO_PIN;
|
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
|
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
|
|
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
|
|
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
|
GPIO_Init(I2C_B1_GPIO, &GPIO_InitStruct);
|
|
}
|
|
|
|
#if defined(IMU_LSM6DS33)
|
|
if (hi2c->Instance==I2C2) // IMU
|
|
{
|
|
GPIO_PinAFConfig(I2C_B2_GPIO, I2C_B2_SCL_GPIO_PinSource, I2C_B2_GPIO_AF);
|
|
GPIO_PinAFConfig(I2C_B2_GPIO, I2C_B2_SDA_GPIO_PinSource, I2C_B2_GPIO_AF);
|
|
|
|
GPIO_InitStruct.GPIO_Pin = I2C_B2_SCL_GPIO_PIN | I2C_B2_SDA_GPIO_PIN;
|
|
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
|
|
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
|
|
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
|
|
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
|
GPIO_Init(I2C_B2_GPIO, &GPIO_InitStruct);
|
|
}
|
|
#endif
|
|
|
|
/* Peripheral clock enable */
|
|
if (I2C_B1 == I2C1)
|
|
__HAL_RCC_I2C1_CLK_ENABLE();
|
|
else if (I2C_B1 == I2C2)
|
|
__HAL_RCC_I2C2_CLK_ENABLE();
|
|
else if (I2C_B1 == I2C3)
|
|
__HAL_RCC_I2C3_CLK_ENABLE();
|
|
else
|
|
TRACE("I2C B1 ERROR: HAL_I2C_MspInit() I2C misconfiguration");
|
|
|
|
#if defined(IMU_LSM6DS33)
|
|
/* Peripheral clock enable */
|
|
if (I2C_B2 == I2C1)
|
|
__HAL_RCC_I2C1_CLK_ENABLE();
|
|
else if (I2C_B2 == I2C2)
|
|
__HAL_RCC_I2C2_CLK_ENABLE();
|
|
else if (I2C_B2 == I2C3)
|
|
__HAL_RCC_I2C3_CLK_ENABLE();
|
|
else
|
|
TRACE("I2C B2 ERROR: HAL_I2C_MspInit() I2C misconfiguration");
|
|
#endif
|
|
}
|
|
|
|
/* De-initializes the GPIOx peripheral registers to their default reset values.
|
|
* @param GPIOx where x can be (A..K) to select the GPIO peripheral for STM32F429X device or
|
|
* x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.
|
|
* @param GPIO_Pin specifies the port bit to be written.
|
|
* This parameter can be one of GPIO_PIN_x where x can be (0..15).
|
|
* @retval None
|
|
*/
|
|
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
|
|
{
|
|
uint32_t position;
|
|
uint32_t ioposition = 0x00U;
|
|
uint32_t iocurrent = 0x00U;
|
|
uint32_t tmp = 0x00U;
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
|
|
|
|
/* Configure the port pins */
|
|
for(position = 0U; position < GPIO_NUMBER; position++)
|
|
{
|
|
/* Get the IO position */
|
|
ioposition = 0x01U << position;
|
|
/* Get the current IO position */
|
|
iocurrent = (GPIO_Pin) & ioposition;
|
|
|
|
if(iocurrent == ioposition)
|
|
{
|
|
/*------------------------- EXTI Mode Configuration --------------------*/
|
|
tmp = SYSCFG->EXTICR[position >> 2U];
|
|
tmp &= (0x0FU << (4U * (position & 0x03U)));
|
|
if(tmp == ((uint32_t)(GPIO_GET_INDEX(GPIOx)) << (4U * (position & 0x03U))))
|
|
{
|
|
/* Clear EXTI line configuration */
|
|
EXTI->IMR &= ~((uint32_t)iocurrent);
|
|
EXTI->EMR &= ~((uint32_t)iocurrent);
|
|
|
|
/* Clear Rising Falling edge configuration */
|
|
EXTI->RTSR &= ~((uint32_t)iocurrent);
|
|
EXTI->FTSR &= ~((uint32_t)iocurrent);
|
|
|
|
/* Configure the External Interrupt or event for the current IO */
|
|
tmp = 0x0FU << (4U * (position & 0x03U));
|
|
SYSCFG->EXTICR[position >> 2U] &= ~tmp;
|
|
}
|
|
|
|
/*------------------------- GPIO Mode Configuration --------------------*/
|
|
/* Configure IO Direction in Input Floating Mode */
|
|
GPIOx->MODER &= ~(GPIO_MODER_MODER0 << (position * 2U));
|
|
|
|
/* Configure the default Alternate Function in current IO */
|
|
GPIOx->AFR[position >> 3U] &= ~(0xFU << ((uint32_t)(position & 0x07U) * 4U)) ;
|
|
|
|
/* Deactivate the Pull-up and Pull-down resistor for the current IO */
|
|
GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << (position * 2U));
|
|
|
|
/* Configure the default value IO Output Type */
|
|
GPIOx->OTYPER &= ~(GPIO_OTYPER_OT_0 << position) ;
|
|
|
|
/* Configure the default value for IO Speed */
|
|
GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2U));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* I2C MSP De-Initialization
|
|
* This function freeze the hardware resources used in this example
|
|
* @param hi2c: I2C handle pointer
|
|
* @retval None
|
|
*/
|
|
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* hi2c)
|
|
{
|
|
if(hi2c->Instance==I2C1)
|
|
{
|
|
__HAL_RCC_I2C1_CLK_DISABLE();
|
|
}
|
|
else
|
|
{
|
|
if(hi2c->Instance==I2C2)
|
|
{
|
|
__HAL_RCC_I2C2_CLK_DISABLE();
|
|
if(hi2c->Instance==I2C3)
|
|
__HAL_RCC_I2C3_CLK_DISABLE();
|
|
else
|
|
TRACE("I2C ERROR: HAL_I2C_MspDeInit() I2C misconfiguration");
|
|
}
|
|
}
|
|
|
|
GPIO_InitTypeDef GPIO_InitStructure;
|
|
|
|
/* Configure the default Alternate Function in current IO */
|
|
GPIO_PinAFConfig(I2C_B1_GPIO, I2C_B1_SCL_GPIO_PinSource, 0);
|
|
GPIO_PinAFConfig(I2C_B1_GPIO, I2C_B1_SDA_GPIO_PinSource, 0);
|
|
|
|
GPIO_InitStructure.GPIO_Pin = I2C_B1_SCL_GPIO_PIN | I2C_B1_SDA_GPIO_PIN;
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; /* Configure a low value for IO Speed */
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; /* Configure IO Direction in Input Floating Mode */
|
|
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; /* Leave the configuration to Open Drain */
|
|
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; /* Deactivate the Pull-up and Pull-down resistor for the current IO */
|
|
GPIO_Init(I2C_B1_GPIO, &GPIO_InitStructure);
|
|
}
|
|
|
|
/* Initializes the I2C according to the specified parameters
|
|
* in the HAL_I2C_InitTypeDef and initialize the associated handle.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2C.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
uint32_t freqrange;
|
|
uint32_t pclk1;
|
|
|
|
/* Check the I2C handle allocation */
|
|
if (hi2c == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance));
|
|
assert_param(IS_I2C_CLOCK_SPEED(hi2c->Init.ClockSpeed));
|
|
assert_param(IS_I2C_DUTY_CYCLE(hi2c->Init.DutyCycle));
|
|
assert_param(IS_I2C_OWN_ADDRESS1(hi2c->Init.OwnAddress1));
|
|
assert_param(IS_I2C_ADDRESSING_MODE(hi2c->Init.AddressingMode));
|
|
assert_param(IS_I2C_DUAL_ADDRESS(hi2c->Init.DualAddressMode));
|
|
assert_param(IS_I2C_OWN_ADDRESS2(hi2c->Init.OwnAddress2));
|
|
assert_param(IS_I2C_GENERAL_CALL(hi2c->Init.GeneralCallMode));
|
|
assert_param(IS_I2C_NO_STRETCH(hi2c->Init.NoStretchMode));
|
|
|
|
if (hi2c->State == HAL_I2C_STATE_RESET)
|
|
{
|
|
/* Allocate lock resource and initialize it */
|
|
hi2c->Lock = HAL_UNLOCKED;
|
|
|
|
/* Init the low level hardware : GPIO, CLOCK, NVIC */
|
|
I2C_MspInit(hi2c);
|
|
}
|
|
|
|
hi2c->State = HAL_I2C_STATE_BUSY;
|
|
|
|
/* Disable the selected I2C peripheral */
|
|
__HAL_I2C_DISABLE(hi2c);
|
|
|
|
/*Reset I2C*/
|
|
hi2c->Instance->CR1 |= I2C_CR1_SWRST;
|
|
hi2c->Instance->CR1 &= ~I2C_CR1_SWRST;
|
|
|
|
/* Get PCLK1 frequency */
|
|
RCC_ClocksTypeDef rccClocks;
|
|
RCC_GetClocksFreq(&rccClocks);
|
|
pclk1 = rccClocks.PCLK1_Frequency;
|
|
|
|
/* Check the minimum allowed PCLK1 frequency */
|
|
if (I2C_MIN_PCLK_FREQ(pclk1, hi2c->Init.ClockSpeed) == 1U)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Calculate frequency range */
|
|
freqrange = I2C_FREQRANGE(pclk1);
|
|
|
|
/*---------------------------- I2Cx CR2 Configuration ----------------------*/
|
|
/* Configure I2Cx: Frequency range */
|
|
MODIFY_REG(hi2c->Instance->CR2, I2C_CR2_FREQ, freqrange);
|
|
|
|
/*---------------------------- I2Cx TRISE Configuration --------------------*/
|
|
/* Configure I2Cx: Rise Time */
|
|
MODIFY_REG(hi2c->Instance->TRISE, I2C_TRISE_TRISE, I2C_RISE_TIME(freqrange, hi2c->Init.ClockSpeed));
|
|
|
|
/*---------------------------- I2Cx CCR Configuration ----------------------*/
|
|
/* Configure I2Cx: Speed */
|
|
MODIFY_REG(hi2c->Instance->CCR, (I2C_CCR_FS | I2C_CCR_DUTY | I2C_CCR_CCR), I2C_SPEED(pclk1, hi2c->Init.ClockSpeed, hi2c->Init.DutyCycle));
|
|
|
|
/*---------------------------- I2Cx CR1 Configuration ----------------------*/
|
|
/* Configure I2Cx: Generalcall and NoStretch mode */
|
|
MODIFY_REG(hi2c->Instance->CR1, (I2C_CR1_ENGC | I2C_CR1_NOSTRETCH), (hi2c->Init.GeneralCallMode | hi2c->Init.NoStretchMode));
|
|
|
|
/*---------------------------- I2Cx OAR1 Configuration ---------------------*/
|
|
/* Configure I2Cx: Own Address1 and addressing mode */
|
|
MODIFY_REG(hi2c->Instance->OAR1, (I2C_OAR1_ADDMODE | I2C_OAR1_ADD8_9 | I2C_OAR1_ADD1_7 | I2C_OAR1_ADD0), (hi2c->Init.AddressingMode | hi2c->Init.OwnAddress1));
|
|
|
|
/*---------------------------- I2Cx OAR2 Configuration ---------------------*/
|
|
/* Configure I2Cx: Dual mode and Own Address2 */
|
|
MODIFY_REG(hi2c->Instance->OAR2, (I2C_OAR2_ENDUAL | I2C_OAR2_ADD2), (hi2c->Init.DualAddressMode | hi2c->Init.OwnAddress2));
|
|
|
|
/* Enable the selected I2C peripheral */
|
|
__HAL_I2C_ENABLE(hi2c);
|
|
|
|
hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* DeInitialize the I2C peripheral.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2C.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_I2C_DeInit(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
/* Check the I2C handle allocation */
|
|
if (hi2c == NULL)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance));
|
|
|
|
hi2c->State = HAL_I2C_STATE_BUSY;
|
|
|
|
/* Disable the I2C Peripheral Clock */
|
|
__HAL_I2C_DISABLE(hi2c);
|
|
|
|
/* DeInit the low level hardware: GPIO, CLOCK, NVIC */
|
|
HAL_I2C_MspDeInit(hi2c);
|
|
|
|
hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
|
|
hi2c->State = HAL_I2C_STATE_RESET;
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
/* Release Lock */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* Configures I2C Analog noise filter.
|
|
* @param hi2c pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2Cx peripheral.
|
|
* @param AnalogFilter new state of the Analog filter.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_I2CEx_ConfigAnalogFilter(I2C_HandleTypeDef *hi2c, uint32_t AnalogFilter)
|
|
{
|
|
/* Check the parameters */
|
|
assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance));
|
|
assert_param(IS_I2C_ANALOG_FILTER(AnalogFilter));
|
|
|
|
if (hi2c->State == HAL_I2C_STATE_READY)
|
|
{
|
|
hi2c->State = HAL_I2C_STATE_BUSY;
|
|
|
|
/* Disable the selected I2C peripheral */
|
|
__HAL_I2C_DISABLE(hi2c);
|
|
|
|
/* Reset I2Cx ANOFF bit */
|
|
hi2c->Instance->FLTR &= ~(I2C_FLTR_ANOFF);
|
|
|
|
/* Disable the analog filter */
|
|
hi2c->Instance->FLTR |= AnalogFilter;
|
|
|
|
__HAL_I2C_ENABLE(hi2c);
|
|
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
|
|
return HAL_OK;
|
|
}
|
|
else
|
|
{
|
|
return HAL_BUSY;
|
|
}
|
|
}
|
|
|
|
/* Configures I2C Digital noise filter.
|
|
* @param hi2c pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2Cx peripheral.
|
|
* @param DigitalFilter Coefficient of digital noise filter between 0x00 and 0x0F.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_I2CEx_ConfigDigitalFilter(I2C_HandleTypeDef *hi2c, uint32_t DigitalFilter)
|
|
{
|
|
uint16_t tmpreg = 0;
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance));
|
|
assert_param(IS_I2C_DIGITAL_FILTER(DigitalFilter));
|
|
|
|
if (hi2c->State == HAL_I2C_STATE_READY)
|
|
{
|
|
hi2c->State = HAL_I2C_STATE_BUSY;
|
|
|
|
/* Disable the selected I2C peripheral */
|
|
__HAL_I2C_DISABLE(hi2c);
|
|
|
|
/* Get the old register value */
|
|
tmpreg = hi2c->Instance->FLTR;
|
|
|
|
/* Reset I2Cx DNF bit [3:0] */
|
|
tmpreg &= ~(I2C_FLTR_DNF);
|
|
|
|
/* Set I2Cx DNF coefficient */
|
|
tmpreg |= DigitalFilter;
|
|
|
|
/* Store the new register value */
|
|
hi2c->Instance->FLTR = tmpreg;
|
|
|
|
__HAL_I2C_ENABLE(hi2c);
|
|
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
|
|
return HAL_OK;
|
|
}
|
|
else
|
|
{
|
|
return HAL_BUSY;
|
|
}
|
|
}
|
|
|
|
/* 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
|
|
*/
|
|
static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart)
|
|
{
|
|
/* Wait until flag is set */
|
|
while (I2C_GetFlagStatus(hi2c->Instance, Flag) == Status)
|
|
{
|
|
/* Check for the Timeout */
|
|
if (Timeout != HAL_MAX_DELAY)
|
|
{
|
|
if (((xTaskGetTickCount() - Tickstart) > Timeout) || (Timeout == 0U))
|
|
{
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* This function handles I2C Communication Timeout for Master addressing phase.
|
|
* @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 Timeout Timeout duration
|
|
* @param Tickstart Tick start value
|
|
* @retval HAL status
|
|
*/
|
|
static HAL_StatusTypeDef I2C_WaitOnMasterAddressFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, uint32_t Timeout, uint32_t Tickstart)
|
|
{
|
|
while (I2C_GetFlagStatus(hi2c->Instance, Flag) == RESET)
|
|
{
|
|
if (I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_AF) == SET)
|
|
{
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
|
|
/* Clear AF Flag */
|
|
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
|
|
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_AF;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Check for the Timeout */
|
|
if (Timeout != HAL_MAX_DELAY)
|
|
{
|
|
if (((xTaskGetTickCount() - Tickstart) > Timeout) || (Timeout == 0U))
|
|
{
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for I2C module
|
|
* @param DevAddress Target device address: The device 7 bits address value
|
|
* in datasheet must be shifted to the left before calling the interface
|
|
* @param Timeout Timeout duration
|
|
* @param Tickstart Tick start value
|
|
* @retval HAL status
|
|
*/
|
|
static HAL_StatusTypeDef I2C_MasterRequestWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart)
|
|
{
|
|
/* Declaration of temporary variable to prevent undefined behavior of volatile usage */
|
|
uint32_t CurrentXferOptions = hi2c->XferOptions;
|
|
|
|
/* Generate Start condition if first transfer */
|
|
if ((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_NO_OPTION_FRAME))
|
|
{
|
|
/* Generate Start */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
|
|
}
|
|
else if (hi2c->PreviousState == I2C_STATE_MASTER_BUSY_RX)
|
|
{
|
|
/* Generate ReStart */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
|
|
}
|
|
else
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
|
|
/* Wait until SB flag is set */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START)
|
|
{
|
|
hi2c->ErrorCode = HAL_I2C_WRONG_START;
|
|
}
|
|
return HAL_TIMEOUT;
|
|
}
|
|
|
|
if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT)
|
|
{
|
|
/* Send slave address */
|
|
hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress);
|
|
}
|
|
else
|
|
{
|
|
/* Send header of slave address */
|
|
hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(DevAddress);
|
|
|
|
/* Wait until ADD10 flag is set */
|
|
if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADD10, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Send slave address */
|
|
hi2c->Instance->DR = I2C_10BIT_ADDRESS(DevAddress);
|
|
}
|
|
|
|
/* Wait until ADDR flag is set */
|
|
if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* 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.
|
|
* @retval HAL status
|
|
*/
|
|
static HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
if ( I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_AF) == SET)
|
|
{
|
|
/* Clear NACKF Flag */
|
|
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
|
|
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_AF;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* This function handles I2C Communication Timeout for specific usage of TXE 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_WaitOnTXEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)
|
|
{
|
|
while ( I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_TXE) == RESET)
|
|
{
|
|
/* Check if a NACK is detected */
|
|
if (I2C_IsAcknowledgeFailed(hi2c) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Check for the Timeout */
|
|
if (Timeout != HAL_MAX_DELAY)
|
|
{
|
|
if (((xTaskGetTickCount() - Tickstart) > Timeout) || (Timeout == 0U))
|
|
{
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* This function handles I2C Communication Timeout for specific usage of BTF 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_WaitOnBTFFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)
|
|
{
|
|
while ( I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_BTF) == RESET)
|
|
{
|
|
/* Check if a NACK is detected */
|
|
if (I2C_IsAcknowledgeFailed(hi2c) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Check for the Timeout */
|
|
if (Timeout != HAL_MAX_DELAY)
|
|
{
|
|
if (((xTaskGetTickCount() - Tickstart) > Timeout) || (Timeout == 0U))
|
|
{
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* 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
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
|
|
{
|
|
/* Init tickstart for timeout management*/
|
|
uint32_t tickstart = xTaskGetTickCount();
|
|
|
|
if (hi2c->State == HAL_I2C_STATE_READY)
|
|
{
|
|
/* Wait until BUSY flag is reset */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_BUSY;
|
|
}
|
|
|
|
/* Process Locked */
|
|
__HAL_LOCK(hi2c);
|
|
|
|
/* 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 */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS);
|
|
|
|
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->XferSize = hi2c->XferCount;
|
|
hi2c->XferOptions = I2C_NO_OPTION_FRAME;
|
|
|
|
/* Send Slave Address */
|
|
if (I2C_MasterRequestWrite(hi2c, DevAddress, Timeout, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
|
|
while (hi2c->XferSize > 0U)
|
|
{
|
|
/* Wait until TXE flag is set */
|
|
if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
|
|
{
|
|
if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
|
|
{
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Write data to DR */
|
|
hi2c->Instance->DR = *hi2c->pBuffPtr;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferCount--;
|
|
hi2c->XferSize--;
|
|
|
|
if (( I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U))
|
|
{
|
|
/* Write data to DR */
|
|
hi2c->Instance->DR = *hi2c->pBuffPtr;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferCount--;
|
|
hi2c->XferSize--;
|
|
}
|
|
|
|
/* Wait until BTF flag is set */
|
|
if (I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
|
|
{
|
|
if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
|
|
{
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_OK;
|
|
}
|
|
else
|
|
{
|
|
return HAL_BUSY;
|
|
}
|
|
}
|
|
|
|
/* Master sends target device address for read request.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for I2C module
|
|
* @param DevAddress Target device address: The device 7 bits address value
|
|
* in datasheet must be shifted to the left before calling the interface
|
|
* @param Timeout Timeout duration
|
|
* @param Tickstart Tick start value
|
|
* @retval HAL status
|
|
*/
|
|
static HAL_StatusTypeDef I2C_MasterRequestRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Timeout, uint32_t Tickstart)
|
|
{
|
|
/* Declaration of temporary variable to prevent undefined behavior of volatile usage */
|
|
uint32_t CurrentXferOptions = hi2c->XferOptions;
|
|
|
|
/* Enable Acknowledge */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
|
|
/* Generate Start condition if first transfer */
|
|
if ((CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_FIRST_FRAME) || (CurrentXferOptions == I2C_NO_OPTION_FRAME))
|
|
{
|
|
/* Generate Start */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
|
|
}
|
|
else if (hi2c->PreviousState == I2C_STATE_MASTER_BUSY_TX)
|
|
{
|
|
/* Generate ReStart */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
|
|
}
|
|
else
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
|
|
/* Wait until SB flag is set */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START)
|
|
{
|
|
hi2c->ErrorCode = HAL_I2C_WRONG_START;
|
|
}
|
|
return HAL_TIMEOUT;
|
|
}
|
|
|
|
if (hi2c->Init.AddressingMode == I2C_ADDRESSINGMODE_7BIT)
|
|
{
|
|
/* Send slave address */
|
|
hi2c->Instance->DR = I2C_7BIT_ADD_READ(DevAddress);
|
|
}
|
|
else
|
|
{
|
|
/* Send header of slave address */
|
|
hi2c->Instance->DR = I2C_10BIT_HEADER_WRITE(DevAddress);
|
|
|
|
/* Wait until ADD10 flag is set */
|
|
if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADD10, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Send slave address */
|
|
hi2c->Instance->DR = I2C_10BIT_ADDRESS(DevAddress);
|
|
|
|
/* Wait until ADDR flag is set */
|
|
if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
|
|
/* Generate Restart */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
|
|
|
|
/* Wait until SB flag is set */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START)
|
|
{
|
|
hi2c->ErrorCode = HAL_I2C_WRONG_START;
|
|
}
|
|
return HAL_TIMEOUT;
|
|
}
|
|
|
|
/* Send header of slave address */
|
|
hi2c->Instance->DR = I2C_10BIT_HEADER_READ(DevAddress);
|
|
}
|
|
|
|
/* Wait until ADDR flag is set */
|
|
if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
|
|
while ( I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_RXNE) == RESET)
|
|
{
|
|
/* Check if a STOPF is detected */
|
|
if ( I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_STOPF) == SET)
|
|
{
|
|
/* Clear STOP Flag */
|
|
__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
|
|
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_NONE;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Check for the Timeout */
|
|
if (((xTaskGetTickCount() - Tickstart) > Timeout) || (Timeout == 0U))
|
|
{
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* 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
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
|
|
{
|
|
/* Init tickstart for timeout management*/
|
|
uint32_t tickstart = xTaskGetTickCount();
|
|
|
|
if (hi2c->State == HAL_I2C_STATE_READY)
|
|
{
|
|
/* Wait until BUSY flag is reset */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_BUSY;
|
|
}
|
|
|
|
/* Process Locked */
|
|
__HAL_LOCK(hi2c);
|
|
|
|
/* 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 */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS);
|
|
|
|
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->XferSize = hi2c->XferCount;
|
|
hi2c->XferOptions = I2C_NO_OPTION_FRAME;
|
|
|
|
/* Send Slave Address */
|
|
if (I2C_MasterRequestRead(hi2c, DevAddress, Timeout, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if (hi2c->XferSize == 0U)
|
|
{
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
else if (hi2c->XferSize == 1U)
|
|
{
|
|
/* Disable Acknowledge */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
else if (hi2c->XferSize == 2U)
|
|
{
|
|
/* Disable Acknowledge */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
|
|
/* Enable Pos */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_POS);
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
}
|
|
else
|
|
{
|
|
/* Enable Acknowledge */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
}
|
|
|
|
while (hi2c->XferSize > 0U)
|
|
{
|
|
if (hi2c->XferSize <= 3U)
|
|
{
|
|
/* One byte */
|
|
if (hi2c->XferSize == 1U)
|
|
{
|
|
/* Wait until RXNE flag is set */
|
|
if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Read data from DR */
|
|
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferSize--;
|
|
hi2c->XferCount--;
|
|
}
|
|
/* Two bytes */
|
|
else if (hi2c->XferSize == 2U)
|
|
{
|
|
/* Wait until BTF flag is set */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
|
|
/* Read data from DR */
|
|
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferSize--;
|
|
hi2c->XferCount--;
|
|
|
|
/* Read data from DR */
|
|
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferSize--;
|
|
hi2c->XferCount--;
|
|
}
|
|
/* 3 Last bytes */
|
|
else
|
|
{
|
|
/* Wait until BTF flag is set */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Disable Acknowledge */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
|
|
/* Read data from DR */
|
|
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferSize--;
|
|
hi2c->XferCount--;
|
|
|
|
/* Wait until BTF flag is set */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
|
|
/* Read data from DR */
|
|
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferSize--;
|
|
hi2c->XferCount--;
|
|
|
|
/* Read data from DR */
|
|
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferSize--;
|
|
hi2c->XferCount--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Wait until RXNE flag is set */
|
|
if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Read data from DR */
|
|
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferSize--;
|
|
hi2c->XferCount--;
|
|
|
|
if ( I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_BTF) == SET)
|
|
{
|
|
/* Read data from DR */
|
|
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
|
|
|
|
/* Increment Buffer pointer */
|
|
hi2c->pBuffPtr++;
|
|
|
|
/* Update counter */
|
|
hi2c->XferSize--;
|
|
hi2c->XferCount--;
|
|
}
|
|
}
|
|
}
|
|
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_OK;
|
|
}
|
|
else
|
|
{
|
|
return HAL_BUSY;
|
|
}
|
|
}
|
|
|
|
/* Slave Tx Transfer completed callback.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2C.
|
|
* @retval None
|
|
*/
|
|
__weak void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
/* Prevent unused argument(s) compilation warning */
|
|
UNUSED(hi2c);
|
|
|
|
/* NOTE : This function should not be modified, when the callback is needed,
|
|
the HAL_I2C_SlaveTxCpltCallback could be implemented in the user file
|
|
*/
|
|
}
|
|
|
|
/* Slave Rx Transfer completed callback.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2C.
|
|
* @retval None
|
|
*/
|
|
__weak void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
/* Prevent unused argument(s) compilation warning */
|
|
UNUSED(hi2c);
|
|
|
|
/* NOTE : This function should not be modified, when the callback is needed,
|
|
the HAL_I2C_SlaveRxCpltCallback could be implemented in the user file
|
|
*/
|
|
}
|
|
|
|
/* I2C error callback.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2C.
|
|
* @retval None
|
|
*/
|
|
__weak void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
/* Prevent unused argument(s) compilation warning */
|
|
UNUSED(hi2c);
|
|
|
|
/* NOTE : This function should not be modified, when the callback is needed,
|
|
the HAL_I2C_ErrorCallback could be implemented in the user file
|
|
*/
|
|
}
|
|
|
|
/* Memory Tx Transfer completed callback.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2C.
|
|
* @retval None
|
|
*/
|
|
__weak void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
/* Prevent unused argument(s) compilation warning */
|
|
UNUSED(hi2c);
|
|
|
|
/* NOTE : This function should not be modified, when the callback is needed,
|
|
the HAL_I2C_MemTxCpltCallback could be implemented in the user file
|
|
*/
|
|
}
|
|
|
|
/* Memory Rx Transfer completed callback.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2C.
|
|
* @retval None
|
|
*/
|
|
__weak void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
/* Prevent unused argument(s) compilation warning */
|
|
UNUSED(hi2c);
|
|
|
|
/* NOTE : This function should not be modified, when the callback is needed,
|
|
the HAL_I2C_MemRxCpltCallback could be implemented in the user file
|
|
*/
|
|
}
|
|
|
|
/* Master Rx Transfer completed callback.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for the specified I2C.
|
|
* @retval None
|
|
*/
|
|
__weak void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
|
|
{
|
|
/* Prevent unused argument(s) compilation warning */
|
|
UNUSED(hi2c);
|
|
|
|
/* NOTE : This function should not be modified, when the callback is needed,
|
|
the HAL_I2C_MasterRxCpltCallback could be implemented in the user file
|
|
*/
|
|
}
|
|
|
|
/* DMA I2C process complete callback.
|
|
* @param hdma DMA handle
|
|
* @retval None
|
|
*/
|
|
static void I2C_DMAXferCplt(DMA_HandleTypeDef *hdma)
|
|
{
|
|
I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */
|
|
|
|
/* Declaration of temporary variable to prevent undefined behavior of volatile usage */
|
|
HAL_I2C_StateTypeDef CurrentState = hi2c->State;
|
|
HAL_I2C_ModeTypeDef CurrentMode = hi2c->Mode;
|
|
uint32_t CurrentXferOptions = hi2c->XferOptions;
|
|
|
|
/* Disable EVT and ERR interrupt */
|
|
__HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR);
|
|
|
|
/* Clear Complete callback */
|
|
if (hi2c->hdmatx != NULL)
|
|
{
|
|
hi2c->hdmatx->XferCpltCallback = NULL;
|
|
}
|
|
if (hi2c->hdmarx != NULL)
|
|
{
|
|
hi2c->hdmarx->XferCpltCallback = NULL;
|
|
}
|
|
|
|
if ((((uint32_t)CurrentState & (uint32_t)HAL_I2C_STATE_BUSY_TX) == (uint32_t)HAL_I2C_STATE_BUSY_TX) || ((((uint32_t)CurrentState & (uint32_t)HAL_I2C_STATE_BUSY_RX) == (uint32_t)HAL_I2C_STATE_BUSY_RX) && (CurrentMode == HAL_I2C_MODE_SLAVE)))
|
|
{
|
|
/* Disable DMA Request */
|
|
CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN);
|
|
|
|
hi2c->XferCount = 0U;
|
|
|
|
if (CurrentState == HAL_I2C_STATE_BUSY_TX_LISTEN)
|
|
{
|
|
/* Set state at HAL_I2C_STATE_LISTEN */
|
|
hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_TX;
|
|
hi2c->State = HAL_I2C_STATE_LISTEN;
|
|
|
|
/* Call the corresponding callback to inform upper layer of End of Transfer */
|
|
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
|
|
hi2c->SlaveTxCpltCallback(hi2c);
|
|
#else
|
|
HAL_I2C_SlaveTxCpltCallback(hi2c);
|
|
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
|
|
}
|
|
else if (CurrentState == HAL_I2C_STATE_BUSY_RX_LISTEN)
|
|
{
|
|
/* Set state at HAL_I2C_STATE_LISTEN */
|
|
hi2c->PreviousState = I2C_STATE_SLAVE_BUSY_RX;
|
|
hi2c->State = HAL_I2C_STATE_LISTEN;
|
|
|
|
/* Call the corresponding callback to inform upper layer of End of Transfer */
|
|
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
|
|
hi2c->SlaveRxCpltCallback(hi2c);
|
|
#else
|
|
HAL_I2C_SlaveRxCpltCallback(hi2c);
|
|
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
|
|
}
|
|
else
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
|
|
/* Enable EVT and ERR interrupt to treat end of transfer in IRQ handler */
|
|
__HAL_I2C_ENABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR);
|
|
}
|
|
/* Check current Mode, in case of treatment DMA handler have been preempted by a prior interrupt */
|
|
else if (hi2c->Mode != HAL_I2C_MODE_NONE)
|
|
{
|
|
if (hi2c->XferCount == (uint16_t)1)
|
|
{
|
|
/* Disable Acknowledge */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
}
|
|
|
|
/* Disable EVT and ERR interrupt */
|
|
__HAL_I2C_DISABLE_IT(hi2c, I2C_IT_EVT | I2C_IT_ERR);
|
|
|
|
/* Prepare next transfer or stop current transfer */
|
|
if ((CurrentXferOptions == I2C_NO_OPTION_FRAME) || (CurrentXferOptions == I2C_FIRST_AND_LAST_FRAME) || (CurrentXferOptions == I2C_OTHER_AND_LAST_FRAME) || (CurrentXferOptions == I2C_LAST_FRAME))
|
|
{
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
|
|
/* Disable Last DMA */
|
|
CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_LAST);
|
|
|
|
/* Disable DMA Request */
|
|
CLEAR_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN);
|
|
|
|
hi2c->XferCount = 0U;
|
|
|
|
/* Check if Errors has been detected during transfer */
|
|
if (hi2c->ErrorCode != HAL_I2C_ERROR_NONE)
|
|
{
|
|
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
|
|
hi2c->ErrorCallback(hi2c);
|
|
#else
|
|
HAL_I2C_ErrorCallback(hi2c);
|
|
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
|
|
}
|
|
else
|
|
{
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
|
|
if (hi2c->Mode == HAL_I2C_MODE_MEM)
|
|
{
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
|
|
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
|
|
hi2c->MemRxCpltCallback(hi2c);
|
|
#else
|
|
HAL_I2C_MemRxCpltCallback(hi2c);
|
|
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
|
|
}
|
|
else
|
|
{
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->PreviousState = I2C_STATE_MASTER_BUSY_RX;
|
|
|
|
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
|
|
hi2c->MasterRxCpltCallback(hi2c);
|
|
#else
|
|
HAL_I2C_MasterRxCpltCallback(hi2c);
|
|
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
}
|
|
|
|
/* Return the DMA error code
|
|
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified DMA Stream.
|
|
* @retval DMA Error Code
|
|
*/
|
|
uint32_t HAL_DMA_GetError(DMA_HandleTypeDef *hdma)
|
|
{
|
|
return hdma->ErrorCode;
|
|
}
|
|
|
|
/* DMA I2C communication error callback.
|
|
* @param hdma DMA handle
|
|
* @retval None
|
|
*/
|
|
static void I2C_DMAError(DMA_HandleTypeDef *hdma)
|
|
{
|
|
I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent; /* Derogation MISRAC2012-Rule-11.5 */
|
|
|
|
/* Clear Complete callback */
|
|
if (hi2c->hdmatx != NULL)
|
|
{
|
|
hi2c->hdmatx->XferCpltCallback = NULL;
|
|
}
|
|
if (hi2c->hdmarx != NULL)
|
|
{
|
|
hi2c->hdmarx->XferCpltCallback = NULL;
|
|
}
|
|
|
|
/* Ignore DMA FIFO error */
|
|
if (HAL_DMA_GetError(hdma) != HAL_DMA_ERROR_FE)
|
|
{
|
|
/* Disable Acknowledge */
|
|
hi2c->Instance->CR1 &= ~I2C_CR1_ACK;
|
|
|
|
hi2c->XferCount = 0U;
|
|
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_DMA;
|
|
|
|
#if (USE_HAL_I2C_REGISTER_CALLBACKS == 1)
|
|
hi2c->ErrorCallback(hi2c);
|
|
#else
|
|
HAL_I2C_ErrorCallback(hi2c);
|
|
#endif /* USE_HAL_I2C_REGISTER_CALLBACKS */
|
|
}
|
|
}
|
|
|
|
/* Sets the DMA Transfer parameter.
|
|
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified DMA Stream.
|
|
* @param SrcAddress The source memory Buffer address
|
|
* @param DstAddress The destination memory Buffer address
|
|
* @param DataLength The length of data to be transferred from source to destination
|
|
* @retval HAL status
|
|
*/
|
|
static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
|
|
{
|
|
/* Clear DBM bit */
|
|
hdma->Instance->CR &= (uint32_t)(~DMA_SxCR_DBM);
|
|
|
|
/* Configure DMA Stream data length */
|
|
hdma->Instance->NDTR = DataLength;
|
|
|
|
/* Memory to Peripheral */
|
|
if((hdma->Init.DMA_DIR) == DMA_MEMORY_TO_PERIPH)
|
|
{
|
|
/* Configure DMA Stream destination address */
|
|
hdma->Instance->PAR = DstAddress;
|
|
|
|
/* Configure DMA Stream source address */
|
|
hdma->Instance->M0AR = SrcAddress;
|
|
}
|
|
/* Peripheral to Memory */
|
|
else
|
|
{
|
|
/* Configure DMA Stream source address */
|
|
hdma->Instance->PAR = SrcAddress;
|
|
|
|
/* Configure DMA Stream destination address */
|
|
hdma->Instance->M0AR = DstAddress;
|
|
}
|
|
}
|
|
|
|
/* Start the DMA Transfer with interrupt enabled.
|
|
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified DMA Stream.
|
|
* @param SrcAddress The source memory Buffer address
|
|
* @param DstAddress The destination memory Buffer address
|
|
* @param DataLength The length of data to be transferred from source to destination
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
|
|
{
|
|
HAL_StatusTypeDef status = HAL_OK;
|
|
|
|
/* calculate DMA base and stream number */
|
|
DMA_Base_Registers *regs = (DMA_Base_Registers *)hdma->StreamBaseAddress;
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_DMA_BUFFER_SIZE(DataLength));
|
|
|
|
/* Process locked */
|
|
__HAL_LOCK(hdma);
|
|
|
|
if(HAL_DMA_STATE_READY == hdma->State)
|
|
{
|
|
/* Change DMA peripheral state */
|
|
hdma->State = HAL_DMA_STATE_BUSY;
|
|
|
|
/* Initialize the error code */
|
|
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
|
|
|
|
/* Configure the source, destination address and the data length */
|
|
DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);
|
|
|
|
/* Clear all interrupt flags at correct offset within the register */
|
|
regs->IFCR = 0x3FU << hdma->StreamIndex;
|
|
|
|
/* Enable Common interrupts*/
|
|
hdma->Instance->CR |= DMA_IT_TC | DMA_IT_TE | DMA_IT_DME;
|
|
|
|
if(hdma->XferHalfCpltCallback != NULL)
|
|
{
|
|
hdma->Instance->CR |= DMA_IT_HT;
|
|
}
|
|
|
|
/* Enable the Peripheral */
|
|
__HAL_DMA_ENABLE(hdma);
|
|
}
|
|
else
|
|
{
|
|
/* Process unlocked */
|
|
__HAL_UNLOCK(hdma);
|
|
|
|
/* Return error status */
|
|
status = HAL_BUSY;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Master sends target device address followed by internal memory address for read request.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for I2C module
|
|
* @param DevAddress Target device address: The device 7 bits address value
|
|
* in datasheet must be shifted to the left before calling the interface
|
|
* @param MemAddress Internal memory address
|
|
* @param MemAddSize Size of internal memory address
|
|
* @param Timeout Timeout duration
|
|
* @param Tickstart Tick start value
|
|
* @retval HAL status
|
|
*/
|
|
static HAL_StatusTypeDef I2C_RequestMemoryRead(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart)
|
|
{
|
|
/* Enable Acknowledge */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
|
|
/* Generate Start */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
|
|
|
|
/* Wait until SB flag is set */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START)
|
|
{
|
|
hi2c->ErrorCode = HAL_I2C_WRONG_START;
|
|
}
|
|
return HAL_TIMEOUT;
|
|
}
|
|
|
|
/* Send slave address */
|
|
hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress);
|
|
|
|
/* Wait until ADDR flag is set */
|
|
if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
|
|
/* Wait until TXE flag is set */
|
|
if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
|
|
{
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* If Memory address size is 8Bit */
|
|
if (MemAddSize == I2C_MEMADD_SIZE_8BIT)
|
|
{
|
|
/* Send Memory Address */
|
|
hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress);
|
|
}
|
|
/* If Memory address size is 16Bit */
|
|
else
|
|
{
|
|
/* Send MSB of Memory Address */
|
|
hi2c->Instance->DR = I2C_MEM_ADD_MSB(MemAddress);
|
|
|
|
/* Wait until TXE flag is set */
|
|
if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
|
|
{
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Send LSB of Memory Address */
|
|
hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress);
|
|
}
|
|
|
|
/* Wait until TXE flag is set */
|
|
if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
|
|
{
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Generate Restart */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
|
|
|
|
/* Wait until SB flag is set */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START)
|
|
{
|
|
hi2c->ErrorCode = HAL_I2C_WRONG_START;
|
|
}
|
|
return HAL_TIMEOUT;
|
|
}
|
|
|
|
/* Send slave address */
|
|
hi2c->Instance->DR = I2C_7BIT_ADD_READ(DevAddress);
|
|
|
|
/* Wait until ADDR flag is set */
|
|
if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* Aborts the DMA Transfer in Interrupt mode.
|
|
* @param hdma pointer to a DMA_HandleTypeDef structure that contains
|
|
* the configuration information for the specified DMA Stream.
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma)
|
|
{
|
|
if(hdma->State != HAL_DMA_STATE_BUSY)
|
|
{
|
|
hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
|
|
return HAL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Set Abort State */
|
|
hdma->State = HAL_DMA_STATE_ABORT;
|
|
|
|
/* Disable the stream */
|
|
__HAL_DMA_DISABLE(hdma);
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* Master sends target device address followed by internal memory address for write request.
|
|
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
|
|
* the configuration information for I2C module
|
|
* @param DevAddress Target device address: The device 7 bits address value
|
|
* in datasheet must be shifted to the left before calling the interface
|
|
* @param MemAddress Internal memory address
|
|
* @param MemAddSize Size of internal memory address
|
|
* @param Timeout Timeout duration
|
|
* @param Tickstart Tick start value
|
|
* @retval HAL status
|
|
*/
|
|
static HAL_StatusTypeDef I2C_RequestMemoryWrite(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint32_t Timeout, uint32_t Tickstart)
|
|
{
|
|
/* Generate Start */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_START);
|
|
|
|
/* Wait until SB flag is set */
|
|
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_SB, RESET, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (READ_BIT(hi2c->Instance->CR1, I2C_CR1_START) == I2C_CR1_START)
|
|
{
|
|
hi2c->ErrorCode = HAL_I2C_WRONG_START;
|
|
}
|
|
return HAL_TIMEOUT;
|
|
}
|
|
|
|
/* Send slave address */
|
|
hi2c->Instance->DR = I2C_7BIT_ADD_WRITE(DevAddress);
|
|
|
|
/* Wait until ADDR flag is set */
|
|
if (I2C_WaitOnMasterAddressFlagUntilTimeout(hi2c, I2C_FLAG_ADDR, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
|
|
/* Wait until TXE flag is set */
|
|
if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
|
|
{
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* If Memory address size is 8Bit */
|
|
if (MemAddSize == I2C_MEMADD_SIZE_8BIT)
|
|
{
|
|
/* Send Memory Address */
|
|
hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress);
|
|
}
|
|
/* If Memory address size is 16Bit */
|
|
else
|
|
{
|
|
/* Send MSB of Memory Address */
|
|
hi2c->Instance->DR = I2C_MEM_ADD_MSB(MemAddress);
|
|
|
|
/* Wait until TXE flag is set */
|
|
if (I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, Tickstart) != HAL_OK)
|
|
{
|
|
if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
|
|
{
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
}
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Send LSB of Memory Address */
|
|
hi2c->Instance->DR = I2C_MEM_ADD_LSB(MemAddress);
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
/* Write an amount of data in non-blocking mode with DMA to a specific memory address
|
|
* @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 MemAddress Internal memory address
|
|
* @param MemAddSize Size of internal memory address
|
|
* @param pData Pointer to data buffer
|
|
* @param Size Amount of data to be sent
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size)
|
|
{
|
|
__IO uint32_t count = 0U;
|
|
HAL_StatusTypeDef dmaxferstatus;
|
|
|
|
/* Init tickstart for timeout management*/
|
|
uint32_t tickstart = xTaskGetTickCount();
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_I2C_MEMADD_SIZE(MemAddSize));
|
|
|
|
if (hi2c->State == HAL_I2C_STATE_READY)
|
|
{
|
|
/* Wait until BUSY flag is reset */
|
|
count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U);
|
|
do
|
|
{
|
|
count--;
|
|
if (count == 0U)
|
|
{
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
while (I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_BUSY) != RESET);
|
|
|
|
/* Process Locked */
|
|
__HAL_LOCK(hi2c);
|
|
|
|
/* 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 */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS);
|
|
|
|
hi2c->State = HAL_I2C_STATE_BUSY_TX;
|
|
hi2c->Mode = HAL_I2C_MODE_MEM;
|
|
hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
|
|
|
|
/* Prepare transfer parameters */
|
|
hi2c->pBuffPtr = pData;
|
|
hi2c->XferCount = Size;
|
|
hi2c->XferSize = hi2c->XferCount;
|
|
hi2c->XferOptions = I2C_NO_OPTION_FRAME;
|
|
|
|
if (hi2c->XferSize > 0U)
|
|
{
|
|
if (hi2c->hdmatx != NULL)
|
|
{
|
|
/* Set the I2C DMA transfer complete callback */
|
|
hi2c->hdmatx->XferCpltCallback = I2C_DMAXferCplt;
|
|
|
|
/* Set the DMA error callback */
|
|
hi2c->hdmatx->XferErrorCallback = I2C_DMAError;
|
|
|
|
/* Set the unused DMA callbacks to NULL */
|
|
hi2c->hdmatx->XferHalfCpltCallback = NULL;
|
|
hi2c->hdmatx->XferM1CpltCallback = NULL;
|
|
hi2c->hdmatx->XferM1HalfCpltCallback = NULL;
|
|
hi2c->hdmatx->XferAbortCallback = NULL;
|
|
|
|
/* Enable the DMA stream */
|
|
dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)hi2c->pBuffPtr, (uint32_t)&hi2c->Instance->DR, hi2c->XferSize);
|
|
}
|
|
else
|
|
{
|
|
/* Update I2C state */
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
/* Update I2C error code */
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if (dmaxferstatus == HAL_OK)
|
|
{
|
|
/* Send Slave Address and Memory Address */
|
|
if (I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK)
|
|
{
|
|
/* Abort the ongoing DMA */
|
|
dmaxferstatus = HAL_DMA_Abort_IT(hi2c->hdmatx);
|
|
|
|
/* Prevent unused argument(s) compilation and MISRA warning */
|
|
UNUSED(dmaxferstatus);
|
|
|
|
/* Set the unused I2C DMA transfer complete callback to NULL */
|
|
hi2c->hdmatx->XferCpltCallback = NULL;
|
|
|
|
/* Disable Acknowledge */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
|
|
hi2c->XferSize = 0U;
|
|
hi2c->XferCount = 0U;
|
|
|
|
/* Disable I2C peripheral to prevent dummy data in buffer */
|
|
__HAL_I2C_DISABLE(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
/* Note : The I2C interrupts must be enabled after unlocking current process
|
|
to avoid the risk of I2C interrupt handle execution before current
|
|
process unlock */
|
|
/* Enable ERR interrupt */
|
|
__HAL_I2C_ENABLE_IT(hi2c, I2C_IT_ERR);
|
|
|
|
/* Enable DMA Request */
|
|
SET_BIT(hi2c->Instance->CR2, I2C_CR2_DMAEN);
|
|
|
|
return HAL_OK;
|
|
}
|
|
else
|
|
{
|
|
/* Update I2C state */
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
/* Update I2C error code */
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_DMA;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Update I2C state */
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
/* Update I2C error code */
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_SIZE;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return HAL_BUSY;
|
|
}
|
|
}
|
|
|
|
/* Reads an amount of data in non-blocking mode with DMA from a specific memory address.
|
|
* @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 MemAddress Internal memory address
|
|
* @param MemAddSize Size of internal memory address
|
|
* @param pData Pointer to data buffer
|
|
* @param Size Amount of data to be read
|
|
* @retval HAL status
|
|
*/
|
|
HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size)
|
|
{
|
|
/* Init tickstart for timeout management*/
|
|
uint32_t tickstart = xTaskGetTickCount();
|
|
__IO uint32_t count = 0U;
|
|
HAL_StatusTypeDef dmaxferstatus;
|
|
|
|
/* Check the parameters */
|
|
assert_param(IS_I2C_MEMADD_SIZE(MemAddSize));
|
|
|
|
if (hi2c->State == HAL_I2C_STATE_READY)
|
|
{
|
|
/* Wait until BUSY flag is reset */
|
|
count = I2C_TIMEOUT_BUSY_FLAG * (SystemCoreClock / 25U / 1000U);
|
|
do
|
|
{
|
|
count--;
|
|
if (count == 0U)
|
|
{
|
|
hi2c->PreviousState = I2C_STATE_NONE;
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
while (I2C_GetFlagStatus(hi2c->Instance, I2C_FLAG_BUSY) != RESET);
|
|
|
|
/* Process Locked */
|
|
__HAL_LOCK(hi2c);
|
|
|
|
/* 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 */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_POS);
|
|
|
|
hi2c->State = HAL_I2C_STATE_BUSY_RX;
|
|
hi2c->Mode = HAL_I2C_MODE_MEM;
|
|
hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
|
|
|
|
/* Prepare transfer parameters */
|
|
hi2c->pBuffPtr = pData;
|
|
hi2c->XferCount = Size;
|
|
hi2c->XferSize = hi2c->XferCount;
|
|
hi2c->XferOptions = I2C_NO_OPTION_FRAME;
|
|
|
|
if (hi2c->XferSize > 0U)
|
|
{
|
|
if (hi2c->hdmarx != NULL)
|
|
{
|
|
/* Set the I2C DMA transfer complete callback */
|
|
hi2c->hdmarx->XferCpltCallback = I2C_DMAXferCplt;
|
|
|
|
/* Set the DMA error callback */
|
|
hi2c->hdmarx->XferErrorCallback = I2C_DMAError;
|
|
|
|
/* Set the unused DMA callbacks to NULL */
|
|
hi2c->hdmarx->XferHalfCpltCallback = NULL;
|
|
hi2c->hdmarx->XferM1CpltCallback = NULL;
|
|
hi2c->hdmarx->XferM1HalfCpltCallback = NULL;
|
|
hi2c->hdmarx->XferAbortCallback = NULL;
|
|
|
|
/* Enable the DMA stream */
|
|
dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmarx, (uint32_t)&hi2c->Instance->DR, (uint32_t)hi2c->pBuffPtr, hi2c->XferSize);
|
|
}
|
|
else
|
|
{
|
|
/* Update I2C state */
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
/* Update I2C error code */
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_DMA_PARAM;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if (dmaxferstatus == HAL_OK)
|
|
{
|
|
/* Send Slave Address and Memory Address */
|
|
if (I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK)
|
|
{
|
|
/* Abort the ongoing DMA */
|
|
dmaxferstatus = HAL_DMA_Abort_IT(hi2c->hdmarx);
|
|
|
|
/* Prevent unused argument(s) compilation and MISRA warning */
|
|
UNUSED(dmaxferstatus);
|
|
|
|
/* Set the unused I2C DMA transfer complete callback to NULL */
|
|
hi2c->hdmarx->XferCpltCallback = NULL;
|
|
|
|
/* Disable Acknowledge */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
|
|
hi2c->XferSize = 0U;
|
|
hi2c->XferCount = 0U;
|
|
|
|
/* Disable I2C peripheral to prevent dummy data in buffer */
|
|
__HAL_I2C_DISABLE(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if (hi2c->XferSize == 1U)
|
|
{
|
|
/* Disable Acknowledge */
|
|
CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
|
|
}
|
|
else
|
|
{
|
|
/* Enable Last DMA bit */
|
|
SET_BIT(hi2c->Instance->CR2, I2C_CR2_LAST);
|
|
}
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
/* Note : The I2C interrupts must be enabled after unlocking current process
|
|
to avoid the risk of I2C interrupt handle execution before current
|
|
process unlock */
|
|
/* Enable ERR interrupt */
|
|
__HAL_I2C_ENABLE_IT(hi2c, I2C_IT_ERR);
|
|
|
|
/* Enable DMA Request */
|
|
hi2c->Instance->CR2 |= I2C_CR2_DMAEN;
|
|
}
|
|
else
|
|
{
|
|
/* Update I2C state */
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
hi2c->Mode = HAL_I2C_MODE_NONE;
|
|
|
|
/* Update I2C error code */
|
|
hi2c->ErrorCode |= HAL_I2C_ERROR_DMA;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
|
|
return HAL_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Send Slave Address and Memory Address */
|
|
if (I2C_RequestMemoryRead(hi2c, DevAddress, MemAddress, MemAddSize, I2C_TIMEOUT_FLAG, tickstart) != HAL_OK)
|
|
{
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
/* Clear ADDR flag */
|
|
__HAL_I2C_CLEAR_ADDRFLAG(hi2c);
|
|
|
|
/* Generate Stop */
|
|
SET_BIT(hi2c->Instance->CR1, I2C_CR1_STOP);
|
|
|
|
hi2c->State = HAL_I2C_STATE_READY;
|
|
|
|
/* Process Unlocked */
|
|
__HAL_UNLOCK(hi2c);
|
|
}
|
|
|
|
return HAL_OK;
|
|
}
|
|
else
|
|
{
|
|
return HAL_BUSY;
|
|
}
|
|
}
|