You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ut...@apache.org on 2018/04/18 21:56:33 UTC

[mynewt-core] 10/13: Add i2c driver for F3/F7

This is an automated email from the ASF dual-hosted git repository.

utzig pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 20e796df31323b54b9f125690286114a773d0b8b
Author: Fabio Utzig <ut...@apache.org>
AuthorDate: Thu Mar 22 14:55:17 2018 -0300

    Add i2c driver for F3/F7
    
    This breaks the stm32cube based driver into two different drivers, one
    which is compiled in if the BSP is based on F1/L1/F4 and another for
    F3/F7.
    
    FIXME: the driver for F3 is using a delay when no stop was sent by
    previous message, might be due to not enough time between messages, need
    to check timing register...
---
 ..._driver_mod_i2c.c => stm32_driver_mod_i2c_v1.c} |  10 +-
 .../stm/stm32_common/src/stm32_driver_mod_i2c_v2.c | 647 +++++++++++++++++++++
 hw/mcu/stm/stm32f1xx/src/hal_i2c.c                 |  34 +-
 3 files changed, 678 insertions(+), 13 deletions(-)

diff --git a/hw/mcu/stm/stm32_common/src/stm32_driver_mod_i2c.c b/hw/mcu/stm/stm32_common/src/stm32_driver_mod_i2c_v1.c
similarity index 95%
rename from hw/mcu/stm/stm32_common/src/stm32_driver_mod_i2c.c
rename to hw/mcu/stm/stm32_common/src/stm32_driver_mod_i2c_v1.c
index 367e09f..c6e02a8 100644
--- a/hw/mcu/stm/stm32_common/src/stm32_driver_mod_i2c.c
+++ b/hw/mcu/stm/stm32_common/src/stm32_driver_mod_i2c_v1.c
@@ -29,6 +29,8 @@
 #include <mcu/stm32_hal.h>
 #include <syscfg/syscfg.h>
 
+#if !defined(STM32F3) && !defined(STM32F7)
+
 #define I2C_TIMEOUT_BUSY_FLAG     25U         /*!< Timeout 25 ms             */
 #define I2C_NO_OPTION_FRAME       0xFFFF0000U /*!< XferOptions default value */
 
@@ -125,8 +127,6 @@ static HAL_StatusTypeDef I2C_WaitOnMasterAddressFlagUntilTimeout(I2C_HandleTypeD
   return HAL_OK;
 }
 
-
-
 /**
   * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
   *         the configuration information for I2C module
@@ -345,8 +345,6 @@ static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *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
@@ -356,6 +354,7 @@ static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c,
   * @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,
@@ -606,6 +605,7 @@ static HAL_StatusTypeDef I2C_MasterRequestRead(I2C_HandleTypeDef *hi2c, uint16_t
   * @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,
@@ -852,4 +852,6 @@ HAL_StatusTypeDef HAL_I2C_Master_Receive_Custom(I2C_HandleTypeDef *hi2c,
   }
 }
 
+#endif /* !defined(STM32F3) && !defined(STM32F7) */
+
 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/hw/mcu/stm/stm32_common/src/stm32_driver_mod_i2c_v2.c b/hw/mcu/stm/stm32_common/src/stm32_driver_mod_i2c_v2.c
new file mode 100644
index 0000000..b24ee86
--- /dev/null
+++ b/hw/mcu/stm/stm32_common/src/stm32_driver_mod_i2c_v2.c
@@ -0,0 +1,647 @@
+/**
+  * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+  *
+  * Redistribution and use in source and binary forms, with or without modification,
+  * are permitted provided that the following conditions are met:
+  *   1. Redistributions of source code must retain the above copyright notice,
+  *      this list of conditions and the following disclaimer.
+  *   2. Redistributions in binary form must reproduce the above copyright notice,
+  *      this list of conditions and the following disclaimer in the documentation
+  *      and/or other materials provided with the distribution.
+  *   3. Neither the name of STMicroelectronics nor the names of its contributors
+  *      may be used to endorse or promote products derived from this software
+  *      without specific prior written permission.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  ******************************************************************************
+  */
+
+#include <os/os_time.h>
+#include <mcu/stm32_hal.h>
+#include <syscfg/syscfg.h>
+
+#if defined(STM32F3) || defined(STM32F7)
+
+#define I2C_TIMEOUT_BUSY    (25U)          /*!< 25 ms */
+
+#define MAX_NBYTE_SIZE      255U
+
+static const uint8_t HAL_I2C_MODE_MASTER_SEL = 0x11;
+
+/**
+  * @brief  This function handles I2C Communication Timeout.
+  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
+  *         the configuration information for I2C module
+  * @param  Flag specifies the I2C flag to check.
+  * @param  Status The new Flag status (SET or RESET).
+  * @param  Timeout Timeout duration
+  * @param  Tickstart Tick start value
+  * @retval HAL status
+  */
+/*
+ * FIXME: this function is similar enough that it could be shared between
+ * both i2c drivers.
+ */
+static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c,
+        uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart)
+{
+  while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status)
+  {
+    /* Check for the Timeout */
+    if (Timeout != HAL_MAX_DELAY)
+    {
+      if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
+      {
+        hi2c->State = HAL_I2C_STATE_READY;
+        hi2c->Mode = HAL_I2C_MODE_NONE;
+
+        /* Process Unlocked */
+        __HAL_UNLOCK(hi2c);
+        return HAL_TIMEOUT;
+      }
+    }
+  }
+  return HAL_OK;
+}
+
+/**
+  * @brief  Handles I2Cx communication when starting transfer or during transfer (TC or TCR flag are set).
+  * @param  hi2c I2C handle.
+  * @param  DevAddress Specifies the slave address to be programmed.
+  * @param  Size Specifies the number of bytes to be programmed.
+  *   This parameter must be a value between 0 and 255.
+  * @param  Mode New state of the I2C START condition generation.
+  *   This parameter can be one of the following values:
+  *     @arg @ref I2C_RELOAD_MODE Enable Reload mode .
+  *     @arg @ref I2C_AUTOEND_MODE Enable Automatic end mode.
+  *     @arg @ref I2C_SOFTEND_MODE Enable Software end mode.
+  * @param  Request New state of the I2C START condition generation.
+  *   This parameter can be one of the following values:
+  *     @arg @ref I2C_NO_STARTSTOP Don't Generate stop and start condition.
+  *     @arg @ref I2C_GENERATE_STOP Generate stop condition (Size should be set to 0).
+  *     @arg @ref I2C_GENERATE_START_READ Generate Restart for read request.
+  *     @arg @ref I2C_GENERATE_START_WRITE Generate Restart for write request.
+  * @retval None
+  */
+static void I2C_TransferConfig(I2C_HandleTypeDef *hi2c,  uint16_t DevAddress, uint8_t Size, uint32_t Mode, uint32_t Request)
+{
+  uint32_t tmpreg = 0U;
+
+  /* Check the parameters */
+  assert_param(IS_I2C_ALL_INSTANCE(hi2c->Instance));
+  assert_param(IS_TRANSFER_MODE(Mode));
+  assert_param(IS_TRANSFER_REQUEST(Request));
+
+  /* Get the CR2 register value */
+  tmpreg = hi2c->Instance->CR2;
+
+  /* clear tmpreg specific bits */
+  tmpreg &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP));
+
+  /* update tmpreg */
+  tmpreg |= (uint32_t)(((uint32_t)DevAddress & I2C_CR2_SADD) | (((uint32_t)Size << 16) & I2C_CR2_NBYTES) | \
+                       (uint32_t)Mode | (uint32_t)Request);
+
+  /* update CR2 register */
+  hi2c->Instance->CR2 = tmpreg;
+}
+
+/**
+  * @brief  I2C Tx data register flush process.
+  * @param  hi2c I2C handle.
+  * @retval None
+  */
+static void I2C_Flush_TXDR(I2C_HandleTypeDef *hi2c)
+{
+  /* If a pending TXIS flag is set */
+  /* Write a dummy data in TXDR to clear it */
+  if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) != RESET)
+  {
+    hi2c->Instance->TXDR = 0x00U;
+  }
+
+  /* Flush TX register if not empty */
+  if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET)
+  {
+    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_TXE);
+  }
+}
+
+/**
+  * @brief  This function handles Acknowledge failed detection during an I2C Communication.
+  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
+  *                the configuration information for the specified I2C.
+  * @param  Timeout Timeout duration
+  * @param  Tickstart Tick start value
+  * @retval HAL status
+  */
+static HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)
+{
+  if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET)
+  {
+    /* Wait until STOP Flag is reset */
+    /* AutoEnd should be initiate after AF */
+    while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET)
+    {
+      /* Check for the Timeout */
+      if (Timeout != HAL_MAX_DELAY)
+      {
+        if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
+        {
+          hi2c->State = HAL_I2C_STATE_READY;
+          hi2c->Mode = HAL_I2C_MODE_NONE;
+
+          /* Process Unlocked */
+          __HAL_UNLOCK(hi2c);
+          return HAL_TIMEOUT;
+        }
+      }
+    }
+
+    /* Clear NACKF Flag */
+    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
+
+    /* Clear STOP Flag */
+    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
+
+    /* Flush TX register */
+    I2C_Flush_TXDR(hi2c);
+
+    /* Clear Configuration Register 2 */
+    I2C_RESET_CR2(hi2c);
+
+    hi2c->ErrorCode = HAL_I2C_ERROR_AF;
+    hi2c->State = HAL_I2C_STATE_READY;
+    hi2c->Mode = HAL_I2C_MODE_NONE;
+
+    /* Process Unlocked */
+    __HAL_UNLOCK(hi2c);
+
+    return HAL_ERROR;
+  }
+  return HAL_OK;
+}
+
+/**
+  * @brief  This function handles I2C Communication Timeout for specific usage of TXIS flag.
+  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
+  *                the configuration information for the specified I2C.
+  * @param  Timeout Timeout duration
+  * @param  Tickstart Tick start value
+  * @retval HAL status
+  */
+static HAL_StatusTypeDef I2C_WaitOnTXISFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)
+{
+  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) == RESET)
+  {
+    /* Check if a NACK is detected */
+    if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK)
+    {
+      return HAL_ERROR;
+    }
+
+    /* Check for the Timeout */
+    if (Timeout != HAL_MAX_DELAY)
+    {
+      if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
+      {
+        hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
+        hi2c->State = HAL_I2C_STATE_READY;
+        hi2c->Mode = HAL_I2C_MODE_NONE;
+
+        /* Process Unlocked */
+        __HAL_UNLOCK(hi2c);
+
+        return HAL_TIMEOUT;
+      }
+    }
+  }
+  return HAL_OK;
+}
+
+/**
+  * @brief  This function handles I2C Communication Timeout for specific usage of STOP flag.
+  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
+  *                the configuration information for the specified I2C.
+  * @param  Timeout Timeout duration
+  * @param  Tickstart Tick start value
+  * @retval HAL status
+  */
+static HAL_StatusTypeDef I2C_WaitOnSTOPFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)
+{
+  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET)
+  {
+    /* Check if a NACK is detected */
+    if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK)
+    {
+      return HAL_ERROR;
+    }
+
+    /* Check for the Timeout */
+    if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
+    {
+      hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
+      hi2c->State = HAL_I2C_STATE_READY;
+      hi2c->Mode = HAL_I2C_MODE_NONE;
+
+      /* Process Unlocked */
+      __HAL_UNLOCK(hi2c);
+
+      return HAL_TIMEOUT;
+    }
+  }
+  return HAL_OK;
+}
+
+/**
+  * @brief  Transmits in master mode an amount of data in blocking mode.
+  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
+  *                the configuration information for the specified I2C.
+  * @param  DevAddress Target device address The device 7 bits address value
+  *         in datasheet must be shifted to the left before calling the interface
+  * @param  pData Pointer to data buffer
+  * @param  Size Amount of data to be sent
+  * @param  Timeout Timeout duration
+  * @param  LastOp If set sends STOP, otherwise no STOP
+  * @retval HAL status
+  */
+HAL_StatusTypeDef HAL_I2C_Master_Transmit_Custom(I2C_HandleTypeDef *hi2c,
+        uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout,
+        uint8_t LastOp)
+{
+  uint32_t tickstart = 0U;
+
+  if (hi2c->State == HAL_I2C_STATE_READY)
+  {
+    /* Process Locked */
+    __HAL_LOCK(hi2c);
+
+    /* Init tickstart for timeout management*/
+    tickstart = HAL_GetTick();
+
+    if (hi2c->Mode != HAL_I2C_MODE_MASTER_SEL)
+    {
+      if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK)
+      {
+        return HAL_TIMEOUT;
+      }
+    }
+    else
+    {
+      /* FIXME: with not stop must wait here! why? timing config? */
+      os_time_delay(1);
+    }
+
+    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);
+    }
+
+    while (hi2c->XferCount > 0U)
+    {
+      /* Wait until TXIS flag is set */
+      if (I2C_WaitOnTXISFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
+      {
+        if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
+        {
+          return HAL_ERROR;
+        }
+        else
+        {
+          return HAL_TIMEOUT;
+        }
+      }
+      /* Write data to TXDR */
+      hi2c->Instance->TXDR = (*hi2c->pBuffPtr++);
+      hi2c->XferCount--;
+      hi2c->XferSize--;
+
+      if ((hi2c->XferSize == 0U) && (hi2c->XferCount != 0U))
+      {
+        /* Wait until TCR flag is set */
+        if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK)
+        {
+          return HAL_TIMEOUT;
+        }
+
+        if (hi2c->XferCount > MAX_NBYTE_SIZE)
+        {
+          hi2c->XferSize = MAX_NBYTE_SIZE;
+          I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
+        }
+        else if (!LastOp)
+        {
+          hi2c->XferSize = hi2c->XferCount;
+          I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_SOFTEND_MODE, I2C_NO_STARTSTOP);
+        }
+        else
+        {
+          hi2c->XferSize = hi2c->XferCount;
+          I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
+        }
+      }
+    }
+
+    if (LastOp)
+    {
+      /* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */
+      /* Wait until STOPF flag is set */
+      if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
+      {
+        if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
+        {
+          return HAL_ERROR;
+        }
+        else
+        {
+          return HAL_TIMEOUT;
+        }
+      }
+
+      /* Clear STOP Flag */
+      __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
+    }
+    else
+    {
+      /* No autoend/reload was requested, make sure transmission of last byte
+       * has finished... */
+      if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TC, SET, Timeout, tickstart) != HAL_OK)
+      {
+        return HAL_TIMEOUT;
+      }
+    }
+
+    /* Clear Configuration Register 2 */
+    I2C_RESET_CR2(hi2c);
+
+    hi2c->State = HAL_I2C_STATE_READY;
+    if (LastOp)
+    {
+      hi2c->Mode = HAL_I2C_MODE_NONE;
+    }
+    else
+    {
+      hi2c->Mode = HAL_I2C_MODE_MASTER_SEL;
+    }
+
+    /* Process Unlocked */
+    __HAL_UNLOCK(hi2c);
+
+    return HAL_OK;
+  }
+  else
+  {
+    return HAL_BUSY;
+  }
+}
+
+/**
+  * @brief  This function handles I2C Communication Timeout for specific usage of RXNE flag.
+  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
+  *                the configuration information for the specified I2C.
+  * @param  Timeout Timeout duration
+  * @param  Tickstart Tick start value
+  * @retval HAL status
+  */
+static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)
+{
+  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_ERROR;
+    }
+
+    /* 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);
+
+      /* Clear Configuration Register 2 */
+      I2C_RESET_CR2(hi2c);
+
+      hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
+      hi2c->State = HAL_I2C_STATE_READY;
+      hi2c->Mode = HAL_I2C_MODE_NONE;
+
+      /* Process Unlocked */
+      __HAL_UNLOCK(hi2c);
+
+      return HAL_ERROR;
+    }
+
+    /* Check for the Timeout */
+    if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
+    {
+      hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
+      hi2c->State = HAL_I2C_STATE_READY;
+
+      /* Process Unlocked */
+      __HAL_UNLOCK(hi2c);
+
+      return HAL_TIMEOUT;
+    }
+  }
+  return HAL_OK;
+}
+
+/**
+  * @brief  Receives in master mode an amount of data in blocking mode. 
+  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
+  *                the configuration information for the specified I2C.
+  * @param  DevAddress Target device address The device 7 bits address value
+  *         in datasheet must be shifted to the left before calling the interface
+  * @param  pData Pointer to data buffer
+  * @param  Size Amount of data to be sent
+  * @param  Timeout Timeout duration
+  * @param  LastOp If set sends STOP, otherwise no STOP
+  * @retval HAL status
+  */
+HAL_StatusTypeDef HAL_I2C_Master_Receive_Custom(I2C_HandleTypeDef *hi2c,
+        uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout,
+        uint8_t LastOp)
+{
+  uint32_t tickstart = 0U;
+
+  if (hi2c->State == HAL_I2C_STATE_READY)
+  {
+    /* Process Locked */
+    __HAL_LOCK(hi2c);
+
+    /* Init tickstart for timeout management*/
+    tickstart = HAL_GetTick();
+
+    if (hi2c->Mode != HAL_I2C_MODE_MASTER_SEL)
+    {
+      if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY, tickstart) != HAL_OK)
+      {
+        return HAL_TIMEOUT;
+      }
+    }
+    else
+    {
+      /* FIXME: with not stop must wait here! why? timing config? */
+      os_time_delay(1);
+    }
+
+    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 */
+      if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
+      {
+        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 ((hi2c->XferSize == 0U) && (hi2c->XferCount != 0U))
+      {
+        /* Wait until TCR flag is set */
+        if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TCR, RESET, Timeout, tickstart) != HAL_OK)
+        {
+          return HAL_TIMEOUT;
+        }
+
+        if (hi2c->XferCount > MAX_NBYTE_SIZE)
+        {
+          hi2c->XferSize = MAX_NBYTE_SIZE;
+          I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_RELOAD_MODE, I2C_NO_STARTSTOP);
+        }
+        else if (!LastOp)
+        {
+          hi2c->XferSize = hi2c->XferCount;
+          I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_SOFTEND_MODE, I2C_NO_STARTSTOP);
+        }
+        else
+        {
+          hi2c->XferSize = hi2c->XferCount;
+          I2C_TransferConfig(hi2c, DevAddress, hi2c->XferSize, I2C_AUTOEND_MODE, I2C_NO_STARTSTOP);
+        }
+      }
+    }
+
+    if (LastOp)
+    {
+      /* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */
+      /* Wait until STOPF flag is set */
+      if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
+      {
+        if (hi2c->ErrorCode == HAL_I2C_ERROR_AF)
+        {
+          return HAL_ERROR;
+        }
+        else
+        {
+          return HAL_TIMEOUT;
+        }
+      }
+
+      /* Clear STOP Flag */
+      __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
+    }
+    else
+    {
+      /* No autoend/reload was requested, make sure transmission of last byte
+       * has finished... */
+      if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_TC, SET, Timeout, tickstart) != HAL_OK)
+      {
+        return HAL_TIMEOUT;
+      }
+    }
+
+    /* Clear Configuration Register 2 */
+    I2C_RESET_CR2(hi2c);
+
+    hi2c->State = HAL_I2C_STATE_READY;
+    if (LastOp)
+    {
+      hi2c->Mode  = HAL_I2C_MODE_NONE;
+    }
+    else
+    {
+      hi2c->Mode  = HAL_I2C_MODE_MASTER_SEL;
+    }
+
+    /* Process Unlocked */
+    __HAL_UNLOCK(hi2c);
+
+    return HAL_OK;
+  }
+  else
+  {
+    return HAL_BUSY;
+  }
+}
+
+#endif /* defined(STM32F3) || defined(STM32F7) */
diff --git a/hw/mcu/stm/stm32f1xx/src/hal_i2c.c b/hw/mcu/stm/stm32f1xx/src/hal_i2c.c
index 59dfc14..0d8d8f8 100644
--- a/hw/mcu/stm/stm32f1xx/src/hal_i2c.c
+++ b/hw/mcu/stm/stm32f1xx/src/hal_i2c.c
@@ -76,6 +76,7 @@ hal_i2c_init(uint8_t i2c_num, void *usercfg)
     struct stm32f1_hal_i2c_cfg *cfg = (struct stm32f1_hal_i2c_cfg *)usercfg;
     struct stm32f1_hal_i2c *dev;
     I2C_InitTypeDef *init;
+    GPIO_InitTypeDef gpio;
     int rc;
 
     if (i2c_num >= HAL_I2C_MAX_DEVS || !(dev = hal_i2c_devs[i2c_num])) {
@@ -93,20 +94,35 @@ hal_i2c_init(uint8_t i2c_num, void *usercfg)
     init->OwnAddress1 = I2C_ADDRESS;
     init->OwnAddress2 = 0xFE;
 
+    init->DutyCycle = I2C_DUTYCYCLE_2;
+    init->DualAddressMode = I2C_DUALADDRESS_DISABLE;
+    init->GeneralCallMode = I2C_GENERALCALL_DISABLE;
+    init->NoStretchMode = I2C_NOSTRETCH_DISABLE;
+
     /*
      * Configure GPIO pins for I2C.
      * Enable clock routing for I2C.
      */
-    rc = hal_gpio_init_af(cfg->hic_pin_sda, cfg->hic_pin_af, HAL_GPIO_PULL_UP,
-                          1);
-    if (rc) {
-        goto err;
-    }
-    rc = hal_gpio_init_af(cfg->hic_pin_scl, cfg->hic_pin_af, HAL_GPIO_PULL_UP,
-                          1);
-    if (rc) {
-        goto err;
+    gpio.Speed = GPIO_SPEED_FREQ_HIGH;
+    gpio.Pull = GPIO_NOPULL;
+    gpio.Mode = GPIO_MODE_AF_OD;
+    hal_gpio_init_stm(cfg->hic_pin_scl, &gpio);
+    hal_gpio_init_stm(cfg->hic_pin_sda, &gpio);
+
+#if 0
+    hal_gpio_write(cfg->hic_pin_scl, 0);
+    //for (int i = 0; i < 1000; i++) asm("nop");
+    hal_gpio_write(cfg->hic_pin_scl, 1);
+
+    hal_gpio_write(cfg->hic_pin_sda, 0);
+    //for (int i = 0; i < 1000; i++) asm("nop");
+    hal_gpio_write(cfg->hic_pin_sda, 1);
+#endif
+
+    if (cfg->hic_pin_remap_fn) {
+        cfg->hic_pin_remap_fn();
     }
+
     *cfg->hic_rcc_reg |= cfg->hic_rcc_dev;
     rc = HAL_I2C_Init(&dev->hid_handle);
     if (rc) {

-- 
To stop receiving notification emails like this one, please contact
utzig@apache.org.