From c0ca0a7e2cfce7ae7f0da145e00c9b28e4581adf Mon Sep 17 00:00:00 2001 From: Laurent MEUNIER Date: Thu, 8 Dec 2016 09:48:07 +0100 Subject: [PATCH 1/4] STM I2C - move i2c_read in SYNC part just change the place of code to have i2c_read and i2c_write together --- targets/TARGET_STM/i2c_api.c | 106 +++++++++++++++++------------------ 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/targets/TARGET_STM/i2c_api.c b/targets/TARGET_STM/i2c_api.c index a87db03ff0..235c965985 100644 --- a/targets/TARGET_STM/i2c_api.c +++ b/targets/TARGET_STM/i2c_api.c @@ -442,60 +442,6 @@ i2c_t *get_i2c_obj(I2C_HandleTypeDef *hi2c){ return (obj); } -/* SYNCHRONOUS API FUNCTIONS */ - -int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { - struct i2c_s *obj_s = I2C_S(obj); - I2C_HandleTypeDef *handle = &(obj_s->handle); - int count = 0, ret = 0; - uint32_t timeout = 0; - - if ((obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) || - (obj_s->XferOperation == I2C_LAST_FRAME)) { - if (stop) - obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME; - else - obj_s->XferOperation = I2C_FIRST_FRAME; - } else if ((obj_s->XferOperation == I2C_FIRST_FRAME) || - (obj_s->XferOperation == I2C_NEXT_FRAME)) { - if (stop) - obj_s->XferOperation = I2C_LAST_FRAME; - else - obj_s->XferOperation = I2C_NEXT_FRAME; - } - - obj_s->event = 0; - - /* Activate default IRQ handlers for sync mode - * which would be overwritten in async mode - */ - i2c_ev_err_enable(obj, i2c_get_irq_handler(obj)); - - ret = HAL_I2C_Master_Sequential_Receive_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation); - - if(ret == HAL_OK) { - timeout = BYTE_TIMEOUT_US * length; - /* transfer started : wait completion or timeout */ - while(!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) { - wait_us(1); - } - - i2c_ev_err_disable(obj); - - if((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) { - DEBUG_PRINTF(" TIMEOUT or error in i2c_read\r\n"); - /* re-init IP to try and get back in a working state */ - i2c_init(obj, obj_s->sda, obj_s->scl); - } else { - count = length; - } - } else { - DEBUG_PRINTF("ERROR in i2c_read\r\n"); - } - - return count; -} - /* * UNITARY APIS. * For very basic operations, direct registers access is needed @@ -685,6 +631,58 @@ void i2c_reset(i2c_t *obj) { /* * SYNC APIS */ +int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { + struct i2c_s *obj_s = I2C_S(obj); + I2C_HandleTypeDef *handle = &(obj_s->handle); + int count = 0, ret = 0; + uint32_t timeout = 0; + + if ((obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) || + (obj_s->XferOperation == I2C_LAST_FRAME)) { + if (stop) + obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME; + else + obj_s->XferOperation = I2C_FIRST_FRAME; + } else if ((obj_s->XferOperation == I2C_FIRST_FRAME) || + (obj_s->XferOperation == I2C_NEXT_FRAME)) { + if (stop) + obj_s->XferOperation = I2C_LAST_FRAME; + else + obj_s->XferOperation = I2C_NEXT_FRAME; + } + + obj_s->event = 0; + + /* Activate default IRQ handlers for sync mode + * which would be overwritten in async mode + */ + i2c_ev_err_enable(obj, i2c_get_irq_handler(obj)); + + ret = HAL_I2C_Master_Sequential_Receive_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation); + + if(ret == HAL_OK) { + timeout = BYTE_TIMEOUT_US * length; + /* transfer started : wait completion or timeout */ + while(!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) { + wait_us(1); + } + + i2c_ev_err_disable(obj); + + if((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) { + DEBUG_PRINTF(" TIMEOUT or error in i2c_read\r\n"); + /* re-init IP to try and get back in a working state */ + i2c_init(obj, obj_s->sda, obj_s->scl); + } else { + count = length; + } + } else { + DEBUG_PRINTF("ERROR in i2c_read:%d\r\n", ret); + } + + return count; +} + int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); From 37c94a03f0b9b4d6e9b56465e48036ba6a9894a8 Mon Sep 17 00:00:00 2001 From: Laurent MEUNIER Date: Mon, 12 Dec 2016 11:42:14 +0100 Subject: [PATCH 2/4] STM I2C: manage Is Device Ready case Some device drivers use a data lenght of 0 to check if device is ready. STM32 HAL provides a dedicated service for that, so let's use it. --- targets/TARGET_STM/i2c_api.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/targets/TARGET_STM/i2c_api.c b/targets/TARGET_STM/i2c_api.c index 235c965985..34d67b197c 100644 --- a/targets/TARGET_STM/i2c_api.c +++ b/targets/TARGET_STM/i2c_api.c @@ -634,9 +634,16 @@ void i2c_reset(i2c_t *obj) { int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); - int count = 0, ret = 0; + int count = I2C_ERROR_BUS_BUSY, ret = 0; uint32_t timeout = 0; + if((length == 0) || (data == 0)) { + if(HAL_I2C_IsDeviceReady(handle, address, 1, 10) == HAL_OK) + return 0; + else + return I2C_ERROR_BUS_BUSY; + } + if ((obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) || (obj_s->XferOperation == I2C_LAST_FRAME)) { if (stop) @@ -686,9 +693,16 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { struct i2c_s *obj_s = I2C_S(obj); I2C_HandleTypeDef *handle = &(obj_s->handle); - int count = 0, ret = 0; + int count = I2C_ERROR_BUS_BUSY, ret = 0; uint32_t timeout = 0; + if((length == 0) || (data == 0)) { + if(HAL_I2C_IsDeviceReady(handle, address, 1, 10) == HAL_OK) + return 0; + else + return I2C_ERROR_BUS_BUSY; + } + if ((obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) || (obj_s->XferOperation == I2C_LAST_FRAME)) { if (stop) From 8406a99dc86351ed2ad127861a221a2985aad760 Mon Sep 17 00:00:00 2001 From: Laurent MEUNIER Date: Mon, 12 Dec 2016 14:03:42 +0100 Subject: [PATCH 3/4] STM32 I2C: avoid timeout to be 0 In continuation of previous IsDeviceReady case, let's add 1 in case length is 0 (even though not recommended) --- targets/TARGET_STM/i2c_api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/targets/TARGET_STM/i2c_api.c b/targets/TARGET_STM/i2c_api.c index 34d67b197c..a7a09d489d 100644 --- a/targets/TARGET_STM/i2c_api.c +++ b/targets/TARGET_STM/i2c_api.c @@ -668,7 +668,7 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { ret = HAL_I2C_Master_Sequential_Receive_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation); if(ret == HAL_OK) { - timeout = BYTE_TIMEOUT_US * length; + timeout = BYTE_TIMEOUT_US * (length + 1); /* transfer started : wait completion or timeout */ while(!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) { wait_us(1); @@ -724,7 +724,7 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { ret = HAL_I2C_Master_Sequential_Transmit_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation); if(ret == HAL_OK) { - timeout = BYTE_TIMEOUT_US * length; + timeout = BYTE_TIMEOUT_US * (length + 1); /* transfer started : wait completion or timeout */ while(!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) { wait_us(1); @@ -903,7 +903,7 @@ int i2c_slave_read(i2c_t *obj, char *data, int length) { ret = HAL_I2C_Slave_Sequential_Receive_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME); if(ret == HAL_OK) { - timeout = BYTE_TIMEOUT_US * length; + timeout = BYTE_TIMEOUT_US * (length + 1); while(obj_s->pending_slave_rx_maxter_tx && (--timeout != 0)) { wait_us(1); } @@ -928,7 +928,7 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length) { ret = HAL_I2C_Slave_Sequential_Transmit_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME); if(ret == HAL_OK) { - timeout = BYTE_TIMEOUT_US * length; + timeout = BYTE_TIMEOUT_US * (length + 1); while(obj_s->pending_slave_tx_master_rx && (--timeout != 0)) { wait_us(1); } From 580d96431e0b093b009bf25c6ec932cf7be1862f Mon Sep 17 00:00:00 2001 From: Laurent MEUNIER Date: Mon, 12 Dec 2016 11:44:12 +0100 Subject: [PATCH 4/4] STM32 I2C manage STOP specific case In case the user applicaiton makes a mixed usage of unitary function (start, stop, byte write & read) with SYNC operation (write and read of data buffers with start and stop management), we need to reset the STM32 HAL state as it is by-passed by a direct call to STOP --- targets/TARGET_STM/i2c_api.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/targets/TARGET_STM/i2c_api.c b/targets/TARGET_STM/i2c_api.c index a7a09d489d..9baa1be6b7 100644 --- a/targets/TARGET_STM/i2c_api.c +++ b/targets/TARGET_STM/i2c_api.c @@ -483,10 +483,18 @@ int i2c_start(i2c_t *obj) { 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; // Generate the STOP condition i2c->CR1 |= I2C_CR1_STOP; + /* 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; }