mbed

Fork of mbed-dev by mbed official

Revision:
156:95d6b41a828b
Parent:
154:37f96f9d4de2
Child:
157:ff67d9f36b67
--- a/targets/TARGET_STM/i2c_api.c	Thu Jan 05 10:51:54 2017 +0000
+++ b/targets/TARGET_STM/i2c_api.c	Mon Jan 16 15:03:32 2017 +0000
@@ -341,6 +341,9 @@
     // I2C Xfer operation init
     obj_s->event = 0;
     obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
+#ifdef I2C_IP_VERSION_V2
+    obj_s->pending_start = 0;
+#endif
 }
 
 void i2c_frequency(i2c_t *obj, int hz)
@@ -366,22 +369,22 @@
     if (hz == 1000000) {
 #if defined(I2C1_BASE) && defined(__HAL_SYSCFG_FASTMODEPLUS_ENABLE) && defined (I2C_FASTMODEPLUS_I2C1)
         if (obj_s->i2c == I2C_1) {
-            __HAL_SYSCFG_FASTMODEPLUS_ENABLE(I2C_FASTMODEPLUS_I2C1);
+            HAL_I2CEx_EnableFastModePlus(I2C_FASTMODEPLUS_I2C1);
         }
 #endif
 #if defined(I2C2_BASE) && defined(__HAL_SYSCFG_FASTMODEPLUS_ENABLE) && defined (I2C_FASTMODEPLUS_I2C2)
         if (obj_s->i2c == I2C_2) {
-            __HAL_SYSCFG_FASTMODEPLUS_ENABLE(I2C_FASTMODEPLUS_I2C2);
+            HAL_I2CEx_EnableFastModePlus(I2C_FASTMODEPLUS_I2C2);
         }
 #endif
 #if defined(I2C3_BASE) && defined(__HAL_SYSCFG_FASTMODEPLUS_ENABLE) && defined (I2C_FASTMODEPLUS_I2C3)
         if (obj_s->i2c == I2C_3) {
-            __HAL_SYSCFG_FASTMODEPLUS_ENABLE(I2C_FASTMODEPLUS_I2C3);
+            HAL_I2CEx_EnableFastModePlus(I2C_FASTMODEPLUS_I2C3);
         }
 #endif
 #if defined(I2C4_BASE) && defined(__HAL_SYSCFG_FASTMODEPLUS_ENABLE) && defined (I2C_FASTMODEPLUS_I2C4)
         if (obj_s->i2c == I2C_4) {
-            __HAL_SYSCFG_FASTMODEPLUS_ENABLE(I2C_FASTMODEPLUS_I2C4);
+            HAL_I2CEx_EnableFastModePlus(I2C_FASTMODEPLUS_I2C4);
         }
 #endif
     }
@@ -440,6 +443,14 @@
     return (obj);
 }
 
+void i2c_reset(i2c_t *obj) {
+    struct i2c_s *obj_s = I2C_S(obj);
+    /*  As recommended in i2c_api.h, mainly send stop */
+    i2c_stop(obj);
+    /* then re-init */
+    i2c_init(obj, obj_s->sda, obj_s->scl);
+}
+
 /*
  *  UNITARY APIS.
  *  For very basic operations, direct registers access is needed
@@ -535,7 +546,7 @@
             (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BTF) == RESET) &&
              (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET)) {
         if ((timeout--) == 0) {
-            return 0;
+            return 2;
         }
     }
 
@@ -548,92 +559,161 @@
 }
 #endif //I2C_IP_VERSION_V1
 #ifdef I2C_IP_VERSION_V2
+
 int i2c_start(i2c_t *obj) {
     struct i2c_s *obj_s = I2C_S(obj);
-    I2C_HandleTypeDef *handle = &(obj_s->handle);
-    I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
-    int timeout;
-
-    // Clear Acknowledge failure flag
-    __HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_AF);
-
-    // Wait the STOP condition has been previously correctly sent
-    timeout = FLAG_TIMEOUT;
-    while ((i2c->CR2 & I2C_CR2_STOP) == I2C_CR2_STOP){
-        if ((timeout--) == 0) {
-            return 1;
-        }
-    }
-
-    // Generate the START condition
-    i2c->CR2 |= I2C_CR2_START;
-
-    // Wait the START condition has been correctly sent
-    timeout = FLAG_TIMEOUT;
-    while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) == RESET) {
-        if ((timeout--) == 0) {
-            return 1;
-        }
-    }
-
+    /*  This I2C IP doesn't  */
+    obj_s->pending_start = 1;
     return 0;
 }
 
 int i2c_stop(i2c_t *obj) {
     struct i2c_s *obj_s = I2C_S(obj);
-    I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
+    I2C_HandleTypeDef *handle = &(obj_s->handle);
+    int timeout = FLAG_TIMEOUT;
+#if DEVICE_I2CSLAVE
+    if (obj_s->slave) {
+        /*  re-init slave when stop is requested */
+        i2c_init(obj, obj_s->sda, obj_s->scl);
+        return 0;
+    }
+#endif
+    // Disable reload mode
+    handle->Instance->CR2 &= (uint32_t)~I2C_CR2_RELOAD;
+    // Generate the STOP condition
+    handle->Instance->CR2 |= I2C_CR2_STOP;
 
-    // Generate the STOP condition
-    i2c->CR2 |= I2C_CR2_STOP;
+    timeout = FLAG_TIMEOUT;
+    while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_STOPF)) {
+        if ((timeout--) == 0) {
+            return I2C_ERROR_BUS_BUSY;
+        }
+    }
+
+    /* Clear STOP Flag */
+    __HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_STOPF);
+
+    /* Erase slave address, this wiil be used as a marker
+     * to know when we need to prepare next start */
+    handle->Instance->CR2 &=  ~I2C_CR2_SADD;
+
+    /*  In case of mixed usage of the APIs (unitary + SYNC)
+     *  re-inti HAL state */
+    if (obj_s->XferOperation != I2C_FIRST_AND_LAST_FRAME) {
+        i2c_init(obj, obj_s->sda, obj_s->scl);
+    }
 
     return 0;
 }
 
 int i2c_byte_read(i2c_t *obj, int last) {
     struct i2c_s *obj_s = I2C_S(obj);
-    I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
     I2C_HandleTypeDef *handle = &(obj_s->handle);
-    int timeout;
+    int timeout = FLAG_TIMEOUT;
+    uint32_t tmpreg = handle->Instance->CR2;
+    char data;
+#if DEVICE_I2CSLAVE
+    if (obj_s->slave) {
+        return i2c_slave_read(obj, &data, 1);
+    }
+#endif
+    /* Then send data when there's room in the TX fifo */
+    if ((tmpreg & I2C_CR2_RELOAD) != 0) {
+        while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TCR)) {
+            if ((timeout--) == 0) {
+                DEBUG_PRINTF("timeout in byte_read\r\n");
+                return -1;
+            }
+        }
+    }
 
-    // Wait until the byte is received
+    /*  Enable reload mode as we don't know how many bytes will eb sent */
+    handle->Instance->CR2 |= I2C_CR2_RELOAD;
+    /*  Set transfer size to 1 */
+    handle->Instance->CR2 |= (I2C_CR2_NBYTES & (1 << 16));
+    /* Set the prepared configuration */
+    handle->Instance->CR2 = tmpreg;
+
     timeout = FLAG_TIMEOUT;
-    while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_RXNE) == RESET) {
+    while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_RXNE)) {
         if ((timeout--) == 0) {
             return -1;
         }
     }
 
-    return (int)i2c->RXDR;
+    /* Then Get Byte */
+    data = handle->Instance->RXDR;
+
+    if (last) {
+        /* Disable Address Acknowledge */
+        handle->Instance->CR2 |= I2C_CR2_NACK;
+    }
+
+    return data;
 }
 
 int i2c_byte_write(i2c_t *obj, int data) {
     struct i2c_s *obj_s = I2C_S(obj);
-    I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
     I2C_HandleTypeDef *handle = &(obj_s->handle);
-    int timeout;
+    int timeout = FLAG_TIMEOUT;
+    uint32_t tmpreg = handle->Instance->CR2;
+#if DEVICE_I2CSLAVE
+    if (obj_s->slave) {
+        return i2c_slave_write(obj, (char *) &data, 1);
+    }
+#endif
+    if (obj_s->pending_start) {
+        obj_s->pending_start = 0;
+        //*  First byte after the start is the address */
+        tmpreg |= (uint32_t)((uint32_t)data & I2C_CR2_SADD);
+        if (data & 0x01) {
+             tmpreg |= I2C_CR2_START | I2C_CR2_RD_WRN;
+        } else {
+             tmpreg |= I2C_CR2_START;
+             tmpreg &= ~I2C_CR2_RD_WRN;
+        }
+        /*  Disable reload first to use it later */
+        tmpreg &= ~I2C_CR2_RELOAD;
+        /*  Disable Autoend */
+        tmpreg &= ~I2C_CR2_AUTOEND;
+        /* Do not set any transfer size for now */
+        tmpreg |= (I2C_CR2_NBYTES & (1 << 16));
+        /* Set the prepared configuration */
+        handle->Instance->CR2 = tmpreg;
+    } else {
+        /* Set the prepared configuration */
+        tmpreg = handle->Instance->CR2;
 
-    // Wait until the previous byte is transmitted
-    timeout = FLAG_TIMEOUT;
-    while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXIS) == RESET) {
-        if ((timeout--) == 0) {
-            return 0;
+        /* Then send data when there's room in the TX fifo */
+        if ((tmpreg & I2C_CR2_RELOAD) != 0) {
+            while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TCR)) {
+                if ((timeout--) == 0) {
+                    DEBUG_PRINTF("timeout in byte_write\r\n");
+                    return 2;
+                }
+            }
         }
+        /*  Enable reload mode as we don't know how many bytes will eb sent */
+        tmpreg |= I2C_CR2_RELOAD;
+         /*  Set transfer size to 1 */
+        tmpreg |= (I2C_CR2_NBYTES & (1 << 16));
+       /* Set the prepared configuration */
+        handle->Instance->CR2 = tmpreg;
+        /*  Prepare next write */
+        timeout = FLAG_TIMEOUT;
+        while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE)) {
+            if ((timeout--) == 0) {
+                return 2;
+            }
+        }
+        /*  Write byte */
+        handle->Instance->TXDR = data;
     }
 
-    i2c->TXDR = (uint8_t)data;
-
     return 1;
 }
 #endif //I2C_IP_VERSION_V2
 
-void i2c_reset(i2c_t *obj) {
-    struct i2c_s *obj_s = I2C_S(obj);
-    /*  As recommended in i2c_api.h, mainly send stop */
-    i2c_stop(obj);
-    /* then re-init */
-    i2c_init(obj, obj_s->sda, obj_s->scl);
-}
-
 /*
  *  SYNC APIS
  */