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/TARGET_STM32F4/i2c_api.c
- Revision:
- 151:5eaa88a5bcc7
- Parent:
- 149:156823d33999
diff -r 02e0a0aed4ec -r 5eaa88a5bcc7 targets/TARGET_STM/TARGET_STM32F4/i2c_api.c
--- a/targets/TARGET_STM/TARGET_STM32F4/i2c_api.c Tue Nov 08 17:45:16 2016 +0000
+++ b/targets/TARGET_STM/TARGET_STM32F4/i2c_api.c Thu Nov 24 17:03:03 2016 +0000
@@ -29,6 +29,7 @@
*/
#include "mbed_assert.h"
#include "i2c_api.h"
+#include "platform/wait_api.h"
#if DEVICE_I2C
@@ -36,16 +37,29 @@
#include "pinmap.h"
#include "PeripheralPins.h"
-/* Timeout values for flags and events waiting loops. These timeouts are
- not based on accurate values, they just guarantee that the application will
- not remain stuck if the I2C communication is corrupted. */
-#define FLAG_TIMEOUT ((int)0x1000)
-#define LONG_TIMEOUT ((int)0x8000)
+#ifndef DEBUG_STDIO
+# define DEBUG_STDIO 0
+#endif
+
+#if DEBUG_STDIO
+# include <stdio.h>
+# define DEBUG_PRINTF(...) do { printf(__VA_ARGS__); } while(0)
+#else
+# define DEBUG_PRINTF(...) {}
+#endif
-int i2c1_inited = 0;
-int i2c2_inited = 0;
-int i2c3_inited = 0;
-int fmpi2c1_inited = 0;
+/* Timeout values are based on core clock and I2C clock.
+ The BYTE_TIMEOUT is computed as twice the number of cycles it would
+ take to send 10 bits over I2C. Most Flags should take less than that.
+ This is for immediate FLAG or ACK check.
+*/
+#define BYTE_TIMEOUT ((SystemCoreClock / handle->Init.ClockSpeed) * 2 * 10)
+/* Timeout values based on I2C clock.
+ The BYTE_TIMEOUT_US is computed as 3x the time in us it would
+ take to send 10 bits over I2C. Most Flags should take less than that.
+ This is for complete transfers check.
+*/
+#define BYTE_TIMEOUT_US ((SystemCoreClock / handle->Init.ClockSpeed) * 3 * 10)
#if DEVICE_I2C_ASYNCH
#define I2C_S(obj) (struct i2c_s *) (&((obj)->i2c))
@@ -53,6 +67,111 @@
#define I2C_S(obj) (struct i2c_s *) (obj)
#endif
+/* could be defined at family level */
+#define I2C_NUM (5)
+static I2C_HandleTypeDef* i2c_handles[I2C_NUM];
+
+static void i2c1_irq(void)
+{
+ I2C_HandleTypeDef * handle = i2c_handles[0];
+ HAL_I2C_EV_IRQHandler(handle);
+ HAL_I2C_ER_IRQHandler(handle);
+}
+
+static void i2c2_irq(void)
+{
+ I2C_HandleTypeDef * handle = i2c_handles[1];
+ HAL_I2C_EV_IRQHandler(handle);
+ HAL_I2C_ER_IRQHandler(handle);
+}
+
+#if defined(I2C3_BASE)
+static void i2c3_irq(void)
+{
+ I2C_HandleTypeDef * handle = i2c_handles[2];
+ HAL_I2C_EV_IRQHandler(handle);
+ HAL_I2C_ER_IRQHandler(handle);
+}
+#endif
+#if defined(I2C4_BASE)
+ static void i2c4_irq(void)
+ {
+ I2C_HandleTypeDef * handle = i2c_handles[3];
+ HAL_I2C_EV_IRQHandler(handle);
+ HAL_I2C_ER_IRQHandler(handle);
+ }
+#endif
+#if defined(FMPI2C1_BASE)
+static void i2c5_irq(void)
+{
+ I2C_HandleTypeDef * handle = i2c_handles[4];
+ HAL_I2C_EV_IRQHandler(handle);
+ HAL_I2C_ER_IRQHandler(handle);
+}
+#endif
+
+void i2c_ev_err_enable(i2c_t *obj, uint32_t handler) {
+ struct i2c_s *obj_s = I2C_S(obj);
+ IRQn_Type irq_event_n = obj_s->event_i2cIRQ;
+ IRQn_Type irq_error_n = obj_s->error_i2cIRQ;
+
+ /* Set up event IT using IRQ and handler tables */
+ NVIC_SetVector(irq_event_n, handler);
+ HAL_NVIC_SetPriority(irq_event_n, 0, 0);
+ HAL_NVIC_EnableIRQ(irq_event_n);
+ /* Set up error IT using IRQ and handler tables */
+ NVIC_SetVector(irq_error_n, handler);
+ HAL_NVIC_SetPriority(irq_error_n, 0, 1);
+ HAL_NVIC_EnableIRQ(irq_error_n);
+}
+
+void i2c_ev_err_disable(i2c_t *obj) {
+ struct i2c_s *obj_s = I2C_S(obj);
+ IRQn_Type irq_event_n = obj_s->event_i2cIRQ;
+ IRQn_Type irq_error_n = obj_s->error_i2cIRQ;
+
+ HAL_NVIC_DisableIRQ(irq_event_n);
+ HAL_NVIC_DisableIRQ(irq_error_n);
+}
+
+void i2c_irq_set(i2c_t *obj, uint32_t enable)
+{
+ struct i2c_s *obj_s = I2C_S(obj);
+ I2C_HandleTypeDef *handle = &(obj_s->handle);
+ uint32_t handler = 0;
+
+ switch (obj_s->index) {
+ case 0:
+ handler = (uint32_t)&i2c1_irq;
+ break;
+ case 1:
+ handler = (uint32_t)&i2c2_irq;
+ break;
+#if defined(I2C3_BASE)
+ case 2:
+ handler = (uint32_t)&i2c3_irq;
+ break;
+#endif
+#if defined(I2C4_BASE)
+ case 3:
+ handler = (uint32_t)&i2c4_irq;
+ break;
+#endif
+#if defined(FMPI2C1_BASE)
+ case 4:
+ handler = (uint32_t)&i2c5_irq;
+ break;
+#endif
+ }
+
+ if (enable) {
+ i2c_handles[obj_s->index] = handle;
+ i2c_ev_err_enable(obj, handler);
+ } else { // disable
+ i2c_ev_err_disable(obj);
+ i2c_handles[obj_s->index] = 0;
+ }
+}
void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
@@ -61,68 +180,75 @@
// Determine the I2C to use
I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
+ obj_s->sda = sda;
+ obj_s->scl = scl;
obj_s->i2c = (I2CName)pinmap_merge(i2c_sda, i2c_scl);
MBED_ASSERT(obj_s->i2c != (I2CName)NC);
// Enable I2C1 clock and pinout if not done
- if ((obj_s->i2c == I2C_1) && !i2c1_inited) {
- i2c1_inited = 1;
+ if (obj_s->i2c == I2C_1) {
+ obj_s->index = 0;
// Configure I2C pins
pinmap_pinout(sda, PinMap_I2C_SDA);
pinmap_pinout(scl, PinMap_I2C_SCL);
pin_mode(sda, PullUp);
pin_mode(scl, PullUp);
-#if DEVICE_I2C_ASYNCH
obj_s->event_i2cIRQ = I2C1_EV_IRQn;
obj_s->error_i2cIRQ = I2C1_ER_IRQn;
-#endif
__I2C1_CLK_ENABLE();
}
// Enable I2C2 clock and pinout if not done
- if ((obj_s->i2c == I2C_2) && !i2c2_inited) {
- i2c2_inited = 1;
+ if (obj_s->i2c == I2C_2) {
+ obj_s->index = 1;
// Configure I2C pins
pinmap_pinout(sda, PinMap_I2C_SDA);
pinmap_pinout(scl, PinMap_I2C_SCL);
pin_mode(sda, PullUp);
pin_mode(scl, PullUp);
-#if DEVICE_I2C_ASYNCH
obj_s->event_i2cIRQ = I2C2_EV_IRQn;
obj_s->error_i2cIRQ = I2C2_ER_IRQn;
-#endif
__I2C2_CLK_ENABLE();
}
#if defined I2C3_BASE
// Enable I2C3 clock and pinout if not done
- if ((obj_s->i2c == I2C_3) && !i2c3_inited) {
- i2c3_inited = 1;
+ if (obj_s->i2c == I2C_3) {
+ obj_s->index = 2;
// Configure I2C pins
pinmap_pinout(sda, PinMap_I2C_SDA);
pinmap_pinout(scl, PinMap_I2C_SCL);
pin_mode(sda, PullUp);
pin_mode(scl, PullUp);
-#if DEVICE_I2C_ASYNCH
obj_s->event_i2cIRQ = I2C3_EV_IRQn;
obj_s->error_i2cIRQ = I2C3_ER_IRQn;
-#endif
__I2C3_CLK_ENABLE();
}
#endif
-
-#if defined FMPI2C1_BASE
- // Enable I2C3 clock and pinout if not done
- if ((obj_s->i2c == FMPI2C_1) && !fmpi2c1_inited) {
- fmpi2c1_inited = 1;
+#if defined I2C4_BASE
+ // Enable clock and pinout if not done
+ if (obj_s->i2c == I2C_4) {
+ obj_s->index = 3;
// Configure I2C pins
pinmap_pinout(sda, PinMap_I2C_SDA);
pinmap_pinout(scl, PinMap_I2C_SCL);
pin_mode(sda, PullUp);
pin_mode(scl, PullUp);
-#if DEVICE_I2C_ASYNCH
+ obj_s->event_i2cIRQ = I2C4_EV_IRQn;
+ obj_s->error_i2cIRQ = I2C4_ER_IRQn;
+ __I2C4_CLK_ENABLE();
+ }
+#endif
+#if defined FMPI2C1_BASE
+ // Enable clock and pinout if not done
+ if (obj_s->i2c == FMPI2C_1) {
+ obj_s->index = 3;
+ // Configure I2C pins
+ pinmap_pinout(sda, PinMap_I2C_SDA);
+ pinmap_pinout(scl, PinMap_I2C_SCL);
+ pin_mode(sda, PullUp);
+ pin_mode(scl, PullUp);
obj_s->event_i2cIRQ = FMPI2C1_EV_IRQn;
obj_s->error_i2cIRQ = FMPI2C1_ER_IRQn;
-#endif
__HAL_RCC_FMPI2C1_CLK_ENABLE();
}
#endif
@@ -136,12 +262,18 @@
#if DEVICE_I2CSLAVE
// I2C master by default
obj_s->slave = 0;
+ obj_s->pending_slave_tx_master_rx = 0;
+ obj_s->pending_slave_rx_maxter_tx = 0;
#endif
-#if DEVICE_I2C_ASYNCH
// I2C Xfer operation init
+ obj_s->event = 0;
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
-#endif
+
+ /* Activate default IRQ handlers for sync mode
+ * which would be overwritten in async mode
+ */
+ i2c_irq_set(obj, 1);
}
void i2c_frequency(i2c_t *obj, int hz)
@@ -154,8 +286,8 @@
MBED_ASSERT((hz > 0) && (hz <= 400000));
// wait before init
- timeout = LONG_TIMEOUT;
- while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (timeout-- != 0));
+ timeout = BYTE_TIMEOUT;
+ while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (--timeout != 0));
// I2C configuration
handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
@@ -168,13 +300,20 @@
handle->Init.OwnAddress2 = 0;
HAL_I2C_Init(handle);
-#if DEVICE_I2CSLAVE
- if (obj_s->slave) {
- /* Enable Address Acknowledge */
- handle->Instance->CR1 |= I2C_CR1_ACK;
- }
-#endif
+}
+
+i2c_t *get_i2c_obj(I2C_HandleTypeDef *hi2c){
+ /* Aim of the function is to get i2c_s pointer using hi2c pointer */
+ /* Highly inspired from magical linux kernel's "container_of" */
+ /* (which was not directly used since not compatible with IAR toolchain) */
+ struct i2c_s *obj_s;
+ i2c_t *obj;
+
+ obj_s = (struct i2c_s *)( (char *)hi2c - offsetof(struct i2c_s,handle));
+ obj = (i2c_t *)( (char *)obj_s - offsetof(i2c_t,i2c));
+
+ return (obj);
}
inline int i2c_start(i2c_t *obj) {
@@ -188,7 +327,7 @@
// Wait the STOP condition has been previously correctly sent
// This timeout can be avoid in some specific cases by simply clearing the STOP bit
- timeout = FLAG_TIMEOUT;
+ timeout = BYTE_TIMEOUT;
while ((handle->Instance->CR1 & I2C_CR1_STOP) == I2C_CR1_STOP) {
if ((timeout--) == 0) {
return 1;
@@ -199,7 +338,7 @@
handle->Instance->CR1 |= I2C_CR1_START;
// Wait the START condition has been correctly sent
- timeout = FLAG_TIMEOUT;
+ timeout = BYTE_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
if ((timeout--) == 0) {
return 1;
@@ -220,95 +359,89 @@
}
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
-
- int timeout;
- int count;
- int value;
struct i2c_s *obj_s = I2C_S(obj);
I2C_HandleTypeDef *handle = &(obj_s->handle);
-
- i2c_start(obj);
+ int count = 0, ret = 0;
+ uint32_t timeout = 0;
- // Wait until SB flag is set
- timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
- timeout--;
- if (timeout == 0) {
- return -1;
- }
+ 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;
}
- handle->Instance->DR = __HAL_I2C_7BIT_ADD_READ(address);
+ obj_s->event = 0;
+ 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);
+ }
- // Wait address is acknowledged
- timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET) {
- timeout--;
- if (timeout == 0) {
- return -1;
+ 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;
}
- }
- __HAL_I2C_CLEAR_ADDRFLAG(handle);
-
- // Read all bytes except last one
- for (count = 0; count < (length - 1); count++) {
- value = i2c_byte_read(obj, 0);
- data[count] = (char)value;
+ } else {
+ DEBUG_PRINTF("ERROR in i2c_read\r\n");
}
- // If not repeated start, send stop.
- // Warning: must be done BEFORE the data is read.
- if (stop) {
- i2c_stop(obj);
- }
-
- // Read the last byte
- value = i2c_byte_read(obj, 1);
- data[count] = (char)value;
-
- return length;
+ return count;
}
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
-
- int timeout;
- int count;
struct i2c_s *obj_s = I2C_S(obj);
I2C_HandleTypeDef *handle = &(obj_s->handle);
-
- i2c_start(obj);
+ int count = 0, ret = 0;
+ uint32_t timeout = 0;
- // Wait until SB flag is set
- timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
- timeout--;
- if (timeout == 0) {
- return -1;
- }
+ 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;
}
- handle->Instance->DR = __HAL_I2C_7BIT_ADD_WRITE(address);
+ obj_s->event = 0;
+
+ ret = HAL_I2C_Master_Sequential_Transmit_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation);
- // Wait address is acknowledged
- timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET) {
- timeout--;
- if (timeout == 0) {
- return -1;
+ 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);
}
- }
- __HAL_I2C_CLEAR_ADDRFLAG(handle);
- for (count = 0; count < length; count++) {
- if (i2c_byte_write(obj, data[count]) != 1) {
- i2c_stop(obj);
- return -1;
- }
- }
-
- // If not repeated start, send stop.
- if (stop) {
- i2c_stop(obj);
+ if((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
+ DEBUG_PRINTF(" TIMEOUT or error in i2c_write\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;
@@ -329,7 +462,7 @@
}
// Wait until the byte is received
- timeout = FLAG_TIMEOUT;
+ timeout = BYTE_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_RXNE) == RESET) {
if ((timeout--) == 0) {
return -1;
@@ -348,7 +481,7 @@
handle->Instance->DR = (uint8_t)data;
// Wait until the byte (might be the address) is transmitted
- timeout = FLAG_TIMEOUT;
+ timeout = BYTE_TIMEOUT;
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE) == RESET) &&
(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BTF) == RESET) &&
(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET)) {
@@ -374,8 +507,8 @@
handle->Instance = (I2C_TypeDef *)(obj_s->i2c);
// wait before reset
- timeout = LONG_TIMEOUT;
- while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (timeout-- != 0));
+ timeout = BYTE_TIMEOUT;
+ while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (--timeout != 0));
if (obj_s->i2c == I2C_1) {
__I2C1_FORCE_RESET();
@@ -392,7 +525,12 @@
__I2C3_RELEASE_RESET();
}
#endif
-
+#if defined I2C4_BASE
+ if (obj_s->i2c == I2C_4) {
+ __I2C4_FORCE_RESET();
+ __I2C4_RELEASE_RESET();
+ }
+#endif
#if defined FMPI2C1_BASE
if (obj_s->i2c == FMPI2C_1) {
__HAL_RCC_FMPI2C1_FORCE_RESET();
@@ -404,31 +542,27 @@
#if DEVICE_I2CSLAVE
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
-
- uint16_t tmpreg = 0;
struct i2c_s *obj_s = I2C_S(obj);
- I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
+ I2C_HandleTypeDef *handle = &(obj_s->handle);
- // Get the old register value
- tmpreg = i2c->OAR1;
- // Reset address bits
- tmpreg &= 0xFC00;
- // Set new address
- tmpreg |= (uint16_t)((uint16_t)address & (uint16_t)0x00FE); // 7-bits
- // Store the new register value
- i2c->OAR1 = tmpreg;
+ // I2C configuration
+ handle->Init.OwnAddress1 = address;
+ HAL_I2C_Init(handle);
+
+ HAL_I2C_EnableListen_IT(handle);
}
void i2c_slave_mode(i2c_t *obj, int enable_slave) {
struct i2c_s *obj_s = I2C_S(obj);
- I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
+ I2C_HandleTypeDef *handle = &(obj_s->handle);
if (enable_slave) {
obj_s->slave = 1;
-
- /* Enable Address Acknowledge */
- i2c->CR1 |= I2C_CR1_ACK;
+ HAL_I2C_EnableListen_IT(handle);
+ } else {
+ obj_s->slave = 0;
+ HAL_I2C_DisableListen_IT(handle);
}
}
@@ -438,184 +572,131 @@
#define WriteGeneral 2 // the master is writing to all slave
#define WriteAddressed 3 // the master is writing to this slave (slave = receiver)
+
+void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) {
+ /* Get object ptr based on handler ptr */
+ i2c_t *obj = get_i2c_obj(hi2c);
+ struct i2c_s *obj_s = I2C_S(obj);
+
+ /* Transfer direction in HAL is from Master point of view */
+ if(TransferDirection == I2C_DIRECTION_RECEIVE) {
+ obj_s->pending_slave_tx_master_rx = 1;
+ }
+
+ if(TransferDirection == I2C_DIRECTION_TRANSMIT) {
+ obj_s->pending_slave_rx_maxter_tx = 1;
+ }
+}
+
+void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *I2cHandle){
+ /* Get object ptr based on handler ptr */
+ i2c_t *obj = get_i2c_obj(I2cHandle);
+ struct i2c_s *obj_s = I2C_S(obj);
+ obj_s->pending_slave_tx_master_rx = 0;
+}
+
+void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2cHandle){
+ /* Get object ptr based on handler ptr */
+ i2c_t *obj = get_i2c_obj(I2cHandle);
+ struct i2c_s *obj_s = I2C_S(obj);
+ obj_s->pending_slave_rx_maxter_tx = 0;
+}
+
+void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
+{
+ /* restart listening for master requests */
+ HAL_I2C_EnableListen_IT(hi2c);
+}
+
int i2c_slave_receive(i2c_t *obj) {
struct i2c_s *obj_s = I2C_S(obj);
- I2C_HandleTypeDef *handle = &(obj_s->handle);
-
int retValue = NoData;
- /* Reading BUSY flag before ADDR flag could clear ADDR */
- int addr = __HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR);
+ if(obj_s->pending_slave_rx_maxter_tx) {
+ retValue = WriteAddressed;
+ }
- if (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) == 1) {
- if (addr == 1) {
- if (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TRA) == 1) {
- retValue = ReadAddressed;
- } else {
- retValue = WriteAddressed;
- }
- __HAL_I2C_CLEAR_ADDRFLAG(handle);
- }
- }
+ if(obj_s->pending_slave_tx_master_rx) {
+ retValue = ReadAddressed;
+ }
return (retValue);
}
int i2c_slave_read(i2c_t *obj, char *data, int length) {
-
struct i2c_s *obj_s = I2C_S(obj);
I2C_HandleTypeDef *handle = &(obj_s->handle);
-
- uint32_t Timeout;
- int size = 0;
-
- while (length > 0) {
+ int count = 0;
+ int ret = 0;
+ uint32_t timeout = 0;
- /* Wait until RXNE flag is set */
- // Wait until the byte is received
- Timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_RXNE) == RESET) {
- Timeout--;
- if (Timeout == 0) {
- return -1;
- }
+ /* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */
+ ret = HAL_I2C_Slave_Sequential_Receive_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME);
+
+ if(ret == HAL_OK) {
+ timeout = BYTE_TIMEOUT_US * length;
+ while(obj_s->pending_slave_rx_maxter_tx && (--timeout != 0)) {
+ wait_us(1);
}
- /* Read data from DR */
- (*data++) = handle->Instance->DR;
- length--;
- size++;
-
- if ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BTF) == SET) && (length != 0)) {
- /* Read data from DR */
- (*data++) = handle->Instance->DR;
- length--;
- size++;
- }
+ if(timeout != 0) {
+ count = length;
+ } else {
+ DEBUG_PRINTF("TIMEOUT or error in i2c_slave_read\r\n");
+ }
}
- /* Wait until STOP flag is set */
- Timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_STOPF) == RESET) {
- Timeout--;
- if (Timeout == 0) {
- return -1;
- }
- }
-
- /* Clear STOP flag */
- __HAL_I2C_CLEAR_STOPFLAG(handle);
-
- /* Wait until BUSY flag is reset */
- Timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) == SET) {
- Timeout--;
- if (Timeout == 0) {
- return -1;
- }
- }
-
- return size;
+ return count;
}
int i2c_slave_write(i2c_t *obj, const char *data, int length) {
-
- uint32_t Timeout;
- int size = 0;
struct i2c_s *obj_s = I2C_S(obj);
I2C_HandleTypeDef *handle = &(obj_s->handle);
+ int count = 0;
+ int ret = 0;
+ uint32_t timeout = 0;
- while (length > 0) {
- /* Wait until TXE flag is set */
- Timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE) == RESET) {
- Timeout--;
- if (Timeout == 0) {
- return -1;
- }
+ /* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */
+ ret = HAL_I2C_Slave_Sequential_Transmit_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME);
+
+ if(ret == HAL_OK) {
+ timeout = BYTE_TIMEOUT_US * length;
+ while(obj_s->pending_slave_tx_master_rx && (--timeout != 0)) {
+ wait_us(1);
}
- /* Write data to DR */
- handle->Instance->DR = (*data++);
- length--;
- size++;
-
- if ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BTF) == SET) && (length != 0)) {
- /* Write data to DR */
- handle->Instance->DR = (*data++);
- length--;
- size++;
- }
+ if(timeout != 0) {
+ count = length;
+ } else {
+ DEBUG_PRINTF("TIMEOUT or error in i2c_slave_write\r\n");
+ }
}
- /* Wait until AF flag is set */
- Timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_AF) == RESET) {
- Timeout--;
- if (Timeout == 0) {
- return -1;
- }
- }
-
- /* Clear AF flag */
- __HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_AF);
-
-
- /* Wait until BUSY flag is reset */
- Timeout = FLAG_TIMEOUT;
- while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) == SET) {
- Timeout--;
- if (Timeout == 0) {
- return -1;
- }
- }
-
- handle->State = HAL_I2C_STATE_READY;
-
- /* Process Unlocked */
- __HAL_UNLOCK(handle);
-
- return size;
+ return count;
}
#endif // DEVICE_I2CSLAVE
-#if DEVICE_I2C_ASYNCH
-
-
-i2c_t *get_i2c_obj(I2C_HandleTypeDef *hi2c){
-
- /* Aim of the function is to get i2c_s pointer using hi2c pointer */
- /* Highly inspired from magical linux kernel's "container_of" */
- /* (which was not directly used since not compatible with IAR toolchain) */
- struct i2c_s *obj_s;
- i2c_t *obj;
-
- obj_s = (struct i2c_s *)( (char *)hi2c - offsetof(struct i2c_s,handle));
- obj = (i2c_t *)( (char *)obj_s - offsetof(i2c_t,i2c));
-
- return (obj);
-}
-
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){
/* Get object ptr based on handler ptr */
i2c_t *obj = get_i2c_obj(hi2c);
struct i2c_s *obj_s = I2C_S(obj);
+#if DEVICE_I2C_ASYNCH
/* Handle potential Tx/Rx use case */
if ((obj->tx_buff.length) && (obj->rx_buff.length)) {
-
- if (obj_s->stop) {
+ if (obj_s->stop) {
obj_s->XferOperation = I2C_LAST_FRAME;
- }
- else {
+ } else {
obj_s->XferOperation = I2C_NEXT_FRAME;
}
HAL_I2C_Master_Sequential_Receive_IT(hi2c, obj_s->address, (uint8_t*)obj->rx_buff.buffer , obj->rx_buff.length, obj_s->XferOperation);
}
- else {
+ else
+#endif
+ {
/* Set event flag */
obj_s->event = I2C_EVENT_TRANSFER_COMPLETE;
}
@@ -635,15 +716,17 @@
/* Get object ptr based on handler ptr */
i2c_t *obj = get_i2c_obj(hi2c);
struct i2c_s *obj_s = I2C_S(obj);
- I2C_HandleTypeDef *handle = &(obj_s->handle);
+
+ DEBUG_PRINTF("HAL_I2C_ErrorCallback:%d, index=%d\r\n", (int) hi2c->ErrorCode, obj_s->index);
- /* Disable IT. Not always done before calling macro */
- __HAL_I2C_DISABLE_IT(handle, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR);
+ /* re-init IP to try and get back in a working state */
+ i2c_init(obj, obj_s->sda, obj_s->scl);
- /* Set event flag */
+ /* Keep Set event flag */
obj_s->event = I2C_EVENT_ERROR;
}
+#if DEVICE_I2C_ASYNCH
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c){
/* Get object ptr based on handler ptr */
i2c_t *obj = get_i2c_obj(hi2c);
@@ -683,18 +766,7 @@
obj_s->address = address;
obj_s->stop = stop;
- IRQn_Type irq_event_n = obj_s->event_i2cIRQ;
- IRQn_Type irq_error_n = obj_s->error_i2cIRQ;
-
- /* Set up event IT using IRQ and handler tables */
- NVIC_SetVector(irq_event_n, handler);
- HAL_NVIC_SetPriority(irq_event_n, 0, 1);
- HAL_NVIC_EnableIRQ(irq_event_n);
-
- /* Set up error IT using IRQ and handler tables */
- NVIC_SetVector(irq_error_n, handler);
- HAL_NVIC_SetPriority(irq_error_n, 0, 0);
- HAL_NVIC_EnableIRQ(irq_error_n);
+ i2c_ev_err_enable(obj, handler);
/* Set operation step depending if stop sending required or not */
if ((tx_length && !rx_length) || (!tx_length && rx_length)) {
