Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-dev by
Diff: targets/TARGET_STM/i2c_api.c
- Revision:
- 156:95d6b41a828b
- Parent:
- 154:37f96f9d4de2
- Child:
- 157:ff67d9f36b67
diff -r 88546b34ff1c -r 95d6b41a828b targets/TARGET_STM/i2c_api.c --- 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 */