mbed
Fork of mbed-dev by
Diff: targets/TARGET_STM/i2c_api.c
- 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 */