From b80d1e622f48f7f63ef64656396c96281e5768bc Mon Sep 17 00:00:00 2001 From: chrysn Date: Thu, 25 Jan 2024 15:23:07 +0100 Subject: [PATCH 1/2] cpu/nrf52 i2c: Always buffer writes The underlying peripheral can only read from RAM. This uses the existing infrastructure (already needed to work around the lack of a hardware support for I2C_NOSTART) to unconditionally copy any to-be-sent data into RAM. --- cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c | 31 ++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c b/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c index 8f420deba33d..626df5235dbf 100644 --- a/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c +++ b/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c @@ -92,6 +92,14 @@ static inline NRF_TWIM_Type *bus(i2c_t dev) return i2c_config[dev].dev; } +/** + * @brief Like i2c_write_bytes, but with the constraint (created by the + * hardware) that data is in RAM + */ +static int direct_i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, + size_t len, + uint8_t flags); + /** * Block until the interrupt described by inten_success_flag or * TWIM_INTEN_ERROR_Msk fires. @@ -262,7 +270,7 @@ int i2c_write_regs(i2c_t dev, uint16_t addr, uint16_t reg, } memcpy(&tx_buf[reg_addr_len], data, len); - int ret = i2c_write_bytes(dev, addr, tx_buf, reg_addr_len + len, flags); + int ret = direct_i2c_write_bytes(dev, addr, tx_buf, reg_addr_len + len, flags); /* Release tx_buf */ mutex_unlock(&buffer_lock); @@ -331,6 +339,27 @@ int i2c_read_regs(i2c_t dev, uint16_t addr, uint16_t reg, int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, uint8_t flags) +{ + /* These are critical for the memcpy; direct_i2c_write_bytes makes some + * more */ + assert((len > 0) && (len < 256)); + + /* Lock tx_buf */ + mutex_lock(&buffer_lock); + + memcpy(tx_buf, data, len); + + int result = direct_i2c_write_bytes(dev, addr, tx_buf, len, flags); + + /* Release tx_buf */ + mutex_unlock(&buffer_lock); + + return result; +} + +int direct_i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, + size_t len, + uint8_t flags) { assert((dev < I2C_NUMOF) && data && (len > 0) && (len < 256)); From 52a976e14766d01b1be1b2a5fe973c0a8cbcf6df Mon Sep 17 00:00:00 2001 From: chrysn Date: Thu, 25 Jan 2024 16:20:32 +0100 Subject: [PATCH 2/2] cpu/nrf52 i2c: Add shortcut when data is in RAM See-Also: https://github.com/RIOT-OS/RIOT/pull/20298#discussion_r1466508505 --- cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c b/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c index 626df5235dbf..288de2607422 100644 --- a/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c +++ b/cpu/nrf5x_common/periph/i2c_nrf52_nrf9160.c @@ -340,6 +340,10 @@ int i2c_read_regs(i2c_t dev, uint16_t addr, uint16_t reg, int i2c_write_bytes(i2c_t dev, uint16_t addr, const void *data, size_t len, uint8_t flags) { + if ((unsigned int)data >= CPU_RAM_BASE && (unsigned int)data < CPU_RAM_BASE + CPU_RAM_SIZE) { + return direct_i2c_write_bytes(dev, addr, data, len, flags); + } + /* These are critical for the memcpy; direct_i2c_write_bytes makes some * more */ assert((len > 0) && (len < 256));