You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by vi...@apache.org on 2018/11/19 17:07:54 UTC
[mynewt-core] 07/07: Add new API for double buffered I2C
This is an automated email from the ASF dual-hosted git repository.
vipulrahane pushed a commit to branch dma_i2c_new_api
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit b9fd22e9c34cca5eed58ebf148415e5e2a341d62
Author: Vipul Rahane <vi...@runtime.io>
AuthorDate: Mon Nov 19 09:07:02 2018 -0800
Add new API for double buffered I2C
---
hw/drivers/led/lp5523/src/lp5523.c | 27 ++++++-
hw/drivers/led/lp5523/syscfg.yml | 4 +-
hw/drivers/sensors/lis2dh12/src/lis2dh12.c | 22 ++++-
hw/drivers/sensors/lis2dh12/syscfg.yml | 2 +-
hw/drivers/sensors/lps33hw/src/lps33hw.c | 21 ++++-
hw/drivers/sensors/lps33hw/syscfg.yml | 4 +-
hw/drivers/sensors/lps33thw/src/lps33thw.c | 19 ++++-
hw/drivers/sensors/lps33thw/syscfg.yml | 2 +-
hw/drivers/sensors/ms5840/src/ms5840.c | 21 ++++-
hw/drivers/sensors/ms5840/syscfg.yml | 2 +-
hw/hal/include/hal/hal_i2c.h | 20 ++++-
hw/hal/syscfg.yml | 4 +
hw/mcu/nordic/nrf52xxx/src/hal_i2c.c | 124 ++++++++++++++++++++++++++---
hw/mcu/nordic/nrf52xxx/syscfg.yml | 1 +
hw/util/i2cn/include/i2cn/i2cn.h | 4 +
hw/util/i2cn/src/i2cn.c | 26 ++++++
16 files changed, 267 insertions(+), 36 deletions(-)
diff --git a/hw/drivers/led/lp5523/src/lp5523.c b/hw/drivers/led/lp5523/src/lp5523.c
index 894a5fc..6e0bdb4 100644
--- a/hw/drivers/led/lp5523/src/lp5523.c
+++ b/hw/drivers/led/lp5523/src/lp5523.c
@@ -31,12 +31,14 @@
STATS_SECT_START(lp5523_stat_section)
STATS_SECT_ENTRY(read_errors)
STATS_SECT_ENTRY(write_errors)
+ STATS_SECT_ENTRY(write_read_errors)
STATS_SECT_END
/* Define stat names for querying */
STATS_NAME_START(lp5523_stat_section)
STATS_NAME(lp5523_stat_section, read_errors)
STATS_NAME(lp5523_stat_section, write_errors)
+ STATS_NAME(lp5523_stat_section, write_read_errors)
STATS_NAME_END(lp5523_stat_section)
/* Global variable used to hold stats data */
@@ -87,8 +89,10 @@ lp5523_get_reg(struct led_itf *itf, enum lp5523_registers addr,
struct hal_i2c_master_data data_struct = {
.address = itf->li_addr,
- .len = 1,
- .buffer = &addr
+ .len1 = 1,
+ .buffer1 = &addr,
+ .len2 = 1,
+ .buffer2 = value
};
rc = led_itf_lock(itf, MYNEWT_VAL(LP5523_ITF_LOCK_TMO));
@@ -96,6 +100,7 @@ lp5523_get_reg(struct led_itf *itf, enum lp5523_registers addr,
return rc;
}
+#if 0
/* Register write */
rc = i2cn_master_write(itf->li_num, &data_struct, MYNEWT_VAL(LP5523_I2C_TIMEOUT_TICKS), 0,
MYNEWT_VAL(LP5523_I2C_RETRIES));
@@ -117,6 +122,16 @@ lp5523_get_reg(struct led_itf *itf, enum lp5523_registers addr,
itf->li_addr, addr);
STATS_INC(g_lp5523stats, read_errors);
}
+#endif
+ rc = i2cn_master_write_read(itf->li_num, &data_struct, MYNEWT_VAL(LP5523_I2C_TIMEOUT_TICKS), 0,
+ MYNEWT_VAL(LP5523_I2C_RETRIES));
+
+ if (rc) {
+ LP5523_LOG(ERROR, "I2C wr failed at address 0x%02X\n",
+ itf->li_addr);
+ STATS_INC(g_lp5523stats, write_read_errors);
+ goto err;
+ }
err:
led_itf_unlock(itf);
@@ -554,7 +569,13 @@ lp5523_get_engine_int(struct led_itf *itf, uint8_t engine, uint8_t *flag)
int
lp5523_reset(struct led_itf *itf)
{
- return lp5523_set_reg(itf, LP5523_RESET, 0xff);
+ int rc;
+
+ rc = lp5523_set_reg(itf, LP5523_RESET, 0xff);
+
+ os_time_delay(1);
+
+ return rc;
}
int
diff --git a/hw/drivers/led/lp5523/syscfg.yml b/hw/drivers/led/lp5523/syscfg.yml
index 49a64c3..bea4c2c 100644
--- a/hw/drivers/led/lp5523/syscfg.yml
+++ b/hw/drivers/led/lp5523/syscfg.yml
@@ -43,7 +43,7 @@ syscfg.defs:
description: >
Number of retries to use for failed I2C communication. A retry is
used when the LP5523 sends an unexpected NACK.
- value: 2
+ value: 0
LP5523_STARTUP_SEQ_DELAY:
description: >
Startup sequence delay for chip to finish start sequence
@@ -52,4 +52,4 @@ syscfg.defs:
LP5523_I2C_TIMEOUT_TICKS:
description: >
Number of OS ticks to wait for each I2C transaction to complete.
- value: 3
+ value: 10
diff --git a/hw/drivers/sensors/lis2dh12/src/lis2dh12.c b/hw/drivers/sensors/lis2dh12/src/lis2dh12.c
index fcc272a..3558f35 100644
--- a/hw/drivers/sensors/lis2dh12/src/lis2dh12.c
+++ b/hw/drivers/sensors/lis2dh12/src/lis2dh12.c
@@ -152,6 +152,7 @@ STATS_SECT_START(lis2dh12_stat_section)
STATS_SECT_ENTRY(orient_chg_y_notify)
STATS_SECT_ENTRY(orient_chg_z_notify)
#endif
+ STATS_SECT_ENTRY(write_read_errors)
STATS_SECT_END
/* Define stat names for querying */
@@ -170,6 +171,7 @@ STATS_NAME_START(lis2dh12_stat_section)
STATS_NAME(lis2dh12_stat_section, orient_chg_y_notify)
STATS_NAME(lis2dh12_stat_section, orient_chg_z_notify)
#endif
+ STATS_NAME(lis2dh12_stat_section, write_read_errors)
STATS_NAME_END(lis2dh12_stat_section)
/* Global variable used to hold stats data */
@@ -227,24 +229,27 @@ lis2dh12_i2c_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer,
uint8_t len)
{
int rc;
+
if (len > 1)
{
addr |= 0x80;
}
- uint8_t payload[20] = { addr, 0, 0, 0, 0, 0, 0, 0,
+ uint8_t payload[20] = { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0};
struct hal_i2c_master_data data_struct = {
.address = itf->si_addr,
- .len = 1,
- .buffer = payload
+ .len1 = 1,
+ .buffer1 = &addr,
+ .len2 = len,
+ .buffer2 = payload
};
/* Clear the supplied buffer */
memset(buffer, 0, len);
-
+#if 0
/* Register write */
rc = i2cn_master_write(itf->si_num, &data_struct, MYNEWT_VAL(LIS2DH12_I2C_TIMEOUT_TICKS), 1,
MYNEWT_VAL(LIS2DH12_I2C_RETRIES));
@@ -266,6 +271,15 @@ lis2dh12_i2c_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer,
STATS_INC(g_lis2dh12stats, read_errors);
goto err;
}
+#endif
+ rc = i2cn_master_write_read(itf->si_num, &data_struct, MYNEWT_VAL(LIS2DH12_I2C_TIMEOUT_TICKS) * (len + 1), 1,
+ MYNEWT_VAL(LIS2DH12_I2C_RETRIES));
+ if (rc) {
+ LIS2DH12_LOG(ERROR, "Failed to read from 0x%02X:0x%02X\n",
+ data_struct.address, addr);
+ STATS_INC(g_lis2dh12stats, write_read_errors);
+ goto err;
+ }
/* Copy the I2C results into the supplied buffer */
memcpy(buffer, payload, len);
diff --git a/hw/drivers/sensors/lis2dh12/syscfg.yml b/hw/drivers/sensors/lis2dh12/syscfg.yml
index 72cd520..d2251f0 100644
--- a/hw/drivers/sensors/lis2dh12/syscfg.yml
+++ b/hw/drivers/sensors/lis2dh12/syscfg.yml
@@ -28,7 +28,7 @@ syscfg.defs:
description: >
Number of retries to use for failed I2C communication. A retry is
used when the LIS2DH12 sends an unexpected NACK.
- value: 2
+ value: 0
LIS2DH12_I2C_TIMEOUT_TICKS:
description: >
Number of OS ticks to wait for each I2C transaction to complete.
diff --git a/hw/drivers/sensors/lps33hw/src/lps33hw.c b/hw/drivers/sensors/lps33hw/src/lps33hw.c
index 62706b5..dd096c7 100644
--- a/hw/drivers/sensors/lps33hw/src/lps33hw.c
+++ b/hw/drivers/sensors/lps33hw/src/lps33hw.c
@@ -47,12 +47,14 @@ static struct hal_spi_settings spi_lps33hw_settings = {
STATS_SECT_START(lps33hw_stat_section)
STATS_SECT_ENTRY(read_errors)
STATS_SECT_ENTRY(write_errors)
+ STATS_SECT_ENTRY(write_read_errors)
STATS_SECT_END
/* Define stat names for querying */
STATS_NAME_START(lps33hw_stat_section)
STATS_NAME(lps33hw_stat_section, read_errors)
STATS_NAME(lps33hw_stat_section, write_errors)
+ STATS_NAME(lps33hw_stat_section, write_read_errors)
STATS_NAME_END(lps33hw_stat_section)
/* Global variable used to hold stats data */
@@ -183,7 +185,7 @@ lps33hw_i2c_set_reg(struct sensor_itf *itf, uint8_t reg, uint8_t value)
LPS33HW_LOG(ERROR,
"Failed to write to 0x%02X:0x%02X with value 0x%02X\n",
itf->si_addr, reg, value);
- STATS_INC(g_lps33hwstats, read_errors);
+ STATS_INC(g_lps33hwstats, write_errors);
}
return rc;
@@ -342,10 +344,13 @@ lps33hw_i2c_get_regs(struct sensor_itf *itf, uint8_t reg, uint8_t size,
struct hal_i2c_master_data data_struct = {
.address = itf->si_addr,
- .len = 1,
- .buffer = ®
+ .len1 = 1,
+ .buffer1 = ®,
+ .len2 = size,
+ .buffer2 = buffer
};
+#if 0
/* Register write */
rc = i2cn_master_write(itf->si_num, &data_struct, MYNEWT_VAL(LPS33HW_I2C_TIMEOUT_TICKS), 0,
MYNEWT_VAL(LPS33HW_I2C_RETRIES));
@@ -368,6 +373,16 @@ lps33hw_i2c_get_regs(struct sensor_itf *itf, uint8_t reg, uint8_t size,
itf->si_addr, reg);
STATS_INC(g_lps33hwstats, read_errors);
}
+#endif
+ rc = i2cn_master_write_read(itf->si_num, &data_struct,
+ (MYNEWT_VAL(LPS33HW_I2C_TIMEOUT_TICKS)) * (size + 1), 1,
+ MYNEWT_VAL(LPS33HW_I2C_RETRIES));
+
+ if (rc) {
+ LPS33HW_LOG(ERROR, "Failed to write-read from 0x%02X:0x%02X\n",
+ itf->si_addr, reg);
+ STATS_INC(g_lps33hwstats, write_read_errors);
+ }
return rc;
}
diff --git a/hw/drivers/sensors/lps33hw/syscfg.yml b/hw/drivers/sensors/lps33hw/syscfg.yml
index 12f5a63..89eaa8e 100644
--- a/hw/drivers/sensors/lps33hw/syscfg.yml
+++ b/hw/drivers/sensors/lps33hw/syscfg.yml
@@ -42,9 +42,9 @@ syscfg.defs:
description: >
Number of retries to use for failed I2C communication. A retry is
used when the LPS33HW sends an unexpected NACK.
- value: 2
+ value: 0
LPS33HW_I2C_TIMEOUT_TICKS:
description: >
Number of OS ticks to wait for each I2C transaction to complete.
value: 3
-
\ No newline at end of file
+
diff --git a/hw/drivers/sensors/lps33thw/src/lps33thw.c b/hw/drivers/sensors/lps33thw/src/lps33thw.c
index 0d38500..1b368d3 100644
--- a/hw/drivers/sensors/lps33thw/src/lps33thw.c
+++ b/hw/drivers/sensors/lps33thw/src/lps33thw.c
@@ -342,10 +342,12 @@ lps33thw_i2c_get_regs(struct sensor_itf *itf, uint8_t reg, uint8_t size,
struct hal_i2c_master_data data_struct = {
.address = itf->si_addr,
- .len = 1,
- .buffer = ®
+ .len1 = 1,
+ .buffer1 = ®,
+ .len2 = size,
+ .buffer2 = buffer
};
-
+#if 0
/* Register write */
rc = i2cn_master_write(itf->si_num, &data_struct, MYNEWT_VAL(LPS33THW_I2C_TIMEOUT_TICKS), 0,
MYNEWT_VAL(LPS33THW_I2C_RETRIES));
@@ -368,6 +370,17 @@ lps33thw_i2c_get_regs(struct sensor_itf *itf, uint8_t reg, uint8_t size,
itf->si_addr, reg);
STATS_INC(g_lps33thwstats, read_errors);
}
+#endif
+ rc = i2cn_master_write_read(itf->si_num, &data_struct,
+ (MYNEWT_VAL(LPS33THW_I2C_TIMEOUT_TICKS)) * (size + 1), 1,
+ MYNEWT_VAL(LPS33THW_I2C_RETRIES));
+
+ if (rc) {
+ LPS33THW_LOG(ERROR, "Failed to write-read from 0x%02X:0x%02X\n",
+ itf->si_addr, reg);
+ STATS_INC(g_lps33thwstats, read_errors);
+ }
+
return rc;
}
diff --git a/hw/drivers/sensors/lps33thw/syscfg.yml b/hw/drivers/sensors/lps33thw/syscfg.yml
index ba1aa29..46773d5 100644
--- a/hw/drivers/sensors/lps33thw/syscfg.yml
+++ b/hw/drivers/sensors/lps33thw/syscfg.yml
@@ -42,7 +42,7 @@ syscfg.defs:
description: >
Number of retries to use for failed I2C communication. A retry is
used when the LPS33THW sends an unexpected NACK.
- value: 2
+ value: 0
LPS33THW_I2C_TIMEOUT_TICKS:
description: >
Number of OS ticks to wait for each I2C transaction to complete.
diff --git a/hw/drivers/sensors/ms5840/src/ms5840.c b/hw/drivers/sensors/ms5840/src/ms5840.c
index ab421de..dac0321 100644
--- a/hw/drivers/sensors/ms5840/src/ms5840.c
+++ b/hw/drivers/sensors/ms5840/src/ms5840.c
@@ -51,6 +51,7 @@ static uint16_t cnv_time[6] = {
STATS_SECT_START(ms5840_stat_section)
STATS_SECT_ENTRY(read_errors)
STATS_SECT_ENTRY(write_errors)
+ STATS_SECT_ENTRY(write_read_errors)
STATS_SECT_ENTRY(eeprom_crc_errors)
STATS_SECT_END
@@ -58,6 +59,7 @@ STATS_SECT_END
STATS_NAME_START(ms5840_stat_section)
STATS_NAME(ms5840_stat_section, read_errors)
STATS_NAME(ms5840_stat_section, write_errors)
+ STATS_NAME(ms5840_stat_section, write_read_errors)
STATS_NAME(ms5840_stat_section, eeprom_crc_errors)
STATS_NAME_END(ms5840_stat_section)
@@ -365,12 +367,14 @@ ms5840_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer,
uint8_t len)
{
int rc;
- uint8_t payload[3] = {addr, 0, 0};
+ uint8_t payload[3] = {0};
struct hal_i2c_master_data data_struct = {
.address = itf->si_addr,
- .len = 1,
- .buffer = payload
+ .len1 = 1,
+ .buffer1 = &addr,
+ .len2 = len,
+ .buffer2 = payload,
};
/* Clear the supplied buffer */
@@ -380,7 +384,7 @@ ms5840_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer,
if (rc) {
return rc;
}
-
+#if 0
/* Command write */
rc = i2cn_master_write(itf->si_num, &data_struct, MYNEWT_VAL(MS5840_I2C_TIMEOUT_TICKS), 1,
MYNEWT_VAL(MS5840_I2C_RETRIES));
@@ -402,6 +406,15 @@ ms5840_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer,
STATS_INC(g_ms5840stats, read_errors);
goto err;
}
+#endif
+ rc = i2cn_master_write_read(itf->si_num, &data_struct, MYNEWT_VAL(MS5840_I2C_TIMEOUT_TICKS) * (len + 1), 1,
+ MYNEWT_VAL(MS5840_I2C_RETRIES));
+ if (rc) {
+ MS5840_LOG(ERROR, "Failed to write-read from 0x%02X:0x%02X\n",
+ data_struct.address, addr);
+ STATS_INC(g_ms5840stats, write_read_errors);
+ goto err;
+ }
/* Copy the I2C results into the supplied buffer */
memcpy(buffer, payload, len);
diff --git a/hw/drivers/sensors/ms5840/syscfg.yml b/hw/drivers/sensors/ms5840/syscfg.yml
index 7a405ea..8c3f76d 100644
--- a/hw/drivers/sensors/ms5840/syscfg.yml
+++ b/hw/drivers/sensors/ms5840/syscfg.yml
@@ -27,7 +27,7 @@ syscfg.defs:
description: >
Number of retries to use for failed I2C communication. A retry is
used when the MS5840 sends an unexpected NACK.
- value: 2
+ value: 0
MS5840_I2C_TIMEOUT_TICKS:
description: >
Number of OS ticks to wait for each I2C transaction to complete.
diff --git a/hw/hal/include/hal/hal_i2c.h b/hw/hal/include/hal/hal_i2c.h
index 0d1173e..a794621 100644
--- a/hw/hal/include/hal/hal_i2c.h
+++ b/hw/hal/include/hal/hal_i2c.h
@@ -114,10 +114,25 @@ struct hal_i2c_master_data {
* only the top 7-bits to this function as 0x40
*/
uint8_t address;
- /** Number of buffer bytes to transmit or receive */
+//#if MYNEWT_VAL(HAL_I2C_DOUBLE_BUFFERED)
+ /** Number of buffer bytes to transmit or receive using buffer 1*/
uint16_t len;
+ /** Number of buffer bytes to transmit or receive using buffer 2*/
+ uint16_t len1;
+//#else
+ /** Number of buffer bytes to transmit or receive */
+ uint16_t len2;
+//#endif
+
+//#if MYNEWT_VAL(HAL_I2C_DOUBLE_BUFFERED)
+ /** Buffer space to hold the transmit or receive */
+ uint8_t *buffer1;
+ /** Buffer space to hold the transmit or receive */
+ uint8_t *buffer2;
+//#else
/** Buffer space to hold the transmit or receive */
uint8_t *buffer;
+//#endif
};
/**
@@ -180,6 +195,9 @@ int hal_i2c_master_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
*/
int hal_i2c_master_probe(uint8_t i2c_num, uint8_t address,
uint32_t timeout);
+int
+hal_i2c_master_write_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
+ uint32_t timo, uint8_t last_op);
#ifdef __cplusplus
}
diff --git a/hw/hal/syscfg.yml b/hw/hal/syscfg.yml
index f49dff1..4333534 100644
--- a/hw/hal/syscfg.yml
+++ b/hw/hal/syscfg.yml
@@ -33,6 +33,10 @@ syscfg.defs:
buffer of this size is allocated on the stack during verify
operations.
value: 16
+ HAL_I2C_DOUBLE_BUFFERED:
+ description: >
+ Specify whether the HAL uses double buffered implementation
+ value: 0
syscfg.vals.OS_DEBUG_MODE:
HAL_FLASH_VERIFY_WRITES: 1
diff --git a/hw/mcu/nordic/nrf52xxx/src/hal_i2c.c b/hw/mcu/nordic/nrf52xxx/src/hal_i2c.c
index c2c5e71..b792318 100644
--- a/hw/mcu/nordic/nrf52xxx/src/hal_i2c.c
+++ b/hw/mcu/nordic/nrf52xxx/src/hal_i2c.c
@@ -399,19 +399,34 @@ hal_i2c_handle_transact_end(NRF_TWIM_Type *regs, uint8_t op, uint32_t start,
{
int rc;
volatile uint32_t *evt;
- os_time_t now = 0;
+ volatile os_time_t now = 0;
- while(1) {
- /*
- * Use last_op as the determining factor for the type of event to be
- * monitored
- */
- if (last_op) {
- evt = ®s->EVENTS_STOPPED;
- } else {
- evt = ®s->EVENTS_SUSPENDED;
+ /*
+ * Use last_op as the determining factor for the type of event to be
+ * monitored
+ */
+ if (last_op) {
+ evt = ®s->EVENTS_STOPPED;
+ } else {
+ evt = ®s->EVENTS_SUSPENDED;
+ }
+
+ /* since there is no SUSPEND short for RX, we have to specifically
+ * deal with it
+ */
+ if (op == I2C_READ && !last_op) {
+ while (!regs->EVENTS_LASTRX) {
+ now = os_time_get();
+ if (OS_TIME_TICK_GT(now, abs_timo)) {
+ rc = HAL_I2C_ERR_TIMEOUT;
+ goto err;
+ }
}
+ regs->TASKS_SUSPEND = 1;
+ }
+
+ while(1) {
if (*evt) {
if (evt == ®s->EVENTS_STOPPED) {
#if MYNEWT_VAL(NRF52_HANDLE_ANOMALY_109)
@@ -433,10 +448,11 @@ hal_i2c_handle_transact_end(NRF_TWIM_Type *regs, uint8_t op, uint32_t start,
goto err;
}
}
+ regs->TASKS_RESUME = 1;
g_start = os_cputime_get32() - g_start;
- console_printf("t:%lu r:%u\n", g_start, op);
+ //console_printf("t:%lu r:%u\n", g_start, op);
return 0;
err:
@@ -638,6 +654,8 @@ hal_i2c_master_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
*/
if (last_op) {
regs->SHORTS = TWIM_SHORTS_LASTRX_STOP_Msk;
+ } else {
+ regs->SHORTS = 0;
}
/* Starts an I2C transaction using TWIM/EasyDMA */
@@ -661,6 +679,90 @@ err:
}
int
+hal_i2c_master_write_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
+ uint32_t timo, uint8_t last_op)
+{
+ int rc;
+ os_time_t now;
+ uint32_t start;
+ NRF_TWIM_Type *regs;
+ struct nrf52_hal_i2c *i2c;
+
+ start = os_time_get();
+ g_start = os_cputime_get32();
+
+ /* Resolve the I2C bus */
+ rc = hal_i2c_resolve(i2c_num, &i2c);
+ if (rc != 0) {
+ return rc;
+ }
+
+ regs = i2c->nhi_regs;
+
+ /* Detect errors on the bus based on the previous and current
+ * condition of the bus
+ */
+ rc = hal_i2c_bus_error_detect(i2c);
+ if (rc) {
+ goto err;
+ }
+
+ /* Configure the RXD registers for EasyDMA access to work with buffers of
+ * specific length and address of the slave
+ */
+ regs->ADDRESS = pdata->address;
+ regs->TXD.MAXCNT = pdata->len1;
+ regs->TXD.PTR = (uint32_t)pdata->buffer1;
+ regs->TXD.LIST = 0;
+ /* Disable and clear interrupts */
+ regs->INTENCLR = NRF_TWIM_ALL_INTS_MASK;
+ regs->INTEN = 0;
+ regs->SHORTS = TWIM_SHORTS_LASTTX_STARTRX_Msk;
+
+ /* Starts an I2C transaction using TWIM/EasyDMA */
+ rc = hal_i2c_handle_transact_start(i2c, I2C_WRITE, start + timo, pdata->address);
+ if (rc) {
+ goto err;
+ }
+
+ while (!regs->EVENTS_LASTTX) {
+ now = os_time_get();
+ if (OS_TIME_TICK_GT(now, start + timo)) {
+ rc = HAL_I2C_ERR_TIMEOUT;
+ return rc;
+ }
+ }
+
+ regs->RXD.MAXCNT = pdata->len2;
+ regs->RXD.PTR = (uint32_t)pdata->buffer2;
+ regs->RXD.LIST = 0;
+ /* Only set short for RX->STOP for last_op:1 since there is no suspend short
+ * available in nrf52832
+ */
+ if (last_op) {
+ regs->SHORTS = TWIM_SHORTS_LASTRX_STOP_Msk;
+ } else {
+ regs->SHORTS = 0;
+ }
+
+ regs->TASKS_RESUME = 1;
+
+ /* Ends an I2C transaction using TWIM/EasyDMA */
+ rc = hal_i2c_handle_transact_end(regs, I2C_READ, start, start + timo, last_op);
+ if (rc) {
+ goto err;
+ }
+
+ /* Save the current last op to detect bus errors later */
+ i2c->nhi_prev_last_op = last_op;
+
+ return 0;
+err:
+ return hal_i2c_handle_errors(i2c, rc, start + timo);
+}
+
+
+int
hal_i2c_master_probe(uint8_t i2c_num, uint8_t address, uint32_t timo)
{
struct hal_i2c_master_data rx;
diff --git a/hw/mcu/nordic/nrf52xxx/syscfg.yml b/hw/mcu/nordic/nrf52xxx/syscfg.yml
index acd907f..98dde96 100644
--- a/hw/mcu/nordic/nrf52xxx/syscfg.yml
+++ b/hw/mcu/nordic/nrf52xxx/syscfg.yml
@@ -410,3 +410,4 @@ syscfg.restrictions:
- "!SPI_3_SLAVE || (SPI_3_SLAVE_PIN_SCK && SPI_3_SLAVE_PIN_MOSI && SPI_3_SLAVE_PIN_MISO && SPI_3_SLAVE_PIN_SS)"
- "!UART_0 || (UART_0_PIN_TX && UART_0_PIN_RX)"
- "!UART_1 || (UART_1_PIN_TX && UART_1_PIN_RX)"
+ - "HAL_I2C_DOUBLE_BUFFERED"
diff --git a/hw/util/i2cn/include/i2cn/i2cn.h b/hw/util/i2cn/include/i2cn/i2cn.h
index d6caaae..f2b4851 100644
--- a/hw/util/i2cn/include/i2cn/i2cn.h
+++ b/hw/util/i2cn/include/i2cn/i2cn.h
@@ -64,6 +64,10 @@ int i2cn_master_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
int i2cn_master_write(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
uint32_t timeout, uint8_t last_op, int retries);
+int
+i2cn_master_write_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
+ uint32_t timeout, uint8_t last_op, int retries);
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/util/i2cn/src/i2cn.c b/hw/util/i2cn/src/i2cn.c
index 2322e1f..536a8bd 100644
--- a/hw/util/i2cn/src/i2cn.c
+++ b/hw/util/i2cn/src/i2cn.c
@@ -19,6 +19,7 @@
#include "hal/hal_i2c.h"
#include "i2cn/i2cn.h"
+#include <console/console.h>
int
i2cn_master_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
@@ -37,6 +38,7 @@ i2cn_master_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
if (rc == 0) {
break;
}
+ console_printf("r addr: %02x n: %u rc: %d\n", pdata->address, retries, rc);
}
return rc;
@@ -59,6 +61,30 @@ i2cn_master_write(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
if (rc == 0) {
break;
}
+ console_printf("w addr: %02x n: %u rc: %d\n", pdata->address, retries, rc);
+ }
+
+ return rc;
+}
+
+int
+i2cn_master_write_read(uint8_t i2c_num, struct hal_i2c_master_data *pdata,
+ uint32_t timeout, uint8_t last_op, int retries)
+{
+ int rc = 0;
+ int i;
+
+ /* Ensure at least one try. */
+ if (retries < 0) {
+ retries = 0;
+ }
+
+ for (i = 0; i <= retries; i++) {
+ rc = hal_i2c_master_write_read(i2c_num, pdata, timeout, last_op);
+ if (rc == 0) {
+ break;
+ }
+ console_printf("wr addr: %02x n: %u rc: %d\n", pdata->address, retries, rc);
}
return rc;