From 624a94b57b3d8aa7784108cf34570d1b153f3cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Wed, 8 Oct 2025 17:41:52 +0200 Subject: [PATCH 01/14] Add files via upload --- libraries/Wire/keywords.txt | 26 ++++++++++++++++++++++++++ libraries/Wire/library.properties | 10 ++++++++++ 2 files changed, 36 insertions(+) create mode 100644 libraries/Wire/keywords.txt create mode 100644 libraries/Wire/library.properties diff --git a/libraries/Wire/keywords.txt b/libraries/Wire/keywords.txt new file mode 100644 index 000000000..8e1482140 --- /dev/null +++ b/libraries/Wire/keywords.txt @@ -0,0 +1,26 @@ +####################################### +# Syntax Coloring Map For Wire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Wire KEYWORD1 +Wire1 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +setClock KEYWORD2 +beginTransmission KEYWORD2 +endTransmission KEYWORD2 +requestFrom KEYWORD2 +onReceive KEYWORD2 +onRequest KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties new file mode 100644 index 000000000..293df5f2b --- /dev/null +++ b/libraries/Wire/library.properties @@ -0,0 +1,10 @@ +name=Wire +version=0.1 +author=Hanz Häger +maintainer=Hanz Häger +sentence=This library allows you to communicate with I2C and Two Wire Interface devices. +paragraph=It allows the communication with I2C devices like temperature sensors, realtime clocks and many others using SDA (Data Line) and SCL (Clock Line). +category=Communication +url= +architectures=renesas,renesas_portenta,renesas_uno +include=Wire.h From 819e8cf1f2700caef1d8e248f8c9d284de8bf93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Wed, 8 Oct 2025 17:43:15 +0200 Subject: [PATCH 02/14] Create Wire.cpp --- libraries/Wire/src/Wire.cpp | 1 + 1 file changed, 1 insertion(+) create mode 100644 libraries/Wire/src/Wire.cpp diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/libraries/Wire/src/Wire.cpp @@ -0,0 +1 @@ + From c9096563f0f20dd87c79e5501dbfb3b36d22dc63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Wed, 8 Oct 2025 17:45:29 +0200 Subject: [PATCH 03/14] Added support for timeout handling Also made the default timeout shorter than the 1000 ms that was hardcoded --- libraries/Wire/src/Wire.cpp | 948 ++++++++++++++++++++++++++++++++++++ libraries/Wire/src/Wire.h | 247 ++++++++++ 2 files changed, 1195 insertions(+) create mode 100644 libraries/Wire/src/Wire.h diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 8b1378917..63799d6cb 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -1 +1,949 @@ +/* + TwoWire.cpp - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts + Modified 2017 by Chuck Todd (ctodd@cableone.net) to correct Unconfigured Slave Mode reboot + + Version 2022 for Renesas RA4 by Daniele Aimo (d.aimo@arduino.cc) + + Version 2025 by Hanz Häger (hanz.hager+arduino@gmail.com) added timeout interface +*/ + +extern "C" { + #include + #include + #include +} + +#include "Wire.h" + +TwoWire *TwoWire::g_SCIWires[TWOWIRE_MAX_SCI_CHANNELS] = {nullptr}; +TwoWire *TwoWire::g_I2CWires[TWOWIRE_MAX_I2C_CHANNELS] = {nullptr}; + +/* -------------------------------------------------------------------------- */ +void TwoWire::setBusStatus(WireStatus_t ws) { +/* -------------------------------------------------------------------------- */ + bus_status = ws; +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::WireSCIMasterCallback(i2c_master_callback_args_t *arg) { +/* -------------------------------------------------------------------------- */ + /* +++++ MASTER I2C SCI Callback ++++++ */ + + i2c_master_cfg_t *cfg = (i2c_master_cfg_t *)arg->p_context; + + TwoWire *ptr = nullptr; + if(cfg->channel < TWOWIRE_MAX_SCI_CHANNELS) { + ptr = g_SCIWires[cfg->channel]; + } + + if(ptr == nullptr) { + return; + } + if(!ptr->init_ok) { + return; + } + + if(ptr != nullptr) { + if(arg->event == I2C_MASTER_EVENT_ABORTED) { + ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); + } + else if(arg->event == I2C_MASTER_EVENT_RX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); + } + else if(arg->event == I2C_MASTER_EVENT_TX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); + } + } + +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::WireMasterCallback(i2c_master_callback_args_t *arg) { +/* -------------------------------------------------------------------------- */ + /* +++++ MASTER I2C not SCI Callback ++++++ */ + i2c_master_cfg_t *cfg = (i2c_master_cfg_t *)arg->p_context; + + TwoWire *ptr = nullptr; + if(cfg->channel < TWOWIRE_MAX_I2C_CHANNELS) { + ptr = g_I2CWires[cfg->channel]; + } + + if(ptr == nullptr) { + return; + } + if(!ptr->init_ok) { + return; + } + + if(ptr != nullptr) { + if(arg->event == I2C_MASTER_EVENT_ABORTED) { + ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); + } + else if(arg->event == I2C_MASTER_EVENT_RX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); + } + else if(arg->event == I2C_MASTER_EVENT_TX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); + } + } +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::WireSlaveCallback(i2c_slave_callback_args_t *arg) { +/* -------------------------------------------------------------------------- */ + /* +++++ SLAVE Callback ++++++ */ + volatile uint32_t bytes = arg->bytes; + volatile i2c_slave_cfg_t *cfg = (i2c_slave_cfg_t *)arg->p_context; + + TwoWire *ptr = nullptr; + if(cfg->channel < TWOWIRE_MAX_I2C_CHANNELS) { + ptr = g_I2CWires[cfg->channel]; + } + + if(ptr == nullptr) { + return; + } + if(!ptr->init_ok) { + return; + } + + if(arg->event == I2C_SLAVE_EVENT_ABORTED) { + ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); + } + else if(arg->event == I2C_SLAVE_EVENT_RX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); + + ptr->cpy_rx_buffer(bytes); + if(ptr->rx_callback != nullptr) { + ptr->rx_callback(bytes); + } + } + else if(arg->event == I2C_SLAVE_EVENT_TX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); + } + else if(arg->event == I2C_SLAVE_EVENT_RX_REQUEST) { + ptr->setBusStatus(WIRE_STATUS_RX_REQUEST); + if(ptr->tmp_i + bytes < I2C_BUFFER_LENGTH) { + volatile fsp_err_t err; + err = ptr->slave_read(1); + if(err == FSP_SUCCESS) { + ptr->tmp_i += 1; + } + } + else { + ptr->slave_read(0); + } + } + else if(arg->event == I2C_SLAVE_EVENT_TX_REQUEST) { + ptr->setBusStatus(WIRE_STATUS_TX_REQUEST); + + if(ptr->tx_callback != nullptr) { + ptr->tx_callback(); + } + } + else if(arg->event == I2C_SLAVE_EVENT_RX_MORE_REQUEST) { + ptr->setBusStatus(WIRE_STATUS_RX_REQUEST); + + if(ptr->tmp_i + bytes < I2C_BUFFER_LENGTH) { + volatile fsp_err_t err; + err = ptr->slave_read(bytes); + if(err == FSP_SUCCESS) { + ptr->tmp_i += bytes; + } + } + else { + ptr->slave_read(0); + } + } + else if(arg->event == I2C_SLAVE_EVENT_TX_MORE_REQUEST) { + ptr->setBusStatus(WIRE_STATUS_TX_REQUEST); + if(ptr->tx_callback != nullptr) { + ptr->tx_callback(); + } + } + else if(arg->event == I2C_SLAVE_EVENT_GENERAL_CALL) { + ptr->setBusStatus(WIRE_STATUS_GENERAL_CALL); + } + +} + + +/* -------------------------------------------------------------------------- */ +TwoWire::TwoWire(int scl, int sda, WireAddressMode_t am /*= ADDRESS_MODE_7_BITS*/, bool prefer_sci /*= false*/) : + scl_pin(scl), + sda_pin(sda), + init_ok(false), + is_master(true), + is_sci(false), + address_mode(am), + timeout_us(25000), + timed_out_flag(false), + do_reset_on_timeout(false), + transmission_begun(false), + data_too_long(false), + rx_index(0), + tx_index(0), + require_sci(prefer_sci) { +/* -------------------------------------------------------------------------- */ + m_i2c_cfg.rxi_irq = FSP_INVALID_VECTOR; + m_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; + m_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; + m_i2c_cfg.eri_irq = FSP_INVALID_VECTOR; + + s_i2c_cfg.rxi_irq = FSP_INVALID_VECTOR; + s_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; + s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; + s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; +} + +/* -------------------------------------------------------------------------- */ +bool TwoWire::cfg_pins(int max_index) { +/* -------------------------------------------------------------------------- */ + /* verify index are good */ + if(scl_pin < 0 || sda_pin < 0 || scl_pin >= max_index || sda_pin >= max_index) { + return false; + } + /* getting configuration from table */ + auto cfgs_scl = getPinCfgs(scl_pin, PIN_CFG_REQ_SCL); + auto cfgs_sda = getPinCfgs(sda_pin, PIN_CFG_REQ_SDA); + + uint16_t cfg_scl = 0; + uint16_t cfg_sda = 0; + + /* Find the best combination */ + for (size_t i = 0; i < cfgs_scl.size(); i++) { + for (size_t j = 0; j < cfgs_sda.size(); j++) { + if (cfgs_scl[i] && cfgs_sda[j] && (GET_CHANNEL(cfgs_scl[i]) == GET_CHANNEL(cfgs_sda[j])) && (IS_SCI(cfgs_scl[i]) == IS_SCI(cfgs_sda[j]))) { + cfg_scl = cfgs_scl[i]; + cfg_sda = cfgs_sda[j]; + channel = GET_CHANNEL(cfg_scl); + goto done; + } + } + } + +done: + if (cfg_sda == 0 || cfg_scl == 0) { + return false; + } + + /* actually configuring PIN function */ + ioport_peripheral_t ioport_sda; + ioport_peripheral_t ioport_scl; + + if(IS_SCI(cfg_sda)) { + if(channel >= TWOWIRE_MAX_SCI_CHANNELS) { // channels are 0 index based + return false; + } + is_sci = true; + ioport_sda = USE_SCI_EVEN_CFG(cfg_sda) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9; + ioport_scl = USE_SCI_EVEN_CFG(cfg_scl) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9; + + R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[sda_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_PERIPHERAL_PIN | ioport_sda)); + R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[scl_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_PERIPHERAL_PIN | ioport_scl)); + + } + else { + if(channel >= TWOWIRE_MAX_I2C_CHANNELS) { // channels are 0 index based + return false; + } + is_sci = false; + ioport_sda = IOPORT_PERIPHERAL_IIC; + ioport_scl = IOPORT_PERIPHERAL_IIC; + + R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[sda_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_DRIVE_MID | IOPORT_CFG_PERIPHERAL_PIN | ioport_sda)); + R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[scl_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_DRIVE_MID | IOPORT_CFG_PERIPHERAL_PIN | ioport_scl)); + } + + return true; +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::begin(void) { +/* -------------------------------------------------------------------------- */ + end(); + is_master = true; + _begin(); + +} + + +/* -------------------------------------------------------------------------- */ +void TwoWire::_begin(void) { +/* -------------------------------------------------------------------------- */ + init_ok = true; + int max_index = PINS_COUNT; + + init_ok &= cfg_pins(max_index); + + if(init_ok) { + + /* ----------------------------------- + ->>>>> MASTER initialization + * ----------------------------------- */ + if(is_master) { + + setClock(I2C_MASTER_RATE_STANDARD); + + if(is_sci) { + TwoWire::g_SCIWires[channel] = this; + + m_open = R_SCI_I2C_Open; + m_read = R_SCI_I2C_Read; + m_write = R_SCI_I2C_Write; + m_abort = R_SCI_I2C_Abort; + m_setSlaveAdd = R_SCI_I2C_SlaveAddressSet; + m_setCallback = R_SCI_I2C_CallbackSet; + m_getStatus = R_SCI_I2C_StatusGet; + m_close = R_SCI_I2C_Close; + + m_i2c_cfg.p_extend = &m_sci_i2c_extend; + m_i2c_cfg.p_callback = WireSCIMasterCallback; + } + else { + TwoWire::g_I2CWires[channel] = this; + + m_open = R_IIC_MASTER_Open; + m_read = R_IIC_MASTER_Read; + m_write = R_IIC_MASTER_Write; + m_abort = R_IIC_MASTER_Abort; + m_setSlaveAdd = R_IIC_MASTER_SlaveAddressSet; + m_setCallback = R_IIC_MASTER_CallbackSet; + m_getStatus = R_IIC_MASTER_StatusGet; + m_close = R_IIC_MASTER_Close; + + m_i2c_cfg.p_extend = &m_i2c_extend; + m_i2c_cfg.p_callback = WireMasterCallback; + + m_i2c_extend.timeout_mode = IIC_MASTER_TIMEOUT_MODE_SHORT; + m_i2c_extend.timeout_scl_low = IIC_MASTER_TIMEOUT_SCL_LOW_DISABLED; + } + + m_i2c_cfg.channel = channel; + m_i2c_cfg.rate = I2C_MASTER_RATE_STANDARD; + m_i2c_cfg.slave = 0x00; + m_i2c_cfg.addr_mode = (address_mode == ADDRESS_MODE_7_BITS) ? I2C_MASTER_ADDR_MODE_7BIT : I2C_MASTER_ADDR_MODE_10BIT; + m_i2c_cfg.p_transfer_tx = NULL; + m_i2c_cfg.p_transfer_rx = NULL; + + m_i2c_cfg.p_context = &m_i2c_cfg; + m_i2c_cfg.ipl = (12); + + } // if(is_master) { + /* ----------------------------------- + ->>>>> SLAVE initialization + * ----------------------------------- */ + else { + /* a slave device cannot be instatiated on SCI peripheral */ + if(is_sci) { + init_ok = false; + return; + } + TwoWire::g_I2CWires[channel] = this; + + s_open = R_IIC_SLAVE_Open; + s_read = R_IIC_SLAVE_Read; + s_write = R_IIC_SLAVE_Write; + s_setCallback = R_IIC_SLAVE_CallbackSet; + s_close = R_IIC_SLAVE_Close; + + s_i2c_cfg.channel = channel; + s_i2c_cfg.rate = I2C_SLAVE_RATE_STANDARD; + s_i2c_cfg.slave = slave_address; + s_i2c_cfg.addr_mode = (address_mode == ADDRESS_MODE_7_BITS) ? I2C_SLAVE_ADDR_MODE_7BIT : I2C_SLAVE_ADDR_MODE_10BIT; + s_i2c_cfg.general_call_enable = false; + s_i2c_cfg.ipl = (12); + s_i2c_cfg.eri_ipl = (12); + s_i2c_cfg.clock_stretching_enable = false; + s_i2c_cfg.p_callback = WireSlaveCallback; + s_i2c_cfg.p_context = &s_i2c_cfg; + s_i2c_cfg.p_extend = NULL; + } + } + else { + init_ok = false; + return; + } + + I2CIrqReq_t irq_req; + irq_req.mcfg = &m_i2c_cfg; + irq_req.scfg = &s_i2c_cfg; + + if(is_master) { + if(is_sci) { + init_ok &= IRQManager::getInstance().addPeripheral(IRQ_SCI_I2C_MASTER,&irq_req); + } + else { + init_ok &= IRQManager::getInstance().addPeripheral(IRQ_I2C_MASTER,&irq_req); + } + if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { + init_ok &= true; + } + else { + init_ok = false; + } + } + else { + init_ok &= IRQManager::getInstance().addPeripheral(IRQ_I2C_SLAVE,&irq_req); + if(FSP_SUCCESS == s_open(&s_i2c_ctrl,&s_i2c_cfg)) { + init_ok &= true; + } + else { + init_ok = false; + } + } +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::begin(uint16_t address) { +/* -------------------------------------------------------------------------- */ + end(); + is_master = false; + slave_address = address; + /* Address is set inside begin() using slave_address member variable */ + _begin(); + +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::begin(int address) { +/* -------------------------------------------------------------------------- */ + begin((uint16_t)address); +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::begin(uint8_t address) { +/* -------------------------------------------------------------------------- */ + begin((uint16_t)address); +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::end(void) { +/* -------------------------------------------------------------------------- */ + + if(init_ok) { + if(is_master) { + if(m_close != nullptr) { + R_BSP_IrqDisable (m_i2c_cfg.txi_irq); + R_BSP_IrqDisable (m_i2c_cfg.rxi_irq); + R_BSP_IrqDisable (m_i2c_cfg.tei_irq); + R_BSP_IrqDisable (m_i2c_cfg.eri_irq); + m_close(&m_i2c_ctrl); + } + } + else { + if(s_close != nullptr) { + R_BSP_IrqDisable (s_i2c_cfg.txi_irq); + R_BSP_IrqDisable (s_i2c_cfg.rxi_irq); + R_BSP_IrqDisable (s_i2c_cfg.tei_irq); + R_BSP_IrqDisable (s_i2c_cfg.eri_irq); + s_close(&s_i2c_ctrl); + + } + } + } + /* fix for slave that create a sort of lock on the I2C bus when end is called and the master + is not more able to get the I2C buse working */ + R_IOPORT_PinCfg(NULL, g_pin_cfg[sda_pin].pin, IOPORT_CFG_PORT_DIRECTION_INPUT | IOPORT_CFG_PULLUP_ENABLE); + R_IOPORT_PinCfg(NULL, g_pin_cfg[scl_pin].pin, IOPORT_CFG_PORT_DIRECTION_INPUT | IOPORT_CFG_PULLUP_ENABLE); + init_ok = false; +} + + + +/* -------------------------------------------------------------------------- */ +uint8_t TwoWire::read_from(uint8_t address, uint8_t* data, uint8_t length, uint32_t timeout_us, bool sendStop) { +/* -------------------------------------------------------------------------- */ + /* ??? does this function make sense only for MASTER ???? */ + + fsp_err_t err = FSP_ERR_ASSERTION; + if(init_ok) { + if(m_setSlaveAdd != nullptr) { + err = m_setSlaveAdd(&m_i2c_ctrl, address, m_i2c_cfg.addr_mode); + } + if(err == FSP_SUCCESS) { + if(m_read != nullptr) { + bus_status = WIRE_STATUS_UNSET; + err = m_read(&m_i2c_ctrl,data,length,!sendStop); + } + } + + while( bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { + uint32_t const start = micros(); + if((timeout_us > 0ul) && ((micros() - start) > timeout_us)) { + handleTimeout(do_reset_on_timeout); + return 0; + } + } + } + + if(bus_status == WIRE_STATUS_RX_COMPLETED) { + return length; + } + + return 0; /* ???????? return value ??????? */ +} + +/* -------------------------------------------------------------------------- */ +uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32_t timeout_us /* micros */, bool sendStop) { +/* -------------------------------------------------------------------------- */ + uint8_t rv = END_TX_OK; + fsp_err_t err = FSP_ERR_ASSERTION; + if(init_ok) { + if(m_setSlaveAdd != nullptr) { + err = m_setSlaveAdd(&m_i2c_ctrl, address, m_i2c_cfg.addr_mode); + } + if(err == FSP_SUCCESS) { + if(m_write != nullptr) { + bus_status = WIRE_STATUS_UNSET; + err = m_write(&m_i2c_ctrl,data,length,!sendStop); + } + } + + while( bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { + uint32_t const start = micros(); + if((timeout_us > 0ul) && ((micros() - start) > timeout_us)) { + handleTimeout(do_reset_on_timeout); + return END_TX_TIMEOUT; + } + } + + if(err != FSP_SUCCESS) { + rv = END_TX_ERR_FSP; + } + else if(data_too_long) { + rv = END_TX_DATA_TOO_LONG; + } + /* as far as I know is impossible to distinguish between NACK on ADDRESS and + NACK on DATA */ + else if(bus_status == WIRE_STATUS_TRANSACTION_ABORTED) { + rv = END_TX_NACK_ON_ADD; + } + } + else { + rv = END_TX_NOT_INIT; + } + + + return rv; +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::setClock(uint32_t freq) { +/* -------------------------------------------------------------------------- */ + if(init_ok && is_master) { + if(m_close != nullptr) { + m_close(&m_i2c_ctrl); + } + } + + if(is_master) { + m_i2c_cfg.rate = (i2c_master_rate_t)freq; + + int clock_divisor = (R_FSP_SystemClockHzGet(BSP_FEATURE_SCI_CLOCK) / 48000000u) - 1; + + if (is_sci) { + m_sci_i2c_extend.clock_settings.clk_divisor_value = 0; + m_sci_i2c_extend.clock_settings.cycles_value = 15; + m_sci_i2c_extend.clock_settings.snfr_value = (1); + switch (m_i2c_cfg.rate) { + case I2C_MASTER_RATE_STANDARD: + m_sci_i2c_extend.clock_settings.brr_value = 14; + m_sci_i2c_extend.clock_settings.mddr_value = 255; + m_sci_i2c_extend.clock_settings.bitrate_modulation = false; + break; + case I2C_MASTER_RATE_FAST: + default: + m_sci_i2c_extend.clock_settings.brr_value = 2; + m_sci_i2c_extend.clock_settings.mddr_value = 204; + m_sci_i2c_extend.clock_settings.bitrate_modulation = true; + break; + } + } else { + switch (m_i2c_cfg.rate) { + case I2C_MASTER_RATE_STANDARD: + m_i2c_extend.clock_settings.brl_value = 27; + m_i2c_extend.clock_settings.brh_value = 26; + m_i2c_extend.clock_settings.cks_value = 2 + clock_divisor; + break; + case I2C_MASTER_RATE_FAST: + m_i2c_extend.clock_settings.brl_value = 16; + m_i2c_extend.clock_settings.brh_value = 15; + m_i2c_extend.clock_settings.cks_value = 0 + clock_divisor; + break; +#if BSP_FEATURE_IIC_FAST_MODE_PLUS + case I2C_MASTER_RATE_FASTPLUS: + m_i2c_extend.clock_settings.brl_value = 6; + m_i2c_extend.clock_settings.brh_value = 5; + m_i2c_extend.clock_settings.cks_value = 0; + break; +#endif + } + } + } + + if(init_ok) { + if(m_open != nullptr) { + if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { + init_ok &= true; + } + else { + init_ok = false; + } + } + } +} + +/*** + * Sets the I2C timeout. + * + * This limits the maximum time to wait for the I2C hardware. If more time passes, the bus is assumed + * to have locked up (e.g. due to noise-induced glitches or faulty slaves) and the transaction is aborted. + * Optionally, the I2C hardware is also reset, which can be required to allow subsequent transactions to + * succeed in some cases (in particular when noise has made the I2C hardware think there is a second + * master that has claimed the bus). + * + * When a timeout is triggered, a flag is set that can be queried with `getWireTimeoutFlag()` and is cleared + * when `clearWireTimeoutFlag()` or `setWireTimeoutUs()` is called. + * + * Note that this timeout can also trigger while waiting for clock stretching or waiting for a second master + * to complete its transaction. So make sure to adapt the timeout to accommodate for those cases if needed. + * A typical timeout would be 25ms (which is the maximum clock stretching allowed by the SMBus protocol), + * but (much) shorter values will usually also work. + * + * In the future, a timeout will be enabled by default, so if you require the timeout to be disabled, it is + * recommended you disable it by default using `setWireTimeoutUs(0)`, even though that is currently + * the default. + * + * @param timeout a timeout value in microseconds, if zero then timeout checking is disabled + * @param reset_with_timeout if true then I2C interface will be automatically reset on timeout + * if false then I2C interface will not be reset on timeout + + */ + +/* -------------------------------------------------------------------------- */ +void TwoWire::setWireTimeout(uint32_t timeout, bool reset_with_timeout){ +/* -------------------------------------------------------------------------- */ + timed_out_flag = false; + timeout_us = timeout; + do_reset_on_timeout = reset_with_timeout; +} + +/*** + * Returns the timeout flag. + * + * @return true if timeout has occurred since the flag was last cleared. + */ +bool TwoWire::getWireTimeoutFlag(void){ + return(timed_out_flag); +} + +/*** + * Clears the timeout flag. + */ +/* -------------------------------------------------------------------------- */ +void TwoWire::clearWireTimeoutFlag(void){ +/* -------------------------------------------------------------------------- */ + timed_out_flag = false; +} + +/* + * Function handleTimeout + * Desc this gets called whenever a while loop here has lasted longer than + * timeout_us microseconds. always sets timed_out_flag + * Input reset: true causes this function to reset the hardware interface + * Output none + */ +/* -------------------------------------------------------------------------- */ +void TwoWire::handleTimeout(bool reset){ +/* -------------------------------------------------------------------------- */ + timed_out_flag = true; + + if (reset) { //TBD; What do we do here? like fixHungWire()? + // TBD, Is this the way to go to reset the bus? + // Do we need more to handle devices that hangs the bus? + if(m_abort != nullptr) { + bus_status = WIRE_STATUS_UNSET; + fsp_err_t err = m_abort(&m_i2c_ctrl); + } + // TDB, Is this the right way to get back after reset? + if(m_open != nullptr) { + if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { + init_ok &= true; + } + } + } +} + + + +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * TRANSMISSION BEGIN + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +/* -------------------------------------------------------------------------- */ +void TwoWire::beginTransmission(uint32_t address) { +/* -------------------------------------------------------------------------- */ + if (init_ok) { + data_too_long = false; + master_tx_address = address; + transmission_begun = true; + tx_index = 0; + } +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::beginTransmission(uint16_t address) { +/* -------------------------------------------------------------------------- */ + beginTransmission((uint32_t)address); +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::beginTransmission(uint8_t address){ +/* -------------------------------------------------------------------------- */ + beginTransmission((uint32_t)address); +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::beginTransmission(int address) { +/* -------------------------------------------------------------------------- */ + beginTransmission((uint32_t)address); +} + +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * TRANSMISSION END + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +/* -------------------------------------------------------------------------- */ +uint8_t TwoWire::endTransmission(bool sendStop) { +/* -------------------------------------------------------------------------- */ + uint8_t ret = write_to(master_tx_address, tx_buffer, tx_index, timeout_us, sendStop); + transmission_begun = false; + return ret; +} + +/* -------------------------------------------------------------------------- */ +uint8_t TwoWire::endTransmission(void) { +/* -------------------------------------------------------------------------- */ + return endTransmission(true); +} + +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * REQUEST FROM + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +/* -------------------------------------------------------------------------- */ +size_t TwoWire::requestFrom(uint8_t address, size_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) { +/* -------------------------------------------------------------------------- */ + if(init_ok) { + + if (isize > 0) { + // send internal address; this mode allows sending a repeated start to access + // some devices' internal registers. This function is executed by the hardware + // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) + + beginTransmission(address); + + // the maximum size of internal address is 3 bytes + if (isize > 3){ + isize = 3; + } + + // write internal register address - most significant byte first + while (isize-- > 0) { + write((uint8_t)(iaddress >> (isize*8))); + } + + endTransmission(false); + } + + // clamp to buffer length + if(quantity > I2C_BUFFER_LENGTH){ + quantity = I2C_BUFFER_LENGTH; + } + // perform blocking read into buffer + uint8_t read = read_from(address, rx_buffer, quantity, timeout_us, sendStop); + // set rx buffer iterator vars + rx_index = read; + rx_extract_index = 0; + + return (size_t)read; + } + else { + return 0; + } +} + +/* -------------------------------------------------------------------------- */ +size_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool sendStop) { +/* -------------------------------------------------------------------------- */ + return requestFrom((uint8_t)address, quantity, (uint32_t)0, (uint8_t)0, sendStop); +} + +/* -------------------------------------------------------------------------- */ +size_t TwoWire::requestFrom(uint8_t address, size_t quantity) { +/* -------------------------------------------------------------------------- */ + return requestFrom((uint8_t)address, quantity, true); +} + +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * WRITE + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +/* -------------------------------------------------------------------------- */ +size_t TwoWire::write(uint8_t data) { +/* -------------------------------------------------------------------------- */ + if(init_ok) { + if(is_master) { + if(transmission_begun) { + if(tx_index >= I2C_BUFFER_LENGTH) { + data_too_long = true; + setWriteError(); + return 0; + } + tx_buffer[tx_index] = data; + tx_index++; + } + } + else { + if(s_write != nullptr) { + s_write(&s_i2c_ctrl,(uint8_t *)&data,1); + } + } + return 1; + } + return 0; + +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +/* -------------------------------------------------------------------------- */ +size_t TwoWire::write(const uint8_t *data, size_t quantity) { +/* -------------------------------------------------------------------------- */ + if(init_ok) { + if(is_master) { + // in master transmitter mode + for(size_t i = 0; i < quantity; ++i){ + write(data[i]); + } + } + else{ + if(s_write != nullptr) { + s_write(&s_i2c_ctrl,(uint8_t *)data,quantity); + } + } + return quantity; + } + else { + return 0; + } +} + + +// sets function called on slave write +/* -------------------------------------------------------------------------- */ +void TwoWire::onReceive( I2C_onRxCallback_f f ) { +/* -------------------------------------------------------------------------- */ + rx_callback = f; +} + +// sets function called on slave read +/* -------------------------------------------------------------------------- */ +void TwoWire::onRequest( I2C_onTxCallback_f f ) { +/* -------------------------------------------------------------------------- */ + tx_callback = f; +} + + + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) + +/* -------------------------------------------------------------------------- */ +int TwoWire::available(void) { +/* -------------------------------------------------------------------------- */ + return rx_index - rx_extract_index; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +/* -------------------------------------------------------------------------- */ +int TwoWire::read(void) { +/* -------------------------------------------------------------------------- */ + int rv = -1; + + // get each successive byte on each call + if(rx_extract_index < rx_index){ + rv = rx_buffer[rx_extract_index]; + rx_extract_index++; + } + + return rv; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +/* -------------------------------------------------------------------------- */ +int TwoWire::peek(void) { +/* -------------------------------------------------------------------------- */ + int rv = -1; + + // get each successive byte on each call + if(rx_extract_index < rx_index){ + rv = rx_buffer[rx_extract_index]; + } + + return rv; +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::flush(void) { +/* -------------------------------------------------------------------------- */ + while(bus_status != WIRE_STATUS_TX_COMPLETED && bus_status != WIRE_STATUS_TRANSACTION_ABORTED) {} +} + + + + +#if WIRE_HOWMANY > 0 +TwoWire Wire(WIRE_SCL_PIN, WIRE_SDA_PIN); +#endif + +#if WIRE_HOWMANY > 1 +TwoWire Wire1(WIRE1_SCL_PIN, WIRE1_SDA_PIN); +#endif + +#if WIRE_HOWMANY > 2 +TwoWire Wire2(WIRE2_SCL_PIN, WIRE2_SDA_PIN); +#endif + +#if WIRE_HOWMANY > 3 +TwoWire Wire3(WIRE3_SCL_PIN, WIRE3_SDA_PIN); +#endif + diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h new file mode 100644 index 000000000..6ac84e911 --- /dev/null +++ b/libraries/Wire/src/Wire.h @@ -0,0 +1,247 @@ +/* + Copyright (c) 2016 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#define _TIMEVAL_DEFINED +#define _SYS_SELECT_H + +#include "Arduino.h" +#include "IRQManager.h" +#include "api/HardwareI2C.h" +#include "api/Stream.h" +#include + +#include "bsp_api.h" + +#include "r_iic_master.h" +#include "r_sci_i2c.h" +#include "r_i2c_master_api.h" +#include "r_i2c_slave_api.h" + +extern "C" { + void i2c_callback(i2c_master_callback_args_t *p_args); +} + +using I2C_masterOpen_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, i2c_master_cfg_t const *const p_cfg); +using I2C_masterRead_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint8_t *const p_dest, uint32_t const bytes, bool const restart); +using I2C_masterWrite_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint8_t *constp_src, uint32_t const bytes, bool const restart); +using I2C_masterAbort_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl); +using I2C_masterSetSlaveAdd_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint32_t const slave, i2c_master_addr_mode_t const addr_mode); +using I2C_masterSetCallBack_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, void(*p_callback)(i2c_master_callback_args_t *), void const *const p_context, i2c_master_callback_args_t *const p_callback_memory); +using I2C_masterGetStatus_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, i2c_master_status_t *p_status); +using I2C_masterClose_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl); + +using I2C_slaveOpen_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, i2c_slave_cfg_t const *const p_cfg); +using I2C_slaveRead_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, uint8_t *const p_dest, uint32_t const bytes); +using I2C_slaveWrite_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, uint8_t *const p_src, uint32_t const bytes); +using I2C_slaveSetCallBack_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, void(*p_callback)(i2c_slave_callback_args_t *), void const *const p_context, i2c_slave_callback_args_t *const p_callback_memory); +using I2C_slaveClose_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl); + +using I2C_onRxCallback_f = void (*)(int); +using I2C_onTxCallback_f = void (*)(void); + + +#define I2C_BUFFER_LENGTH 255 + +#define TWOWIRE_MAX_I2C_CHANNELS (3) // IIC0 to IIC2 +#define TWOWIRE_MAX_SCI_CHANNELS (10) // SCI0 to SCI9 + +#ifdef __cplusplus + +#ifndef __ARDUINO_WIRE_IMPLEMENTATION__ +#define __ARDUINO_WIRE_IMPLEMENTATION__ + +// WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + +#define END_TX_OK 0 +#define END_TX_DATA_TOO_LONG 1 +#define END_TX_NACK_ON_ADD 2 +#define END_TX_NACK_ON_DATA 3 +#define END_TX_ERR_FSP 4 +#define END_TX_TIMEOUT 5 +#define END_TX_NOT_INIT 6 + + +typedef enum { + ADDRESS_MODE_7_BITS, + ADDRESS_MODE_10_BITS +} WireAddressMode_t; + +typedef enum { + WIRE_STATUS_UNSET, + WIRE_STATUS_RX_COMPLETED, + WIRE_STATUS_TX_COMPLETED, + WIRE_STATUS_TRANSACTION_ABORTED, + WIRE_STATUS_RX_REQUEST, + WIRE_STATUS_TX_REQUEST, + WIRE_STATUS_GENERAL_CALL +} WireStatus_t; + +class TwoWire : public arduino::HardwareI2C { + + public: + TwoWire(int scl_pin, int sda_pin, WireAddressMode_t am = ADDRESS_MODE_7_BITS, bool prefer_sci = false); + void begin(); + void begin(uint8_t); + void begin(uint16_t); + void begin(int); + void end(); + void setClock(uint32_t); + + void setWireTimeout(uint32_t timeout = 25000, bool reset_with_timeout = false); + bool getWireTimeoutFlag(void); + void clearWireTimeoutFlag(void); + + void beginTransmission(uint32_t); + void beginTransmission(uint16_t); + void beginTransmission(uint8_t); + void beginTransmission(int); + + uint8_t endTransmission(void); + uint8_t endTransmission(bool); + size_t requestFrom(uint8_t, size_t); + size_t requestFrom(uint8_t, size_t, bool); + size_t requestFrom(uint8_t, size_t, uint32_t, uint8_t, uint8_t); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *, size_t); + virtual int available(void); + virtual int read(void); + virtual int peek(void); + virtual void flush(void); + void onReceive( void (*)(int) ); + void onRequest( void (*)(void) ); + + void setBusStatus(WireStatus_t); + + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } + using Print::write; + + volatile uint32_t tmp_i = 0; + + void cpy_rx_buffer(uint32_t h) { + memcpy(rx_buffer,tmp_buff,h); + rx_index = h; + tmp_i = 0; + rx_extract_index = 0; + memset(tmp_buff, 0x00,I2C_BUFFER_LENGTH); + } + + fsp_err_t slave_read(volatile uint32_t d) { + if(s_read != nullptr) { + return s_read(&s_i2c_ctrl,tmp_buff + tmp_i,d); + } + else { + return FSP_ERR_ASSERTION; + } + } + + private: + + static TwoWire *g_SCIWires[TWOWIRE_MAX_SCI_CHANNELS]; + static TwoWire *g_I2CWires[TWOWIRE_MAX_I2C_CHANNELS]; + + static void WireSCIMasterCallback(i2c_master_callback_args_t *); + static void WireMasterCallback(i2c_master_callback_args_t *); + static void WireSlaveCallback(i2c_slave_callback_args_t *); + + void _begin(); + + int scl_pin; + int sda_pin; + bool init_ok; + bool is_master; + int channel; + bool is_sci; + WireAddressMode_t address_mode; + + uint32_t timeout_us; + volatile bool timed_out_flag; + bool do_reset_on_timeout; + + void handleTimeout(bool reset); + + bool transmission_begun; + bool data_too_long; + + volatile WireStatus_t bus_status; + + sci_i2c_extended_cfg_t m_sci_i2c_extend; + + iic_master_extended_cfg_t m_i2c_extend; + iic_master_instance_ctrl_t m_i2c_ctrl; + i2c_master_cfg_t m_i2c_cfg; + + iic_slave_instance_ctrl_t s_i2c_ctrl; + i2c_slave_cfg_t s_i2c_cfg; + uint16_t slave_address; + + uint32_t master_tx_address; + + I2C_masterOpen_f m_open = nullptr; + I2C_masterRead_f m_read = nullptr; + I2C_masterWrite_f m_write = nullptr; + I2C_masterAbort_f m_abort = nullptr; + I2C_masterSetSlaveAdd_f m_setSlaveAdd = nullptr; + I2C_masterSetCallBack_f m_setCallback = nullptr; + I2C_masterGetStatus_f m_getStatus = nullptr; + I2C_masterClose_f m_close = nullptr; + + I2C_slaveOpen_f s_open = nullptr; + I2C_slaveRead_f s_read = nullptr; + I2C_slaveWrite_f s_write = nullptr; + I2C_slaveSetCallBack_f s_setCallback = nullptr; + I2C_slaveClose_f s_close = nullptr; + + uint8_t tmp_buff[I2C_BUFFER_LENGTH]; + uint8_t tx_buffer[I2C_BUFFER_LENGTH]; + uint8_t rx_buffer[I2C_BUFFER_LENGTH]; + size_t rx_index; + size_t tx_index; + uint8_t rx_extract_index; + + bool require_sci; + + uint8_t read_from(uint8_t, uint8_t*, uint8_t, uint32_t, bool); + uint8_t write_to(uint8_t, uint8_t*, uint8_t, uint32_t, bool); + + bool cfg_pins(int max_index); + + I2C_onRxCallback_f rx_callback; + I2C_onTxCallback_f tx_callback; + +}; + +#if WIRE_HOWMANY > 0 +extern TwoWire Wire; +#endif +#if WIRE_HOWMANY > 1 +extern TwoWire Wire1; +#endif +#if WIRE_HOWMANY > 2 +extern TwoWire Wire2; +#endif +#if WIRE_HOWMANY > 3 +extern TwoWire Wire3; +#endif + +#endif +#endif From 8b59e618983e0bbe821d1290f30b92ad84b55c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Wed, 8 Oct 2025 18:22:26 +0200 Subject: [PATCH 04/14] Added support for I2C timeout handling in Wire --- libraries/Wire/Wire.h | 238 ------------------------------------------ 1 file changed, 238 deletions(-) delete mode 100644 libraries/Wire/Wire.h diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h deleted file mode 100644 index 88ff8d652..000000000 --- a/libraries/Wire/Wire.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - - -#define _TIMEVAL_DEFINED -#define _SYS_SELECT_H - -#include "Arduino.h" -#include "IRQManager.h" -#include "api/HardwareI2C.h" -#include "api/Stream.h" -#include - -#include "bsp_api.h" - -#include "r_iic_master.h" -#include "r_sci_i2c.h" -#include "r_i2c_master_api.h" -#include "r_i2c_slave_api.h" - -extern "C" { - void i2c_callback(i2c_master_callback_args_t *p_args); -} - -using I2C_masterOpen_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, i2c_master_cfg_t const *const p_cfg); -using I2C_masterRead_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint8_t *const p_dest, uint32_t const bytes, bool const restart); -using I2C_masterWrite_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint8_t *constp_src, uint32_t const bytes, bool const restart); -using I2C_masterAbort_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl); -using I2C_masterSetSlaveAdd_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint32_t const slave, i2c_master_addr_mode_t const addr_mode); -using I2C_masterSetCallBack_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, void(*p_callback)(i2c_master_callback_args_t *), void const *const p_context, i2c_master_callback_args_t *const p_callback_memory); -using I2C_masterGetStatus_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, i2c_master_status_t *p_status); -using I2C_masterClose_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl); - -using I2C_slaveOpen_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, i2c_slave_cfg_t const *const p_cfg); -using I2C_slaveRead_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, uint8_t *const p_dest, uint32_t const bytes); -using I2C_slaveWrite_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, uint8_t *const p_src, uint32_t const bytes); -using I2C_slaveSetCallBack_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, void(*p_callback)(i2c_slave_callback_args_t *), void const *const p_context, i2c_slave_callback_args_t *const p_callback_memory); -using I2C_slaveClose_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl); - -using I2C_onRxCallback_f = void (*)(int); -using I2C_onTxCallback_f = void (*)(void); - - -#define I2C_BUFFER_LENGTH 255 - -#define TWOWIRE_MAX_I2C_CHANNELS (3) // IIC0 to IIC2 -#define TWOWIRE_MAX_SCI_CHANNELS (10) // SCI0 to SCI9 - -#ifdef __cplusplus - -#ifndef __ARDUINO_WIRE_IMPLEMENTATION__ -#define __ARDUINO_WIRE_IMPLEMENTATION__ - -// WIRE_HAS_END means Wire has end() -#define WIRE_HAS_END 1 - -#define END_TX_OK 0 -#define END_TX_DATA_TOO_LONG 1 -#define END_TX_NACK_ON_ADD 2 -#define END_TX_NACK_ON_DATA 3 -#define END_TX_ERR_FSP 4 -#define END_TX_TIMEOUT 5 -#define END_TX_NOT_INIT 6 - - -typedef enum { - ADDRESS_MODE_7_BITS, - ADDRESS_MODE_10_BITS -} WireAddressMode_t; - -typedef enum { - WIRE_STATUS_UNSET, - WIRE_STATUS_RX_COMPLETED, - WIRE_STATUS_TX_COMPLETED, - WIRE_STATUS_TRANSACTION_ABORTED, - WIRE_STATUS_RX_REQUEST, - WIRE_STATUS_TX_REQUEST, - WIRE_STATUS_GENERAL_CALL -} WireStatus_t; - -class TwoWire : public arduino::HardwareI2C { - - public: - TwoWire(int scl_pin, int sda_pin, WireAddressMode_t am = ADDRESS_MODE_7_BITS, bool prefer_sci = false); - void begin(); - void begin(uint8_t); - void begin(uint16_t); - void begin(int); - void end(); - void setClock(uint32_t); - - void beginTransmission(uint32_t); - void beginTransmission(uint16_t); - void beginTransmission(uint8_t); - void beginTransmission(int); - - uint8_t endTransmission(void); - uint8_t endTransmission(bool); - size_t requestFrom(uint8_t, size_t); - size_t requestFrom(uint8_t, size_t, bool); - size_t requestFrom(uint8_t, size_t, uint32_t, uint8_t, uint8_t); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *, size_t); - virtual int available(void); - virtual int read(void); - virtual int peek(void); - virtual void flush(void); - void onReceive( void (*)(int) ); - void onRequest( void (*)(void) ); - - void setBusStatus(WireStatus_t); - - inline size_t write(unsigned long n) { return write((uint8_t)n); } - inline size_t write(long n) { return write((uint8_t)n); } - inline size_t write(unsigned int n) { return write((uint8_t)n); } - inline size_t write(int n) { return write((uint8_t)n); } - using Print::write; - - volatile uint32_t tmp_i = 0; - - void cpy_rx_buffer(uint32_t h) { - memcpy(rx_buffer,tmp_buff,h); - rx_index = h; - tmp_i = 0; - rx_extract_index = 0; - memset(tmp_buff, 0x00,I2C_BUFFER_LENGTH); - } - - fsp_err_t slave_read(volatile uint32_t d) { - if(s_read != nullptr) { - return s_read(&s_i2c_ctrl,tmp_buff + tmp_i,d); - } - else { - return FSP_ERR_ASSERTION; - } - } - - private: - - static TwoWire *g_SCIWires[TWOWIRE_MAX_SCI_CHANNELS]; - static TwoWire *g_I2CWires[TWOWIRE_MAX_I2C_CHANNELS]; - - static void WireSCIMasterCallback(i2c_master_callback_args_t *); - static void WireMasterCallback(i2c_master_callback_args_t *); - static void WireSlaveCallback(i2c_slave_callback_args_t *); - - void _begin(); - - int scl_pin; - int sda_pin; - bool init_ok; - bool is_master; - int channel; - bool is_sci; - WireAddressMode_t address_mode; - - unsigned int timeout; - bool transmission_begun; - bool data_too_long; - - volatile WireStatus_t bus_status; - - sci_i2c_extended_cfg_t m_sci_i2c_extend; - - iic_master_extended_cfg_t m_i2c_extend; - iic_master_instance_ctrl_t m_i2c_ctrl; - i2c_master_cfg_t m_i2c_cfg; - - iic_slave_instance_ctrl_t s_i2c_ctrl; - i2c_slave_cfg_t s_i2c_cfg; - uint16_t slave_address; - - uint32_t master_tx_address; - - I2C_masterOpen_f m_open = nullptr; - I2C_masterRead_f m_read = nullptr; - I2C_masterWrite_f m_write = nullptr; - I2C_masterAbort_f m_abort = nullptr; - I2C_masterSetSlaveAdd_f m_setSlaveAdd = nullptr; - I2C_masterSetCallBack_f m_setCallback = nullptr; - I2C_masterGetStatus_f m_getStatus = nullptr; - I2C_masterClose_f m_close = nullptr; - - I2C_slaveOpen_f s_open = nullptr; - I2C_slaveRead_f s_read = nullptr; - I2C_slaveWrite_f s_write = nullptr; - I2C_slaveSetCallBack_f s_setCallback = nullptr; - I2C_slaveClose_f s_close = nullptr; - - uint8_t tmp_buff[I2C_BUFFER_LENGTH]; - uint8_t tx_buffer[I2C_BUFFER_LENGTH]; - uint8_t rx_buffer[I2C_BUFFER_LENGTH]; - size_t rx_index; - size_t tx_index; - uint8_t rx_extract_index; - - bool require_sci; - - uint8_t read_from(uint8_t, uint8_t*, uint8_t, unsigned int, bool); - uint8_t write_to(uint8_t, uint8_t*, uint8_t, unsigned int, bool); - - bool cfg_pins(int max_index); - - I2C_onRxCallback_f rx_callback; - I2C_onTxCallback_f tx_callback; - -}; - -#if WIRE_HOWMANY > 0 -extern TwoWire Wire; -#endif -#if WIRE_HOWMANY > 1 -extern TwoWire Wire1; -#endif -#if WIRE_HOWMANY > 2 -extern TwoWire Wire2; -#endif -#if WIRE_HOWMANY > 3 -extern TwoWire Wire3; -#endif - -#endif -#endif \ No newline at end of file From ded4ed91116241e14bb9a0f64d432022c2e16a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Wed, 8 Oct 2025 18:23:05 +0200 Subject: [PATCH 05/14] Added support for I2C timeout handling in Wire --- libraries/Wire/Wire.cpp | 857 ---------------------------------------- 1 file changed, 857 deletions(-) delete mode 100644 libraries/Wire/Wire.cpp diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp deleted file mode 100644 index 1cb6aa7f3..000000000 --- a/libraries/Wire/Wire.cpp +++ /dev/null @@ -1,857 +0,0 @@ -/* - TwoWire.cpp - TWI/I2C library for Wiring & Arduino - Copyright (c) 2006 Nicholas Zambetti. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts - Modified 2017 by Chuck Todd (ctodd@cableone.net) to correct Unconfigured Slave Mode reboot - - Version 2022 for Renesas RA4 by Daniele Aimo (d.aimo@arduino.cc) -*/ - -extern "C" { - #include - #include - #include -} - -#include "Wire.h" - -TwoWire *TwoWire::g_SCIWires[TWOWIRE_MAX_SCI_CHANNELS] = {nullptr}; -TwoWire *TwoWire::g_I2CWires[TWOWIRE_MAX_I2C_CHANNELS] = {nullptr}; - -/* -------------------------------------------------------------------------- */ -void TwoWire::setBusStatus(WireStatus_t ws) { -/* -------------------------------------------------------------------------- */ - bus_status = ws; -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::WireSCIMasterCallback(i2c_master_callback_args_t *arg) { -/* -------------------------------------------------------------------------- */ - /* +++++ MASTER I2C SCI Callback ++++++ */ - - i2c_master_cfg_t *cfg = (i2c_master_cfg_t *)arg->p_context; - - TwoWire *ptr = nullptr; - if(cfg->channel < TWOWIRE_MAX_SCI_CHANNELS) { - ptr = g_SCIWires[cfg->channel]; - } - - if(ptr == nullptr) { - return; - } - if(!ptr->init_ok) { - return; - } - - if(ptr != nullptr) { - if(arg->event == I2C_MASTER_EVENT_ABORTED) { - ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); - } - else if(arg->event == I2C_MASTER_EVENT_RX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); - } - else if(arg->event == I2C_MASTER_EVENT_TX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); - } - } - -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::WireMasterCallback(i2c_master_callback_args_t *arg) { -/* -------------------------------------------------------------------------- */ - /* +++++ MASTER I2C not SCI Callback ++++++ */ - i2c_master_cfg_t *cfg = (i2c_master_cfg_t *)arg->p_context; - - TwoWire *ptr = nullptr; - if(cfg->channel < TWOWIRE_MAX_I2C_CHANNELS) { - ptr = g_I2CWires[cfg->channel]; - } - - if(ptr == nullptr) { - return; - } - if(!ptr->init_ok) { - return; - } - - if(ptr != nullptr) { - if(arg->event == I2C_MASTER_EVENT_ABORTED) { - ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); - } - else if(arg->event == I2C_MASTER_EVENT_RX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); - } - else if(arg->event == I2C_MASTER_EVENT_TX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); - } - } -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::WireSlaveCallback(i2c_slave_callback_args_t *arg) { -/* -------------------------------------------------------------------------- */ - /* +++++ SLAVE Callback ++++++ */ - volatile uint32_t bytes = arg->bytes; - volatile i2c_slave_cfg_t *cfg = (i2c_slave_cfg_t *)arg->p_context; - - TwoWire *ptr = nullptr; - if(cfg->channel < TWOWIRE_MAX_I2C_CHANNELS) { - ptr = g_I2CWires[cfg->channel]; - } - - if(ptr == nullptr) { - return; - } - if(!ptr->init_ok) { - return; - } - - if(arg->event == I2C_SLAVE_EVENT_ABORTED) { - ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); - } - else if(arg->event == I2C_SLAVE_EVENT_RX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); - - ptr->cpy_rx_buffer(bytes); - if(ptr->rx_callback != nullptr) { - ptr->rx_callback(bytes); - } - } - else if(arg->event == I2C_SLAVE_EVENT_TX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); - } - else if(arg->event == I2C_SLAVE_EVENT_RX_REQUEST) { - ptr->setBusStatus(WIRE_STATUS_RX_REQUEST); - if(ptr->tmp_i + bytes < I2C_BUFFER_LENGTH) { - volatile fsp_err_t err; - err = ptr->slave_read(1); - if(err == FSP_SUCCESS) { - ptr->tmp_i += 1; - } - } - else { - ptr->slave_read(0); - } - } - else if(arg->event == I2C_SLAVE_EVENT_TX_REQUEST) { - ptr->setBusStatus(WIRE_STATUS_TX_REQUEST); - - if(ptr->tx_callback != nullptr) { - ptr->tx_callback(); - } - } - else if(arg->event == I2C_SLAVE_EVENT_RX_MORE_REQUEST) { - ptr->setBusStatus(WIRE_STATUS_RX_REQUEST); - - if(ptr->tmp_i + bytes < I2C_BUFFER_LENGTH) { - volatile fsp_err_t err; - err = ptr->slave_read(bytes); - if(err == FSP_SUCCESS) { - ptr->tmp_i += bytes; - } - } - else { - ptr->slave_read(0); - } - } - else if(arg->event == I2C_SLAVE_EVENT_TX_MORE_REQUEST) { - ptr->setBusStatus(WIRE_STATUS_TX_REQUEST); - if(ptr->tx_callback != nullptr) { - ptr->tx_callback(); - } - } - else if(arg->event == I2C_SLAVE_EVENT_GENERAL_CALL) { - ptr->setBusStatus(WIRE_STATUS_GENERAL_CALL); - } - -} - - -/* -------------------------------------------------------------------------- */ -TwoWire::TwoWire(int scl, int sda, WireAddressMode_t am /*= ADDRESS_MODE_7_BITS*/, bool prefer_sci /*= false*/) : - scl_pin(scl), - sda_pin(sda), - init_ok(false), - is_master(true), - is_sci(false), - address_mode(am), - timeout(1000), - transmission_begun(false), - data_too_long(false), - rx_index(0), - tx_index(0), - require_sci(prefer_sci) { -/* -------------------------------------------------------------------------- */ - m_i2c_cfg.rxi_irq = FSP_INVALID_VECTOR; - m_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; - m_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; - m_i2c_cfg.eri_irq = FSP_INVALID_VECTOR; - - s_i2c_cfg.rxi_irq = FSP_INVALID_VECTOR; - s_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; - s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; - s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; -} - -/* -------------------------------------------------------------------------- */ -bool TwoWire::cfg_pins(int max_index) { -/* -------------------------------------------------------------------------- */ - /* verify index are good */ - if(scl_pin < 0 || sda_pin < 0 || scl_pin >= max_index || sda_pin >= max_index) { - return false; - } - /* getting configuration from table */ - auto cfgs_scl = getPinCfgs(scl_pin, PIN_CFG_REQ_SCL); - auto cfgs_sda = getPinCfgs(sda_pin, PIN_CFG_REQ_SDA); - - uint16_t cfg_scl = 0; - uint16_t cfg_sda = 0; - - /* Find the best combination */ - for (size_t i = 0; i < cfgs_scl.size(); i++) { - for (size_t j = 0; j < cfgs_sda.size(); j++) { - if (cfgs_scl[i] && cfgs_sda[j] && (GET_CHANNEL(cfgs_scl[i]) == GET_CHANNEL(cfgs_sda[j])) && (IS_SCI(cfgs_scl[i]) == IS_SCI(cfgs_sda[j]))) { - cfg_scl = cfgs_scl[i]; - cfg_sda = cfgs_sda[j]; - channel = GET_CHANNEL(cfg_scl); - goto done; - } - } - } - -done: - if (cfg_sda == 0 || cfg_scl == 0) { - return false; - } - - /* actually configuring PIN function */ - ioport_peripheral_t ioport_sda; - ioport_peripheral_t ioport_scl; - - if(IS_SCI(cfg_sda)) { - if(channel >= TWOWIRE_MAX_SCI_CHANNELS) { // channels are 0 index based - return false; - } - is_sci = true; - ioport_sda = USE_SCI_EVEN_CFG(cfg_sda) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9; - ioport_scl = USE_SCI_EVEN_CFG(cfg_scl) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9; - - R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[sda_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_PERIPHERAL_PIN | ioport_sda)); - R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[scl_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_PERIPHERAL_PIN | ioport_scl)); - - } - else { - if(channel >= TWOWIRE_MAX_I2C_CHANNELS) { // channels are 0 index based - return false; - } - is_sci = false; - ioport_sda = IOPORT_PERIPHERAL_IIC; - ioport_scl = IOPORT_PERIPHERAL_IIC; - - R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[sda_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_DRIVE_MID | IOPORT_CFG_PERIPHERAL_PIN | ioport_sda)); - R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[scl_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_DRIVE_MID | IOPORT_CFG_PERIPHERAL_PIN | ioport_scl)); - } - - return true; -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::begin(void) { -/* -------------------------------------------------------------------------- */ - end(); - is_master = true; - _begin(); - -} - - -/* -------------------------------------------------------------------------- */ -void TwoWire::_begin(void) { -/* -------------------------------------------------------------------------- */ - init_ok = true; - int max_index = PINS_COUNT; - - init_ok &= cfg_pins(max_index); - - if(init_ok) { - - /* ----------------------------------- - ->>>>> MASTER initialization - * ----------------------------------- */ - if(is_master) { - - setClock(I2C_MASTER_RATE_STANDARD); - - if(is_sci) { - TwoWire::g_SCIWires[channel] = this; - - m_open = R_SCI_I2C_Open; - m_read = R_SCI_I2C_Read; - m_write = R_SCI_I2C_Write; - m_abort = R_SCI_I2C_Abort; - m_setSlaveAdd = R_SCI_I2C_SlaveAddressSet; - m_setCallback = R_SCI_I2C_CallbackSet; - m_getStatus = R_SCI_I2C_StatusGet; - m_close = R_SCI_I2C_Close; - - m_i2c_cfg.p_extend = &m_sci_i2c_extend; - m_i2c_cfg.p_callback = WireSCIMasterCallback; - } - else { - TwoWire::g_I2CWires[channel] = this; - - m_open = R_IIC_MASTER_Open; - m_read = R_IIC_MASTER_Read; - m_write = R_IIC_MASTER_Write; - m_abort = R_IIC_MASTER_Abort; - m_setSlaveAdd = R_IIC_MASTER_SlaveAddressSet; - m_setCallback = R_IIC_MASTER_CallbackSet; - m_getStatus = R_IIC_MASTER_StatusGet; - m_close = R_IIC_MASTER_Close; - - m_i2c_cfg.p_extend = &m_i2c_extend; - m_i2c_cfg.p_callback = WireMasterCallback; - - m_i2c_extend.timeout_mode = IIC_MASTER_TIMEOUT_MODE_SHORT; - m_i2c_extend.timeout_scl_low = IIC_MASTER_TIMEOUT_SCL_LOW_DISABLED; - } - - m_i2c_cfg.channel = channel; - m_i2c_cfg.rate = I2C_MASTER_RATE_STANDARD; - m_i2c_cfg.slave = 0x00; - m_i2c_cfg.addr_mode = (address_mode == ADDRESS_MODE_7_BITS) ? I2C_MASTER_ADDR_MODE_7BIT : I2C_MASTER_ADDR_MODE_10BIT; - m_i2c_cfg.p_transfer_tx = NULL; - m_i2c_cfg.p_transfer_rx = NULL; - - m_i2c_cfg.p_context = &m_i2c_cfg; - m_i2c_cfg.ipl = (12); - - } // if(is_master) { - /* ----------------------------------- - ->>>>> SLAVE initialization - * ----------------------------------- */ - else { - /* a slave device cannot be instatiated on SCI peripheral */ - if(is_sci) { - init_ok = false; - return; - } - TwoWire::g_I2CWires[channel] = this; - - s_open = R_IIC_SLAVE_Open; - s_read = R_IIC_SLAVE_Read; - s_write = R_IIC_SLAVE_Write; - s_setCallback = R_IIC_SLAVE_CallbackSet; - s_close = R_IIC_SLAVE_Close; - - s_i2c_cfg.channel = channel; - s_i2c_cfg.rate = I2C_SLAVE_RATE_STANDARD; - s_i2c_cfg.slave = slave_address; - s_i2c_cfg.addr_mode = (address_mode == ADDRESS_MODE_7_BITS) ? I2C_SLAVE_ADDR_MODE_7BIT : I2C_SLAVE_ADDR_MODE_10BIT; - s_i2c_cfg.general_call_enable = false; - s_i2c_cfg.ipl = (12); - s_i2c_cfg.eri_ipl = (12); - s_i2c_cfg.clock_stretching_enable = false; - s_i2c_cfg.p_callback = WireSlaveCallback; - s_i2c_cfg.p_context = &s_i2c_cfg; - s_i2c_cfg.p_extend = NULL; - } - } - else { - init_ok = false; - return; - } - - I2CIrqReq_t irq_req; - irq_req.mcfg = &m_i2c_cfg; - irq_req.scfg = &s_i2c_cfg; - - if(is_master) { - if(is_sci) { - init_ok &= IRQManager::getInstance().addPeripheral(IRQ_SCI_I2C_MASTER,&irq_req); - } - else { - init_ok &= IRQManager::getInstance().addPeripheral(IRQ_I2C_MASTER,&irq_req); - } - if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { - init_ok &= true; - } - else { - init_ok = false; - } - } - else { - init_ok &= IRQManager::getInstance().addPeripheral(IRQ_I2C_SLAVE,&irq_req); - if(FSP_SUCCESS == s_open(&s_i2c_ctrl,&s_i2c_cfg)) { - init_ok &= true; - } - else { - init_ok = false; - } - } -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::begin(uint16_t address) { -/* -------------------------------------------------------------------------- */ - end(); - is_master = false; - slave_address = address; - /* Address is set inside begin() using slave_address member variable */ - _begin(); - -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::begin(int address) { -/* -------------------------------------------------------------------------- */ - begin((uint16_t)address); -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::begin(uint8_t address) { -/* -------------------------------------------------------------------------- */ - begin((uint16_t)address); -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::end(void) { -/* -------------------------------------------------------------------------- */ - - if(init_ok) { - if(is_master) { - if(m_close != nullptr) { - R_BSP_IrqDisable (m_i2c_cfg.txi_irq); - R_BSP_IrqDisable (m_i2c_cfg.rxi_irq); - R_BSP_IrqDisable (m_i2c_cfg.tei_irq); - R_BSP_IrqDisable (m_i2c_cfg.eri_irq); - m_close(&m_i2c_ctrl); - } - } - else { - if(s_close != nullptr) { - R_BSP_IrqDisable (s_i2c_cfg.txi_irq); - R_BSP_IrqDisable (s_i2c_cfg.rxi_irq); - R_BSP_IrqDisable (s_i2c_cfg.tei_irq); - R_BSP_IrqDisable (s_i2c_cfg.eri_irq); - s_close(&s_i2c_ctrl); - - } - } - } - /* fix for slave that create a sort of lock on the I2C bus when end is called and the master - is not more able to get the I2C buse working */ - R_IOPORT_PinCfg(NULL, g_pin_cfg[sda_pin].pin, IOPORT_CFG_PORT_DIRECTION_INPUT | IOPORT_CFG_PULLUP_ENABLE); - R_IOPORT_PinCfg(NULL, g_pin_cfg[scl_pin].pin, IOPORT_CFG_PORT_DIRECTION_INPUT | IOPORT_CFG_PULLUP_ENABLE); - init_ok = false; -} - - - -/* -------------------------------------------------------------------------- */ -uint8_t TwoWire::read_from(uint8_t address, uint8_t* data, uint8_t length, unsigned int timeout_ms, bool sendStop) { -/* -------------------------------------------------------------------------- */ - /* ??? does this function make sense only for MASTER ???? */ - - fsp_err_t err = FSP_ERR_ASSERTION; - if(init_ok) { - if(m_setSlaveAdd != nullptr) { - err = m_setSlaveAdd(&m_i2c_ctrl, address, m_i2c_cfg.addr_mode); - } - if(err == FSP_SUCCESS) { - if(m_read != nullptr) { - bus_status = WIRE_STATUS_UNSET; - err = m_read(&m_i2c_ctrl,data,length,!sendStop); - } - } - uint32_t const start = millis(); - while(((millis() - start) < timeout_ms) && bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { - - } - } - - if(bus_status == WIRE_STATUS_RX_COMPLETED) { - return length; - } - - return 0; /* ???????? return value ??????? */ -} - -/* -------------------------------------------------------------------------- */ -uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, unsigned int timeout_ms, bool sendStop) { -/* -------------------------------------------------------------------------- */ - uint8_t rv = END_TX_OK; - fsp_err_t err = FSP_ERR_ASSERTION; - if(init_ok) { - if(m_setSlaveAdd != nullptr) { - err = m_setSlaveAdd(&m_i2c_ctrl, address, m_i2c_cfg.addr_mode); - } - if(err == FSP_SUCCESS) { - if(m_write != nullptr) { - bus_status = WIRE_STATUS_UNSET; - err = m_write(&m_i2c_ctrl,data,length,!sendStop); - } - } - uint32_t const start = millis(); - while(((millis() - start) < timeout_ms) && bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { - - } - - if(err != FSP_SUCCESS) { - rv = END_TX_ERR_FSP; - } - else if(data_too_long) { - rv = END_TX_DATA_TOO_LONG; - } - else if(bus_status == WIRE_STATUS_UNSET) { - rv = END_TX_TIMEOUT; - } - /* as far as I know is impossible to distinguish between NACK on ADDRESS and - NACK on DATA */ - else if(bus_status == WIRE_STATUS_TRANSACTION_ABORTED) { - rv = END_TX_NACK_ON_ADD; - } - } - else { - rv = END_TX_NOT_INIT; - } - - - return rv; -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::setClock(uint32_t freq) { -/* -------------------------------------------------------------------------- */ - if(init_ok && is_master) { - if(m_close != nullptr) { - m_close(&m_i2c_ctrl); - } - } - - if(is_master) { - m_i2c_cfg.rate = (i2c_master_rate_t)freq; - - int clock_divisor = (R_FSP_SystemClockHzGet(BSP_FEATURE_SCI_CLOCK) / 48000000u) - 1; - - if (is_sci) { - m_sci_i2c_extend.clock_settings.clk_divisor_value = 0; - m_sci_i2c_extend.clock_settings.cycles_value = 15; - m_sci_i2c_extend.clock_settings.snfr_value = (1); - switch (m_i2c_cfg.rate) { - case I2C_MASTER_RATE_STANDARD: - m_sci_i2c_extend.clock_settings.brr_value = 14; - m_sci_i2c_extend.clock_settings.mddr_value = 255; - m_sci_i2c_extend.clock_settings.bitrate_modulation = false; - break; - case I2C_MASTER_RATE_FAST: - default: - m_sci_i2c_extend.clock_settings.brr_value = 2; - m_sci_i2c_extend.clock_settings.mddr_value = 204; - m_sci_i2c_extend.clock_settings.bitrate_modulation = true; - break; - } - } else { - switch (m_i2c_cfg.rate) { - case I2C_MASTER_RATE_STANDARD: - m_i2c_extend.clock_settings.brl_value = 27; - m_i2c_extend.clock_settings.brh_value = 26; - m_i2c_extend.clock_settings.cks_value = 2 + clock_divisor; - break; - case I2C_MASTER_RATE_FAST: - m_i2c_extend.clock_settings.brl_value = 16; - m_i2c_extend.clock_settings.brh_value = 15; - m_i2c_extend.clock_settings.cks_value = 0 + clock_divisor; - break; -#if BSP_FEATURE_IIC_FAST_MODE_PLUS - case I2C_MASTER_RATE_FASTPLUS: - m_i2c_extend.clock_settings.brl_value = 6; - m_i2c_extend.clock_settings.brh_value = 5; - m_i2c_extend.clock_settings.cks_value = 0; - break; -#endif - } - } - } - - if(init_ok) { - if(m_open != nullptr) { - if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { - init_ok &= true; - } - else { - init_ok = false; - } - } - } -} - -/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * TRANSMISSION BEGIN - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - -/* -------------------------------------------------------------------------- */ -void TwoWire::beginTransmission(uint32_t address) { -/* -------------------------------------------------------------------------- */ - if (init_ok) { - data_too_long = false; - master_tx_address = address; - transmission_begun = true; - tx_index = 0; - } -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::beginTransmission(uint16_t address) { -/* -------------------------------------------------------------------------- */ - beginTransmission((uint32_t)address); -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::beginTransmission(uint8_t address){ -/* -------------------------------------------------------------------------- */ - beginTransmission((uint32_t)address); -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::beginTransmission(int address) { -/* -------------------------------------------------------------------------- */ - beginTransmission((uint32_t)address); -} - -/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * TRANSMISSION END - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - -/* -------------------------------------------------------------------------- */ -uint8_t TwoWire::endTransmission(bool sendStop) { -/* -------------------------------------------------------------------------- */ - uint8_t ret = write_to(master_tx_address, tx_buffer, tx_index, timeout, sendStop); - transmission_begun = false; - return ret; -} - -/* -------------------------------------------------------------------------- */ -uint8_t TwoWire::endTransmission(void) { -/* -------------------------------------------------------------------------- */ - return endTransmission(true); -} - -/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * REQUEST FROM - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - -/* -------------------------------------------------------------------------- */ -size_t TwoWire::requestFrom(uint8_t address, size_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) { -/* -------------------------------------------------------------------------- */ - if(init_ok) { - - if (isize > 0) { - // send internal address; this mode allows sending a repeated start to access - // some devices' internal registers. This function is executed by the hardware - // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) - - beginTransmission(address); - - // the maximum size of internal address is 3 bytes - if (isize > 3){ - isize = 3; - } - - // write internal register address - most significant byte first - while (isize-- > 0) { - write((uint8_t)(iaddress >> (isize*8))); - } - - endTransmission(false); - } - - // clamp to buffer length - if(quantity > I2C_BUFFER_LENGTH){ - quantity = I2C_BUFFER_LENGTH; - } - // perform blocking read into buffer - uint8_t read = read_from(address, rx_buffer, quantity, timeout, sendStop); - // set rx buffer iterator vars - rx_index = read; - rx_extract_index = 0; - - return (size_t)read; - } - else { - return 0; - } -} - -/* -------------------------------------------------------------------------- */ -size_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool sendStop) { -/* -------------------------------------------------------------------------- */ - return requestFrom((uint8_t)address, quantity, (uint32_t)0, (uint8_t)0, sendStop); -} - -/* -------------------------------------------------------------------------- */ -size_t TwoWire::requestFrom(uint8_t address, size_t quantity) { -/* -------------------------------------------------------------------------- */ - return requestFrom((uint8_t)address, quantity, true); -} - -/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * WRITE - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -/* -------------------------------------------------------------------------- */ -size_t TwoWire::write(uint8_t data) { -/* -------------------------------------------------------------------------- */ - if(init_ok) { - if(is_master) { - if(transmission_begun) { - if(tx_index >= I2C_BUFFER_LENGTH) { - data_too_long = true; - setWriteError(); - return 0; - } - tx_buffer[tx_index] = data; - tx_index++; - } - } - else { - if(s_write != nullptr) { - s_write(&s_i2c_ctrl,(uint8_t *)&data,1); - } - } - return 1; - } - return 0; - -} - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -/* -------------------------------------------------------------------------- */ -size_t TwoWire::write(const uint8_t *data, size_t quantity) { -/* -------------------------------------------------------------------------- */ - if(init_ok) { - if(is_master) { - // in master transmitter mode - for(size_t i = 0; i < quantity; ++i){ - write(data[i]); - } - } - else{ - if(s_write != nullptr) { - s_write(&s_i2c_ctrl,(uint8_t *)data,quantity); - } - } - return quantity; - } - else { - return 0; - } -} - - -// sets function called on slave write -/* -------------------------------------------------------------------------- */ -void TwoWire::onReceive( I2C_onRxCallback_f f ) { -/* -------------------------------------------------------------------------- */ - rx_callback = f; -} - -// sets function called on slave read -/* -------------------------------------------------------------------------- */ -void TwoWire::onRequest( I2C_onTxCallback_f f ) { -/* -------------------------------------------------------------------------- */ - tx_callback = f; -} - - - -// must be called in: -// slave rx event callback -// or after requestFrom(address, numBytes) - -/* -------------------------------------------------------------------------- */ -int TwoWire::available(void) { -/* -------------------------------------------------------------------------- */ - return rx_index - rx_extract_index; -} - -// must be called in: -// slave rx event callback -// or after requestFrom(address, numBytes) -/* -------------------------------------------------------------------------- */ -int TwoWire::read(void) { -/* -------------------------------------------------------------------------- */ - int rv = -1; - - // get each successive byte on each call - if(rx_extract_index < rx_index){ - rv = rx_buffer[rx_extract_index]; - rx_extract_index++; - } - - return rv; -} - -// must be called in: -// slave rx event callback -// or after requestFrom(address, numBytes) -/* -------------------------------------------------------------------------- */ -int TwoWire::peek(void) { -/* -------------------------------------------------------------------------- */ - int rv = -1; - - // get each successive byte on each call - if(rx_extract_index < rx_index){ - rv = rx_buffer[rx_extract_index]; - } - - return rv; -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::flush(void) { -/* -------------------------------------------------------------------------- */ - while(bus_status != WIRE_STATUS_TX_COMPLETED && bus_status != WIRE_STATUS_TRANSACTION_ABORTED) {} -} - - - - -#if WIRE_HOWMANY > 0 -TwoWire Wire(WIRE_SCL_PIN, WIRE_SDA_PIN); -#endif - -#if WIRE_HOWMANY > 1 -TwoWire Wire1(WIRE1_SCL_PIN, WIRE1_SDA_PIN); -#endif - -#if WIRE_HOWMANY > 2 -TwoWire Wire2(WIRE2_SCL_PIN, WIRE2_SDA_PIN); -#endif - -#if WIRE_HOWMANY > 3 -TwoWire Wire3(WIRE3_SCL_PIN, WIRE3_SDA_PIN); -#endif - - From 64aa5ad9c2ae7391f876d0b4459d21e5f9b0e958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Thu, 9 Oct 2025 19:12:59 +0200 Subject: [PATCH 06/14] Fixed timeout bug The new logic for the timeout loop in read_from() and write_to() had a bug. It is now fixed. --- libraries/Wire/src/Wire.cpp | 42 ++++++++++++++++++++----------------- libraries/Wire/src/Wire.h | 8 +++++++ 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 63799d6cb..afed9b543 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -30,6 +30,7 @@ extern "C" { #include } +#include "Arduino.h" #include "Wire.h" TwoWire *TwoWire::g_SCIWires[TWOWIRE_MAX_SCI_CHANNELS] = {nullptr}; @@ -211,6 +212,8 @@ TwoWire::TwoWire(int scl, int sda, WireAddressMode_t am /*= ADDRESS_MODE_7_BITS* s_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; + + } /* -------------------------------------------------------------------------- */ @@ -485,12 +488,13 @@ uint8_t TwoWire::read_from(uint8_t address, uint8_t* data, uint8_t length, uint3 } } - while( bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { - uint32_t const start = micros(); - if((timeout_us > 0ul) && ((micros() - start) > timeout_us)) { - handleTimeout(do_reset_on_timeout); - return 0; - } + uint32_t const start = micros(); + while (((timeout_us == 0ul) || ((millis() - start) < timeout_us)) && + bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { + } + if ((err == FSP_SUCCESS) && (bus_status == WIRE_STATUS_UNSET)) { + handleTimeout(do_reset_on_timeout); + return 0; } } @@ -502,7 +506,7 @@ uint8_t TwoWire::read_from(uint8_t address, uint8_t* data, uint8_t length, uint3 } /* -------------------------------------------------------------------------- */ -uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32_t timeout_us /* micros */, bool sendStop) { +uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32_t timeout_us , bool sendStop) { /* -------------------------------------------------------------------------- */ uint8_t rv = END_TX_OK; fsp_err_t err = FSP_ERR_ASSERTION; @@ -517,12 +521,9 @@ uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32 } } - while( bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { - uint32_t const start = micros(); - if((timeout_us > 0ul) && ((micros() - start) > timeout_us)) { - handleTimeout(do_reset_on_timeout); - return END_TX_TIMEOUT; - } + uint32_t const start = micros(); + while (((timeout_us == 0ul) || ((millis() - start) < timeout_us)) && + bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { } if(err != FSP_SUCCESS) { @@ -531,6 +532,10 @@ uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32 else if(data_too_long) { rv = END_TX_DATA_TOO_LONG; } + else if(bus_status == WIRE_STATUS_UNSET) { + rv = END_TX_TIMEOUT; + handleTimeout(do_reset_on_timeout); + } /* as far as I know is impossible to distinguish between NACK on ADDRESS and NACK on DATA */ else if(bus_status == WIRE_STATUS_TRANSACTION_ABORTED) { @@ -675,7 +680,6 @@ void TwoWire::clearWireTimeoutFlag(void){ void TwoWire::handleTimeout(bool reset){ /* -------------------------------------------------------------------------- */ timed_out_flag = true; - if (reset) { //TBD; What do we do here? like fixHungWire()? // TBD, Is this the way to go to reset the bus? // Do we need more to handle devices that hangs the bus? @@ -684,11 +688,11 @@ void TwoWire::handleTimeout(bool reset){ fsp_err_t err = m_abort(&m_i2c_ctrl); } // TDB, Is this the right way to get back after reset? - if(m_open != nullptr) { - if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { - init_ok &= true; - } - } + //if(m_open != nullptr) { + // if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { + // init_ok &= true; + // } + //} } } diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 6ac84e911..a4145c9d2 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -69,6 +69,14 @@ using I2C_onTxCallback_f = void (*)(void); // WIRE_HAS_END means Wire has end() #define WIRE_HAS_END 1 +// WIRE_HAS_TIMEOUT means Wire has setWireTimeout(), getWireTimeoutFlag +// and clearWireTimeoutFlag() +#define WIRE_HAS_TIMEOUT 1 + +// When not configured, these settings are used for the timeout +#define WIRE_DEFAULT_TIMEOUT 25000 +#define WIRE_DEFAULT_RESET_WITH_TIMEOUT 0 + #define END_TX_OK 0 #define END_TX_DATA_TOO_LONG 1 #define END_TX_NACK_ON_ADD 2 From 9ea93da084bf6e0b4c3e6bbcc50d176bb7841cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Thu, 9 Oct 2025 19:22:01 +0200 Subject: [PATCH 07/14] Delete libraries/Wire/keywords.txt --- libraries/Wire/keywords.txt | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 libraries/Wire/keywords.txt diff --git a/libraries/Wire/keywords.txt b/libraries/Wire/keywords.txt deleted file mode 100644 index 8e1482140..000000000 --- a/libraries/Wire/keywords.txt +++ /dev/null @@ -1,26 +0,0 @@ -####################################### -# Syntax Coloring Map For Wire -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -Wire KEYWORD1 -Wire1 KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -begin KEYWORD2 -setClock KEYWORD2 -beginTransmission KEYWORD2 -endTransmission KEYWORD2 -requestFrom KEYWORD2 -onReceive KEYWORD2 -onRequest KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### From 6078e77b7947fcc4e8c2a3e500d33365e7fdf3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Thu, 9 Oct 2025 19:22:13 +0200 Subject: [PATCH 08/14] Delete libraries/Wire/library.properties --- libraries/Wire/library.properties | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 libraries/Wire/library.properties diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties deleted file mode 100644 index 293df5f2b..000000000 --- a/libraries/Wire/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=Wire -version=0.1 -author=Hanz Häger -maintainer=Hanz Häger -sentence=This library allows you to communicate with I2C and Two Wire Interface devices. -paragraph=It allows the communication with I2C devices like temperature sensors, realtime clocks and many others using SDA (Data Line) and SCL (Clock Line). -category=Communication -url= -architectures=renesas,renesas_portenta,renesas_uno -include=Wire.h From b04ee641e9f74c1c316965e0bcaabf72dd6384aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Thu, 9 Oct 2025 19:22:28 +0200 Subject: [PATCH 09/14] Delete libraries/Wire/src/Wire.cpp --- libraries/Wire/src/Wire.cpp | 953 ------------------------------------ 1 file changed, 953 deletions(-) delete mode 100644 libraries/Wire/src/Wire.cpp diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp deleted file mode 100644 index afed9b543..000000000 --- a/libraries/Wire/src/Wire.cpp +++ /dev/null @@ -1,953 +0,0 @@ -/* - TwoWire.cpp - TWI/I2C library for Wiring & Arduino - Copyright (c) 2006 Nicholas Zambetti. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts - Modified 2017 by Chuck Todd (ctodd@cableone.net) to correct Unconfigured Slave Mode reboot - - Version 2022 for Renesas RA4 by Daniele Aimo (d.aimo@arduino.cc) - - Version 2025 by Hanz Häger (hanz.hager+arduino@gmail.com) added timeout interface -*/ - -extern "C" { - #include - #include - #include -} - -#include "Arduino.h" -#include "Wire.h" - -TwoWire *TwoWire::g_SCIWires[TWOWIRE_MAX_SCI_CHANNELS] = {nullptr}; -TwoWire *TwoWire::g_I2CWires[TWOWIRE_MAX_I2C_CHANNELS] = {nullptr}; - -/* -------------------------------------------------------------------------- */ -void TwoWire::setBusStatus(WireStatus_t ws) { -/* -------------------------------------------------------------------------- */ - bus_status = ws; -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::WireSCIMasterCallback(i2c_master_callback_args_t *arg) { -/* -------------------------------------------------------------------------- */ - /* +++++ MASTER I2C SCI Callback ++++++ */ - - i2c_master_cfg_t *cfg = (i2c_master_cfg_t *)arg->p_context; - - TwoWire *ptr = nullptr; - if(cfg->channel < TWOWIRE_MAX_SCI_CHANNELS) { - ptr = g_SCIWires[cfg->channel]; - } - - if(ptr == nullptr) { - return; - } - if(!ptr->init_ok) { - return; - } - - if(ptr != nullptr) { - if(arg->event == I2C_MASTER_EVENT_ABORTED) { - ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); - } - else if(arg->event == I2C_MASTER_EVENT_RX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); - } - else if(arg->event == I2C_MASTER_EVENT_TX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); - } - } - -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::WireMasterCallback(i2c_master_callback_args_t *arg) { -/* -------------------------------------------------------------------------- */ - /* +++++ MASTER I2C not SCI Callback ++++++ */ - i2c_master_cfg_t *cfg = (i2c_master_cfg_t *)arg->p_context; - - TwoWire *ptr = nullptr; - if(cfg->channel < TWOWIRE_MAX_I2C_CHANNELS) { - ptr = g_I2CWires[cfg->channel]; - } - - if(ptr == nullptr) { - return; - } - if(!ptr->init_ok) { - return; - } - - if(ptr != nullptr) { - if(arg->event == I2C_MASTER_EVENT_ABORTED) { - ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); - } - else if(arg->event == I2C_MASTER_EVENT_RX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); - } - else if(arg->event == I2C_MASTER_EVENT_TX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); - } - } -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::WireSlaveCallback(i2c_slave_callback_args_t *arg) { -/* -------------------------------------------------------------------------- */ - /* +++++ SLAVE Callback ++++++ */ - volatile uint32_t bytes = arg->bytes; - volatile i2c_slave_cfg_t *cfg = (i2c_slave_cfg_t *)arg->p_context; - - TwoWire *ptr = nullptr; - if(cfg->channel < TWOWIRE_MAX_I2C_CHANNELS) { - ptr = g_I2CWires[cfg->channel]; - } - - if(ptr == nullptr) { - return; - } - if(!ptr->init_ok) { - return; - } - - if(arg->event == I2C_SLAVE_EVENT_ABORTED) { - ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); - } - else if(arg->event == I2C_SLAVE_EVENT_RX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); - - ptr->cpy_rx_buffer(bytes); - if(ptr->rx_callback != nullptr) { - ptr->rx_callback(bytes); - } - } - else if(arg->event == I2C_SLAVE_EVENT_TX_COMPLETE) { - ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); - } - else if(arg->event == I2C_SLAVE_EVENT_RX_REQUEST) { - ptr->setBusStatus(WIRE_STATUS_RX_REQUEST); - if(ptr->tmp_i + bytes < I2C_BUFFER_LENGTH) { - volatile fsp_err_t err; - err = ptr->slave_read(1); - if(err == FSP_SUCCESS) { - ptr->tmp_i += 1; - } - } - else { - ptr->slave_read(0); - } - } - else if(arg->event == I2C_SLAVE_EVENT_TX_REQUEST) { - ptr->setBusStatus(WIRE_STATUS_TX_REQUEST); - - if(ptr->tx_callback != nullptr) { - ptr->tx_callback(); - } - } - else if(arg->event == I2C_SLAVE_EVENT_RX_MORE_REQUEST) { - ptr->setBusStatus(WIRE_STATUS_RX_REQUEST); - - if(ptr->tmp_i + bytes < I2C_BUFFER_LENGTH) { - volatile fsp_err_t err; - err = ptr->slave_read(bytes); - if(err == FSP_SUCCESS) { - ptr->tmp_i += bytes; - } - } - else { - ptr->slave_read(0); - } - } - else if(arg->event == I2C_SLAVE_EVENT_TX_MORE_REQUEST) { - ptr->setBusStatus(WIRE_STATUS_TX_REQUEST); - if(ptr->tx_callback != nullptr) { - ptr->tx_callback(); - } - } - else if(arg->event == I2C_SLAVE_EVENT_GENERAL_CALL) { - ptr->setBusStatus(WIRE_STATUS_GENERAL_CALL); - } - -} - - -/* -------------------------------------------------------------------------- */ -TwoWire::TwoWire(int scl, int sda, WireAddressMode_t am /*= ADDRESS_MODE_7_BITS*/, bool prefer_sci /*= false*/) : - scl_pin(scl), - sda_pin(sda), - init_ok(false), - is_master(true), - is_sci(false), - address_mode(am), - timeout_us(25000), - timed_out_flag(false), - do_reset_on_timeout(false), - transmission_begun(false), - data_too_long(false), - rx_index(0), - tx_index(0), - require_sci(prefer_sci) { -/* -------------------------------------------------------------------------- */ - m_i2c_cfg.rxi_irq = FSP_INVALID_VECTOR; - m_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; - m_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; - m_i2c_cfg.eri_irq = FSP_INVALID_VECTOR; - - s_i2c_cfg.rxi_irq = FSP_INVALID_VECTOR; - s_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; - s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; - s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; - - -} - -/* -------------------------------------------------------------------------- */ -bool TwoWire::cfg_pins(int max_index) { -/* -------------------------------------------------------------------------- */ - /* verify index are good */ - if(scl_pin < 0 || sda_pin < 0 || scl_pin >= max_index || sda_pin >= max_index) { - return false; - } - /* getting configuration from table */ - auto cfgs_scl = getPinCfgs(scl_pin, PIN_CFG_REQ_SCL); - auto cfgs_sda = getPinCfgs(sda_pin, PIN_CFG_REQ_SDA); - - uint16_t cfg_scl = 0; - uint16_t cfg_sda = 0; - - /* Find the best combination */ - for (size_t i = 0; i < cfgs_scl.size(); i++) { - for (size_t j = 0; j < cfgs_sda.size(); j++) { - if (cfgs_scl[i] && cfgs_sda[j] && (GET_CHANNEL(cfgs_scl[i]) == GET_CHANNEL(cfgs_sda[j])) && (IS_SCI(cfgs_scl[i]) == IS_SCI(cfgs_sda[j]))) { - cfg_scl = cfgs_scl[i]; - cfg_sda = cfgs_sda[j]; - channel = GET_CHANNEL(cfg_scl); - goto done; - } - } - } - -done: - if (cfg_sda == 0 || cfg_scl == 0) { - return false; - } - - /* actually configuring PIN function */ - ioport_peripheral_t ioport_sda; - ioport_peripheral_t ioport_scl; - - if(IS_SCI(cfg_sda)) { - if(channel >= TWOWIRE_MAX_SCI_CHANNELS) { // channels are 0 index based - return false; - } - is_sci = true; - ioport_sda = USE_SCI_EVEN_CFG(cfg_sda) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9; - ioport_scl = USE_SCI_EVEN_CFG(cfg_scl) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9; - - R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[sda_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_PERIPHERAL_PIN | ioport_sda)); - R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[scl_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_PERIPHERAL_PIN | ioport_scl)); - - } - else { - if(channel >= TWOWIRE_MAX_I2C_CHANNELS) { // channels are 0 index based - return false; - } - is_sci = false; - ioport_sda = IOPORT_PERIPHERAL_IIC; - ioport_scl = IOPORT_PERIPHERAL_IIC; - - R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[sda_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_DRIVE_MID | IOPORT_CFG_PERIPHERAL_PIN | ioport_sda)); - R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[scl_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_DRIVE_MID | IOPORT_CFG_PERIPHERAL_PIN | ioport_scl)); - } - - return true; -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::begin(void) { -/* -------------------------------------------------------------------------- */ - end(); - is_master = true; - _begin(); - -} - - -/* -------------------------------------------------------------------------- */ -void TwoWire::_begin(void) { -/* -------------------------------------------------------------------------- */ - init_ok = true; - int max_index = PINS_COUNT; - - init_ok &= cfg_pins(max_index); - - if(init_ok) { - - /* ----------------------------------- - ->>>>> MASTER initialization - * ----------------------------------- */ - if(is_master) { - - setClock(I2C_MASTER_RATE_STANDARD); - - if(is_sci) { - TwoWire::g_SCIWires[channel] = this; - - m_open = R_SCI_I2C_Open; - m_read = R_SCI_I2C_Read; - m_write = R_SCI_I2C_Write; - m_abort = R_SCI_I2C_Abort; - m_setSlaveAdd = R_SCI_I2C_SlaveAddressSet; - m_setCallback = R_SCI_I2C_CallbackSet; - m_getStatus = R_SCI_I2C_StatusGet; - m_close = R_SCI_I2C_Close; - - m_i2c_cfg.p_extend = &m_sci_i2c_extend; - m_i2c_cfg.p_callback = WireSCIMasterCallback; - } - else { - TwoWire::g_I2CWires[channel] = this; - - m_open = R_IIC_MASTER_Open; - m_read = R_IIC_MASTER_Read; - m_write = R_IIC_MASTER_Write; - m_abort = R_IIC_MASTER_Abort; - m_setSlaveAdd = R_IIC_MASTER_SlaveAddressSet; - m_setCallback = R_IIC_MASTER_CallbackSet; - m_getStatus = R_IIC_MASTER_StatusGet; - m_close = R_IIC_MASTER_Close; - - m_i2c_cfg.p_extend = &m_i2c_extend; - m_i2c_cfg.p_callback = WireMasterCallback; - - m_i2c_extend.timeout_mode = IIC_MASTER_TIMEOUT_MODE_SHORT; - m_i2c_extend.timeout_scl_low = IIC_MASTER_TIMEOUT_SCL_LOW_DISABLED; - } - - m_i2c_cfg.channel = channel; - m_i2c_cfg.rate = I2C_MASTER_RATE_STANDARD; - m_i2c_cfg.slave = 0x00; - m_i2c_cfg.addr_mode = (address_mode == ADDRESS_MODE_7_BITS) ? I2C_MASTER_ADDR_MODE_7BIT : I2C_MASTER_ADDR_MODE_10BIT; - m_i2c_cfg.p_transfer_tx = NULL; - m_i2c_cfg.p_transfer_rx = NULL; - - m_i2c_cfg.p_context = &m_i2c_cfg; - m_i2c_cfg.ipl = (12); - - } // if(is_master) { - /* ----------------------------------- - ->>>>> SLAVE initialization - * ----------------------------------- */ - else { - /* a slave device cannot be instatiated on SCI peripheral */ - if(is_sci) { - init_ok = false; - return; - } - TwoWire::g_I2CWires[channel] = this; - - s_open = R_IIC_SLAVE_Open; - s_read = R_IIC_SLAVE_Read; - s_write = R_IIC_SLAVE_Write; - s_setCallback = R_IIC_SLAVE_CallbackSet; - s_close = R_IIC_SLAVE_Close; - - s_i2c_cfg.channel = channel; - s_i2c_cfg.rate = I2C_SLAVE_RATE_STANDARD; - s_i2c_cfg.slave = slave_address; - s_i2c_cfg.addr_mode = (address_mode == ADDRESS_MODE_7_BITS) ? I2C_SLAVE_ADDR_MODE_7BIT : I2C_SLAVE_ADDR_MODE_10BIT; - s_i2c_cfg.general_call_enable = false; - s_i2c_cfg.ipl = (12); - s_i2c_cfg.eri_ipl = (12); - s_i2c_cfg.clock_stretching_enable = false; - s_i2c_cfg.p_callback = WireSlaveCallback; - s_i2c_cfg.p_context = &s_i2c_cfg; - s_i2c_cfg.p_extend = NULL; - } - } - else { - init_ok = false; - return; - } - - I2CIrqReq_t irq_req; - irq_req.mcfg = &m_i2c_cfg; - irq_req.scfg = &s_i2c_cfg; - - if(is_master) { - if(is_sci) { - init_ok &= IRQManager::getInstance().addPeripheral(IRQ_SCI_I2C_MASTER,&irq_req); - } - else { - init_ok &= IRQManager::getInstance().addPeripheral(IRQ_I2C_MASTER,&irq_req); - } - if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { - init_ok &= true; - } - else { - init_ok = false; - } - } - else { - init_ok &= IRQManager::getInstance().addPeripheral(IRQ_I2C_SLAVE,&irq_req); - if(FSP_SUCCESS == s_open(&s_i2c_ctrl,&s_i2c_cfg)) { - init_ok &= true; - } - else { - init_ok = false; - } - } -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::begin(uint16_t address) { -/* -------------------------------------------------------------------------- */ - end(); - is_master = false; - slave_address = address; - /* Address is set inside begin() using slave_address member variable */ - _begin(); - -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::begin(int address) { -/* -------------------------------------------------------------------------- */ - begin((uint16_t)address); -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::begin(uint8_t address) { -/* -------------------------------------------------------------------------- */ - begin((uint16_t)address); -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::end(void) { -/* -------------------------------------------------------------------------- */ - - if(init_ok) { - if(is_master) { - if(m_close != nullptr) { - R_BSP_IrqDisable (m_i2c_cfg.txi_irq); - R_BSP_IrqDisable (m_i2c_cfg.rxi_irq); - R_BSP_IrqDisable (m_i2c_cfg.tei_irq); - R_BSP_IrqDisable (m_i2c_cfg.eri_irq); - m_close(&m_i2c_ctrl); - } - } - else { - if(s_close != nullptr) { - R_BSP_IrqDisable (s_i2c_cfg.txi_irq); - R_BSP_IrqDisable (s_i2c_cfg.rxi_irq); - R_BSP_IrqDisable (s_i2c_cfg.tei_irq); - R_BSP_IrqDisable (s_i2c_cfg.eri_irq); - s_close(&s_i2c_ctrl); - - } - } - } - /* fix for slave that create a sort of lock on the I2C bus when end is called and the master - is not more able to get the I2C buse working */ - R_IOPORT_PinCfg(NULL, g_pin_cfg[sda_pin].pin, IOPORT_CFG_PORT_DIRECTION_INPUT | IOPORT_CFG_PULLUP_ENABLE); - R_IOPORT_PinCfg(NULL, g_pin_cfg[scl_pin].pin, IOPORT_CFG_PORT_DIRECTION_INPUT | IOPORT_CFG_PULLUP_ENABLE); - init_ok = false; -} - - - -/* -------------------------------------------------------------------------- */ -uint8_t TwoWire::read_from(uint8_t address, uint8_t* data, uint8_t length, uint32_t timeout_us, bool sendStop) { -/* -------------------------------------------------------------------------- */ - /* ??? does this function make sense only for MASTER ???? */ - - fsp_err_t err = FSP_ERR_ASSERTION; - if(init_ok) { - if(m_setSlaveAdd != nullptr) { - err = m_setSlaveAdd(&m_i2c_ctrl, address, m_i2c_cfg.addr_mode); - } - if(err == FSP_SUCCESS) { - if(m_read != nullptr) { - bus_status = WIRE_STATUS_UNSET; - err = m_read(&m_i2c_ctrl,data,length,!sendStop); - } - } - - uint32_t const start = micros(); - while (((timeout_us == 0ul) || ((millis() - start) < timeout_us)) && - bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { - } - if ((err == FSP_SUCCESS) && (bus_status == WIRE_STATUS_UNSET)) { - handleTimeout(do_reset_on_timeout); - return 0; - } - } - - if(bus_status == WIRE_STATUS_RX_COMPLETED) { - return length; - } - - return 0; /* ???????? return value ??????? */ -} - -/* -------------------------------------------------------------------------- */ -uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32_t timeout_us , bool sendStop) { -/* -------------------------------------------------------------------------- */ - uint8_t rv = END_TX_OK; - fsp_err_t err = FSP_ERR_ASSERTION; - if(init_ok) { - if(m_setSlaveAdd != nullptr) { - err = m_setSlaveAdd(&m_i2c_ctrl, address, m_i2c_cfg.addr_mode); - } - if(err == FSP_SUCCESS) { - if(m_write != nullptr) { - bus_status = WIRE_STATUS_UNSET; - err = m_write(&m_i2c_ctrl,data,length,!sendStop); - } - } - - uint32_t const start = micros(); - while (((timeout_us == 0ul) || ((millis() - start) < timeout_us)) && - bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { - } - - if(err != FSP_SUCCESS) { - rv = END_TX_ERR_FSP; - } - else if(data_too_long) { - rv = END_TX_DATA_TOO_LONG; - } - else if(bus_status == WIRE_STATUS_UNSET) { - rv = END_TX_TIMEOUT; - handleTimeout(do_reset_on_timeout); - } - /* as far as I know is impossible to distinguish between NACK on ADDRESS and - NACK on DATA */ - else if(bus_status == WIRE_STATUS_TRANSACTION_ABORTED) { - rv = END_TX_NACK_ON_ADD; - } - } - else { - rv = END_TX_NOT_INIT; - } - - - return rv; -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::setClock(uint32_t freq) { -/* -------------------------------------------------------------------------- */ - if(init_ok && is_master) { - if(m_close != nullptr) { - m_close(&m_i2c_ctrl); - } - } - - if(is_master) { - m_i2c_cfg.rate = (i2c_master_rate_t)freq; - - int clock_divisor = (R_FSP_SystemClockHzGet(BSP_FEATURE_SCI_CLOCK) / 48000000u) - 1; - - if (is_sci) { - m_sci_i2c_extend.clock_settings.clk_divisor_value = 0; - m_sci_i2c_extend.clock_settings.cycles_value = 15; - m_sci_i2c_extend.clock_settings.snfr_value = (1); - switch (m_i2c_cfg.rate) { - case I2C_MASTER_RATE_STANDARD: - m_sci_i2c_extend.clock_settings.brr_value = 14; - m_sci_i2c_extend.clock_settings.mddr_value = 255; - m_sci_i2c_extend.clock_settings.bitrate_modulation = false; - break; - case I2C_MASTER_RATE_FAST: - default: - m_sci_i2c_extend.clock_settings.brr_value = 2; - m_sci_i2c_extend.clock_settings.mddr_value = 204; - m_sci_i2c_extend.clock_settings.bitrate_modulation = true; - break; - } - } else { - switch (m_i2c_cfg.rate) { - case I2C_MASTER_RATE_STANDARD: - m_i2c_extend.clock_settings.brl_value = 27; - m_i2c_extend.clock_settings.brh_value = 26; - m_i2c_extend.clock_settings.cks_value = 2 + clock_divisor; - break; - case I2C_MASTER_RATE_FAST: - m_i2c_extend.clock_settings.brl_value = 16; - m_i2c_extend.clock_settings.brh_value = 15; - m_i2c_extend.clock_settings.cks_value = 0 + clock_divisor; - break; -#if BSP_FEATURE_IIC_FAST_MODE_PLUS - case I2C_MASTER_RATE_FASTPLUS: - m_i2c_extend.clock_settings.brl_value = 6; - m_i2c_extend.clock_settings.brh_value = 5; - m_i2c_extend.clock_settings.cks_value = 0; - break; -#endif - } - } - } - - if(init_ok) { - if(m_open != nullptr) { - if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { - init_ok &= true; - } - else { - init_ok = false; - } - } - } -} - -/*** - * Sets the I2C timeout. - * - * This limits the maximum time to wait for the I2C hardware. If more time passes, the bus is assumed - * to have locked up (e.g. due to noise-induced glitches or faulty slaves) and the transaction is aborted. - * Optionally, the I2C hardware is also reset, which can be required to allow subsequent transactions to - * succeed in some cases (in particular when noise has made the I2C hardware think there is a second - * master that has claimed the bus). - * - * When a timeout is triggered, a flag is set that can be queried with `getWireTimeoutFlag()` and is cleared - * when `clearWireTimeoutFlag()` or `setWireTimeoutUs()` is called. - * - * Note that this timeout can also trigger while waiting for clock stretching or waiting for a second master - * to complete its transaction. So make sure to adapt the timeout to accommodate for those cases if needed. - * A typical timeout would be 25ms (which is the maximum clock stretching allowed by the SMBus protocol), - * but (much) shorter values will usually also work. - * - * In the future, a timeout will be enabled by default, so if you require the timeout to be disabled, it is - * recommended you disable it by default using `setWireTimeoutUs(0)`, even though that is currently - * the default. - * - * @param timeout a timeout value in microseconds, if zero then timeout checking is disabled - * @param reset_with_timeout if true then I2C interface will be automatically reset on timeout - * if false then I2C interface will not be reset on timeout - - */ - -/* -------------------------------------------------------------------------- */ -void TwoWire::setWireTimeout(uint32_t timeout, bool reset_with_timeout){ -/* -------------------------------------------------------------------------- */ - timed_out_flag = false; - timeout_us = timeout; - do_reset_on_timeout = reset_with_timeout; -} - -/*** - * Returns the timeout flag. - * - * @return true if timeout has occurred since the flag was last cleared. - */ -bool TwoWire::getWireTimeoutFlag(void){ - return(timed_out_flag); -} - -/*** - * Clears the timeout flag. - */ -/* -------------------------------------------------------------------------- */ -void TwoWire::clearWireTimeoutFlag(void){ -/* -------------------------------------------------------------------------- */ - timed_out_flag = false; -} - -/* - * Function handleTimeout - * Desc this gets called whenever a while loop here has lasted longer than - * timeout_us microseconds. always sets timed_out_flag - * Input reset: true causes this function to reset the hardware interface - * Output none - */ -/* -------------------------------------------------------------------------- */ -void TwoWire::handleTimeout(bool reset){ -/* -------------------------------------------------------------------------- */ - timed_out_flag = true; - if (reset) { //TBD; What do we do here? like fixHungWire()? - // TBD, Is this the way to go to reset the bus? - // Do we need more to handle devices that hangs the bus? - if(m_abort != nullptr) { - bus_status = WIRE_STATUS_UNSET; - fsp_err_t err = m_abort(&m_i2c_ctrl); - } - // TDB, Is this the right way to get back after reset? - //if(m_open != nullptr) { - // if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { - // init_ok &= true; - // } - //} - } -} - - - -/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * TRANSMISSION BEGIN - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - -/* -------------------------------------------------------------------------- */ -void TwoWire::beginTransmission(uint32_t address) { -/* -------------------------------------------------------------------------- */ - if (init_ok) { - data_too_long = false; - master_tx_address = address; - transmission_begun = true; - tx_index = 0; - } -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::beginTransmission(uint16_t address) { -/* -------------------------------------------------------------------------- */ - beginTransmission((uint32_t)address); -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::beginTransmission(uint8_t address){ -/* -------------------------------------------------------------------------- */ - beginTransmission((uint32_t)address); -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::beginTransmission(int address) { -/* -------------------------------------------------------------------------- */ - beginTransmission((uint32_t)address); -} - -/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * TRANSMISSION END - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - -/* -------------------------------------------------------------------------- */ -uint8_t TwoWire::endTransmission(bool sendStop) { -/* -------------------------------------------------------------------------- */ - uint8_t ret = write_to(master_tx_address, tx_buffer, tx_index, timeout_us, sendStop); - transmission_begun = false; - return ret; -} - -/* -------------------------------------------------------------------------- */ -uint8_t TwoWire::endTransmission(void) { -/* -------------------------------------------------------------------------- */ - return endTransmission(true); -} - -/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * REQUEST FROM - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - -/* -------------------------------------------------------------------------- */ -size_t TwoWire::requestFrom(uint8_t address, size_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) { -/* -------------------------------------------------------------------------- */ - if(init_ok) { - - if (isize > 0) { - // send internal address; this mode allows sending a repeated start to access - // some devices' internal registers. This function is executed by the hardware - // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) - - beginTransmission(address); - - // the maximum size of internal address is 3 bytes - if (isize > 3){ - isize = 3; - } - - // write internal register address - most significant byte first - while (isize-- > 0) { - write((uint8_t)(iaddress >> (isize*8))); - } - - endTransmission(false); - } - - // clamp to buffer length - if(quantity > I2C_BUFFER_LENGTH){ - quantity = I2C_BUFFER_LENGTH; - } - // perform blocking read into buffer - uint8_t read = read_from(address, rx_buffer, quantity, timeout_us, sendStop); - // set rx buffer iterator vars - rx_index = read; - rx_extract_index = 0; - - return (size_t)read; - } - else { - return 0; - } -} - -/* -------------------------------------------------------------------------- */ -size_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool sendStop) { -/* -------------------------------------------------------------------------- */ - return requestFrom((uint8_t)address, quantity, (uint32_t)0, (uint8_t)0, sendStop); -} - -/* -------------------------------------------------------------------------- */ -size_t TwoWire::requestFrom(uint8_t address, size_t quantity) { -/* -------------------------------------------------------------------------- */ - return requestFrom((uint8_t)address, quantity, true); -} - -/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - * WRITE - * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -/* -------------------------------------------------------------------------- */ -size_t TwoWire::write(uint8_t data) { -/* -------------------------------------------------------------------------- */ - if(init_ok) { - if(is_master) { - if(transmission_begun) { - if(tx_index >= I2C_BUFFER_LENGTH) { - data_too_long = true; - setWriteError(); - return 0; - } - tx_buffer[tx_index] = data; - tx_index++; - } - } - else { - if(s_write != nullptr) { - s_write(&s_i2c_ctrl,(uint8_t *)&data,1); - } - } - return 1; - } - return 0; - -} - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -/* -------------------------------------------------------------------------- */ -size_t TwoWire::write(const uint8_t *data, size_t quantity) { -/* -------------------------------------------------------------------------- */ - if(init_ok) { - if(is_master) { - // in master transmitter mode - for(size_t i = 0; i < quantity; ++i){ - write(data[i]); - } - } - else{ - if(s_write != nullptr) { - s_write(&s_i2c_ctrl,(uint8_t *)data,quantity); - } - } - return quantity; - } - else { - return 0; - } -} - - -// sets function called on slave write -/* -------------------------------------------------------------------------- */ -void TwoWire::onReceive( I2C_onRxCallback_f f ) { -/* -------------------------------------------------------------------------- */ - rx_callback = f; -} - -// sets function called on slave read -/* -------------------------------------------------------------------------- */ -void TwoWire::onRequest( I2C_onTxCallback_f f ) { -/* -------------------------------------------------------------------------- */ - tx_callback = f; -} - - - -// must be called in: -// slave rx event callback -// or after requestFrom(address, numBytes) - -/* -------------------------------------------------------------------------- */ -int TwoWire::available(void) { -/* -------------------------------------------------------------------------- */ - return rx_index - rx_extract_index; -} - -// must be called in: -// slave rx event callback -// or after requestFrom(address, numBytes) -/* -------------------------------------------------------------------------- */ -int TwoWire::read(void) { -/* -------------------------------------------------------------------------- */ - int rv = -1; - - // get each successive byte on each call - if(rx_extract_index < rx_index){ - rv = rx_buffer[rx_extract_index]; - rx_extract_index++; - } - - return rv; -} - -// must be called in: -// slave rx event callback -// or after requestFrom(address, numBytes) -/* -------------------------------------------------------------------------- */ -int TwoWire::peek(void) { -/* -------------------------------------------------------------------------- */ - int rv = -1; - - // get each successive byte on each call - if(rx_extract_index < rx_index){ - rv = rx_buffer[rx_extract_index]; - } - - return rv; -} - -/* -------------------------------------------------------------------------- */ -void TwoWire::flush(void) { -/* -------------------------------------------------------------------------- */ - while(bus_status != WIRE_STATUS_TX_COMPLETED && bus_status != WIRE_STATUS_TRANSACTION_ABORTED) {} -} - - - - -#if WIRE_HOWMANY > 0 -TwoWire Wire(WIRE_SCL_PIN, WIRE_SDA_PIN); -#endif - -#if WIRE_HOWMANY > 1 -TwoWire Wire1(WIRE1_SCL_PIN, WIRE1_SDA_PIN); -#endif - -#if WIRE_HOWMANY > 2 -TwoWire Wire2(WIRE2_SCL_PIN, WIRE2_SDA_PIN); -#endif - -#if WIRE_HOWMANY > 3 -TwoWire Wire3(WIRE3_SCL_PIN, WIRE3_SDA_PIN); -#endif - - From 224cbc7a54123bbd98c7c2e139c033c6ef5272e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Thu, 9 Oct 2025 19:22:39 +0200 Subject: [PATCH 10/14] Delete libraries/Wire/src/Wire.h --- libraries/Wire/src/Wire.h | 255 -------------------------------------- 1 file changed, 255 deletions(-) delete mode 100644 libraries/Wire/src/Wire.h diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h deleted file mode 100644 index a4145c9d2..000000000 --- a/libraries/Wire/src/Wire.h +++ /dev/null @@ -1,255 +0,0 @@ -/* - Copyright (c) 2016 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - - -#define _TIMEVAL_DEFINED -#define _SYS_SELECT_H - -#include "Arduino.h" -#include "IRQManager.h" -#include "api/HardwareI2C.h" -#include "api/Stream.h" -#include - -#include "bsp_api.h" - -#include "r_iic_master.h" -#include "r_sci_i2c.h" -#include "r_i2c_master_api.h" -#include "r_i2c_slave_api.h" - -extern "C" { - void i2c_callback(i2c_master_callback_args_t *p_args); -} - -using I2C_masterOpen_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, i2c_master_cfg_t const *const p_cfg); -using I2C_masterRead_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint8_t *const p_dest, uint32_t const bytes, bool const restart); -using I2C_masterWrite_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint8_t *constp_src, uint32_t const bytes, bool const restart); -using I2C_masterAbort_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl); -using I2C_masterSetSlaveAdd_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint32_t const slave, i2c_master_addr_mode_t const addr_mode); -using I2C_masterSetCallBack_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, void(*p_callback)(i2c_master_callback_args_t *), void const *const p_context, i2c_master_callback_args_t *const p_callback_memory); -using I2C_masterGetStatus_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, i2c_master_status_t *p_status); -using I2C_masterClose_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl); - -using I2C_slaveOpen_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, i2c_slave_cfg_t const *const p_cfg); -using I2C_slaveRead_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, uint8_t *const p_dest, uint32_t const bytes); -using I2C_slaveWrite_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, uint8_t *const p_src, uint32_t const bytes); -using I2C_slaveSetCallBack_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, void(*p_callback)(i2c_slave_callback_args_t *), void const *const p_context, i2c_slave_callback_args_t *const p_callback_memory); -using I2C_slaveClose_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl); - -using I2C_onRxCallback_f = void (*)(int); -using I2C_onTxCallback_f = void (*)(void); - - -#define I2C_BUFFER_LENGTH 255 - -#define TWOWIRE_MAX_I2C_CHANNELS (3) // IIC0 to IIC2 -#define TWOWIRE_MAX_SCI_CHANNELS (10) // SCI0 to SCI9 - -#ifdef __cplusplus - -#ifndef __ARDUINO_WIRE_IMPLEMENTATION__ -#define __ARDUINO_WIRE_IMPLEMENTATION__ - -// WIRE_HAS_END means Wire has end() -#define WIRE_HAS_END 1 - -// WIRE_HAS_TIMEOUT means Wire has setWireTimeout(), getWireTimeoutFlag -// and clearWireTimeoutFlag() -#define WIRE_HAS_TIMEOUT 1 - -// When not configured, these settings are used for the timeout -#define WIRE_DEFAULT_TIMEOUT 25000 -#define WIRE_DEFAULT_RESET_WITH_TIMEOUT 0 - -#define END_TX_OK 0 -#define END_TX_DATA_TOO_LONG 1 -#define END_TX_NACK_ON_ADD 2 -#define END_TX_NACK_ON_DATA 3 -#define END_TX_ERR_FSP 4 -#define END_TX_TIMEOUT 5 -#define END_TX_NOT_INIT 6 - - -typedef enum { - ADDRESS_MODE_7_BITS, - ADDRESS_MODE_10_BITS -} WireAddressMode_t; - -typedef enum { - WIRE_STATUS_UNSET, - WIRE_STATUS_RX_COMPLETED, - WIRE_STATUS_TX_COMPLETED, - WIRE_STATUS_TRANSACTION_ABORTED, - WIRE_STATUS_RX_REQUEST, - WIRE_STATUS_TX_REQUEST, - WIRE_STATUS_GENERAL_CALL -} WireStatus_t; - -class TwoWire : public arduino::HardwareI2C { - - public: - TwoWire(int scl_pin, int sda_pin, WireAddressMode_t am = ADDRESS_MODE_7_BITS, bool prefer_sci = false); - void begin(); - void begin(uint8_t); - void begin(uint16_t); - void begin(int); - void end(); - void setClock(uint32_t); - - void setWireTimeout(uint32_t timeout = 25000, bool reset_with_timeout = false); - bool getWireTimeoutFlag(void); - void clearWireTimeoutFlag(void); - - void beginTransmission(uint32_t); - void beginTransmission(uint16_t); - void beginTransmission(uint8_t); - void beginTransmission(int); - - uint8_t endTransmission(void); - uint8_t endTransmission(bool); - size_t requestFrom(uint8_t, size_t); - size_t requestFrom(uint8_t, size_t, bool); - size_t requestFrom(uint8_t, size_t, uint32_t, uint8_t, uint8_t); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *, size_t); - virtual int available(void); - virtual int read(void); - virtual int peek(void); - virtual void flush(void); - void onReceive( void (*)(int) ); - void onRequest( void (*)(void) ); - - void setBusStatus(WireStatus_t); - - inline size_t write(unsigned long n) { return write((uint8_t)n); } - inline size_t write(long n) { return write((uint8_t)n); } - inline size_t write(unsigned int n) { return write((uint8_t)n); } - inline size_t write(int n) { return write((uint8_t)n); } - using Print::write; - - volatile uint32_t tmp_i = 0; - - void cpy_rx_buffer(uint32_t h) { - memcpy(rx_buffer,tmp_buff,h); - rx_index = h; - tmp_i = 0; - rx_extract_index = 0; - memset(tmp_buff, 0x00,I2C_BUFFER_LENGTH); - } - - fsp_err_t slave_read(volatile uint32_t d) { - if(s_read != nullptr) { - return s_read(&s_i2c_ctrl,tmp_buff + tmp_i,d); - } - else { - return FSP_ERR_ASSERTION; - } - } - - private: - - static TwoWire *g_SCIWires[TWOWIRE_MAX_SCI_CHANNELS]; - static TwoWire *g_I2CWires[TWOWIRE_MAX_I2C_CHANNELS]; - - static void WireSCIMasterCallback(i2c_master_callback_args_t *); - static void WireMasterCallback(i2c_master_callback_args_t *); - static void WireSlaveCallback(i2c_slave_callback_args_t *); - - void _begin(); - - int scl_pin; - int sda_pin; - bool init_ok; - bool is_master; - int channel; - bool is_sci; - WireAddressMode_t address_mode; - - uint32_t timeout_us; - volatile bool timed_out_flag; - bool do_reset_on_timeout; - - void handleTimeout(bool reset); - - bool transmission_begun; - bool data_too_long; - - volatile WireStatus_t bus_status; - - sci_i2c_extended_cfg_t m_sci_i2c_extend; - - iic_master_extended_cfg_t m_i2c_extend; - iic_master_instance_ctrl_t m_i2c_ctrl; - i2c_master_cfg_t m_i2c_cfg; - - iic_slave_instance_ctrl_t s_i2c_ctrl; - i2c_slave_cfg_t s_i2c_cfg; - uint16_t slave_address; - - uint32_t master_tx_address; - - I2C_masterOpen_f m_open = nullptr; - I2C_masterRead_f m_read = nullptr; - I2C_masterWrite_f m_write = nullptr; - I2C_masterAbort_f m_abort = nullptr; - I2C_masterSetSlaveAdd_f m_setSlaveAdd = nullptr; - I2C_masterSetCallBack_f m_setCallback = nullptr; - I2C_masterGetStatus_f m_getStatus = nullptr; - I2C_masterClose_f m_close = nullptr; - - I2C_slaveOpen_f s_open = nullptr; - I2C_slaveRead_f s_read = nullptr; - I2C_slaveWrite_f s_write = nullptr; - I2C_slaveSetCallBack_f s_setCallback = nullptr; - I2C_slaveClose_f s_close = nullptr; - - uint8_t tmp_buff[I2C_BUFFER_LENGTH]; - uint8_t tx_buffer[I2C_BUFFER_LENGTH]; - uint8_t rx_buffer[I2C_BUFFER_LENGTH]; - size_t rx_index; - size_t tx_index; - uint8_t rx_extract_index; - - bool require_sci; - - uint8_t read_from(uint8_t, uint8_t*, uint8_t, uint32_t, bool); - uint8_t write_to(uint8_t, uint8_t*, uint8_t, uint32_t, bool); - - bool cfg_pins(int max_index); - - I2C_onRxCallback_f rx_callback; - I2C_onTxCallback_f tx_callback; - -}; - -#if WIRE_HOWMANY > 0 -extern TwoWire Wire; -#endif -#if WIRE_HOWMANY > 1 -extern TwoWire Wire1; -#endif -#if WIRE_HOWMANY > 2 -extern TwoWire Wire2; -#endif -#if WIRE_HOWMANY > 3 -extern TwoWire Wire3; -#endif - -#endif -#endif From 30f0c78229cb6d8cd61e99c69823e0c5bc50535f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Thu, 9 Oct 2025 19:29:53 +0200 Subject: [PATCH 11/14] Create Wire.h --- libraries/Wire/Wire.h | 1 + 1 file changed, 1 insertion(+) create mode 100644 libraries/Wire/Wire.h diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/libraries/Wire/Wire.h @@ -0,0 +1 @@ + From 4be168988a636a1e43fc5cc50763be6a37a27ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Thu, 9 Oct 2025 19:32:35 +0200 Subject: [PATCH 12/14] Add timeout handling for I2C in Wire #497 Adding timeout handling for I2C in Wire according to previously defined solution on other platforms Also reduced the default timeout from 1000ms to 25ms --- libraries/Wire/Wire.cpp | 953 ++++++++++++++++++++++++++++++++++++++++ libraries/Wire/Wire.h | 254 +++++++++++ 2 files changed, 1207 insertions(+) create mode 100644 libraries/Wire/Wire.cpp diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp new file mode 100644 index 000000000..afed9b543 --- /dev/null +++ b/libraries/Wire/Wire.cpp @@ -0,0 +1,953 @@ +/* + TwoWire.cpp - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts + Modified 2017 by Chuck Todd (ctodd@cableone.net) to correct Unconfigured Slave Mode reboot + + Version 2022 for Renesas RA4 by Daniele Aimo (d.aimo@arduino.cc) + + Version 2025 by Hanz Häger (hanz.hager+arduino@gmail.com) added timeout interface +*/ + +extern "C" { + #include + #include + #include +} + +#include "Arduino.h" +#include "Wire.h" + +TwoWire *TwoWire::g_SCIWires[TWOWIRE_MAX_SCI_CHANNELS] = {nullptr}; +TwoWire *TwoWire::g_I2CWires[TWOWIRE_MAX_I2C_CHANNELS] = {nullptr}; + +/* -------------------------------------------------------------------------- */ +void TwoWire::setBusStatus(WireStatus_t ws) { +/* -------------------------------------------------------------------------- */ + bus_status = ws; +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::WireSCIMasterCallback(i2c_master_callback_args_t *arg) { +/* -------------------------------------------------------------------------- */ + /* +++++ MASTER I2C SCI Callback ++++++ */ + + i2c_master_cfg_t *cfg = (i2c_master_cfg_t *)arg->p_context; + + TwoWire *ptr = nullptr; + if(cfg->channel < TWOWIRE_MAX_SCI_CHANNELS) { + ptr = g_SCIWires[cfg->channel]; + } + + if(ptr == nullptr) { + return; + } + if(!ptr->init_ok) { + return; + } + + if(ptr != nullptr) { + if(arg->event == I2C_MASTER_EVENT_ABORTED) { + ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); + } + else if(arg->event == I2C_MASTER_EVENT_RX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); + } + else if(arg->event == I2C_MASTER_EVENT_TX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); + } + } + +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::WireMasterCallback(i2c_master_callback_args_t *arg) { +/* -------------------------------------------------------------------------- */ + /* +++++ MASTER I2C not SCI Callback ++++++ */ + i2c_master_cfg_t *cfg = (i2c_master_cfg_t *)arg->p_context; + + TwoWire *ptr = nullptr; + if(cfg->channel < TWOWIRE_MAX_I2C_CHANNELS) { + ptr = g_I2CWires[cfg->channel]; + } + + if(ptr == nullptr) { + return; + } + if(!ptr->init_ok) { + return; + } + + if(ptr != nullptr) { + if(arg->event == I2C_MASTER_EVENT_ABORTED) { + ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); + } + else if(arg->event == I2C_MASTER_EVENT_RX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); + } + else if(arg->event == I2C_MASTER_EVENT_TX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); + } + } +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::WireSlaveCallback(i2c_slave_callback_args_t *arg) { +/* -------------------------------------------------------------------------- */ + /* +++++ SLAVE Callback ++++++ */ + volatile uint32_t bytes = arg->bytes; + volatile i2c_slave_cfg_t *cfg = (i2c_slave_cfg_t *)arg->p_context; + + TwoWire *ptr = nullptr; + if(cfg->channel < TWOWIRE_MAX_I2C_CHANNELS) { + ptr = g_I2CWires[cfg->channel]; + } + + if(ptr == nullptr) { + return; + } + if(!ptr->init_ok) { + return; + } + + if(arg->event == I2C_SLAVE_EVENT_ABORTED) { + ptr->setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); + } + else if(arg->event == I2C_SLAVE_EVENT_RX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_RX_COMPLETED); + + ptr->cpy_rx_buffer(bytes); + if(ptr->rx_callback != nullptr) { + ptr->rx_callback(bytes); + } + } + else if(arg->event == I2C_SLAVE_EVENT_TX_COMPLETE) { + ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); + } + else if(arg->event == I2C_SLAVE_EVENT_RX_REQUEST) { + ptr->setBusStatus(WIRE_STATUS_RX_REQUEST); + if(ptr->tmp_i + bytes < I2C_BUFFER_LENGTH) { + volatile fsp_err_t err; + err = ptr->slave_read(1); + if(err == FSP_SUCCESS) { + ptr->tmp_i += 1; + } + } + else { + ptr->slave_read(0); + } + } + else if(arg->event == I2C_SLAVE_EVENT_TX_REQUEST) { + ptr->setBusStatus(WIRE_STATUS_TX_REQUEST); + + if(ptr->tx_callback != nullptr) { + ptr->tx_callback(); + } + } + else if(arg->event == I2C_SLAVE_EVENT_RX_MORE_REQUEST) { + ptr->setBusStatus(WIRE_STATUS_RX_REQUEST); + + if(ptr->tmp_i + bytes < I2C_BUFFER_LENGTH) { + volatile fsp_err_t err; + err = ptr->slave_read(bytes); + if(err == FSP_SUCCESS) { + ptr->tmp_i += bytes; + } + } + else { + ptr->slave_read(0); + } + } + else if(arg->event == I2C_SLAVE_EVENT_TX_MORE_REQUEST) { + ptr->setBusStatus(WIRE_STATUS_TX_REQUEST); + if(ptr->tx_callback != nullptr) { + ptr->tx_callback(); + } + } + else if(arg->event == I2C_SLAVE_EVENT_GENERAL_CALL) { + ptr->setBusStatus(WIRE_STATUS_GENERAL_CALL); + } + +} + + +/* -------------------------------------------------------------------------- */ +TwoWire::TwoWire(int scl, int sda, WireAddressMode_t am /*= ADDRESS_MODE_7_BITS*/, bool prefer_sci /*= false*/) : + scl_pin(scl), + sda_pin(sda), + init_ok(false), + is_master(true), + is_sci(false), + address_mode(am), + timeout_us(25000), + timed_out_flag(false), + do_reset_on_timeout(false), + transmission_begun(false), + data_too_long(false), + rx_index(0), + tx_index(0), + require_sci(prefer_sci) { +/* -------------------------------------------------------------------------- */ + m_i2c_cfg.rxi_irq = FSP_INVALID_VECTOR; + m_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; + m_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; + m_i2c_cfg.eri_irq = FSP_INVALID_VECTOR; + + s_i2c_cfg.rxi_irq = FSP_INVALID_VECTOR; + s_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; + s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; + s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; + + +} + +/* -------------------------------------------------------------------------- */ +bool TwoWire::cfg_pins(int max_index) { +/* -------------------------------------------------------------------------- */ + /* verify index are good */ + if(scl_pin < 0 || sda_pin < 0 || scl_pin >= max_index || sda_pin >= max_index) { + return false; + } + /* getting configuration from table */ + auto cfgs_scl = getPinCfgs(scl_pin, PIN_CFG_REQ_SCL); + auto cfgs_sda = getPinCfgs(sda_pin, PIN_CFG_REQ_SDA); + + uint16_t cfg_scl = 0; + uint16_t cfg_sda = 0; + + /* Find the best combination */ + for (size_t i = 0; i < cfgs_scl.size(); i++) { + for (size_t j = 0; j < cfgs_sda.size(); j++) { + if (cfgs_scl[i] && cfgs_sda[j] && (GET_CHANNEL(cfgs_scl[i]) == GET_CHANNEL(cfgs_sda[j])) && (IS_SCI(cfgs_scl[i]) == IS_SCI(cfgs_sda[j]))) { + cfg_scl = cfgs_scl[i]; + cfg_sda = cfgs_sda[j]; + channel = GET_CHANNEL(cfg_scl); + goto done; + } + } + } + +done: + if (cfg_sda == 0 || cfg_scl == 0) { + return false; + } + + /* actually configuring PIN function */ + ioport_peripheral_t ioport_sda; + ioport_peripheral_t ioport_scl; + + if(IS_SCI(cfg_sda)) { + if(channel >= TWOWIRE_MAX_SCI_CHANNELS) { // channels are 0 index based + return false; + } + is_sci = true; + ioport_sda = USE_SCI_EVEN_CFG(cfg_sda) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9; + ioport_scl = USE_SCI_EVEN_CFG(cfg_scl) ? IOPORT_PERIPHERAL_SCI0_2_4_6_8 : IOPORT_PERIPHERAL_SCI1_3_5_7_9; + + R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[sda_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_PERIPHERAL_PIN | ioport_sda)); + R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[scl_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_PERIPHERAL_PIN | ioport_scl)); + + } + else { + if(channel >= TWOWIRE_MAX_I2C_CHANNELS) { // channels are 0 index based + return false; + } + is_sci = false; + ioport_sda = IOPORT_PERIPHERAL_IIC; + ioport_scl = IOPORT_PERIPHERAL_IIC; + + R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[sda_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_DRIVE_MID | IOPORT_CFG_PERIPHERAL_PIN | ioport_sda)); + R_IOPORT_PinCfg(&g_ioport_ctrl, g_pin_cfg[scl_pin].pin, (uint32_t) (IOPORT_CFG_PULLUP_ENABLE | IOPORT_CFG_DRIVE_MID | IOPORT_CFG_PERIPHERAL_PIN | ioport_scl)); + } + + return true; +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::begin(void) { +/* -------------------------------------------------------------------------- */ + end(); + is_master = true; + _begin(); + +} + + +/* -------------------------------------------------------------------------- */ +void TwoWire::_begin(void) { +/* -------------------------------------------------------------------------- */ + init_ok = true; + int max_index = PINS_COUNT; + + init_ok &= cfg_pins(max_index); + + if(init_ok) { + + /* ----------------------------------- + ->>>>> MASTER initialization + * ----------------------------------- */ + if(is_master) { + + setClock(I2C_MASTER_RATE_STANDARD); + + if(is_sci) { + TwoWire::g_SCIWires[channel] = this; + + m_open = R_SCI_I2C_Open; + m_read = R_SCI_I2C_Read; + m_write = R_SCI_I2C_Write; + m_abort = R_SCI_I2C_Abort; + m_setSlaveAdd = R_SCI_I2C_SlaveAddressSet; + m_setCallback = R_SCI_I2C_CallbackSet; + m_getStatus = R_SCI_I2C_StatusGet; + m_close = R_SCI_I2C_Close; + + m_i2c_cfg.p_extend = &m_sci_i2c_extend; + m_i2c_cfg.p_callback = WireSCIMasterCallback; + } + else { + TwoWire::g_I2CWires[channel] = this; + + m_open = R_IIC_MASTER_Open; + m_read = R_IIC_MASTER_Read; + m_write = R_IIC_MASTER_Write; + m_abort = R_IIC_MASTER_Abort; + m_setSlaveAdd = R_IIC_MASTER_SlaveAddressSet; + m_setCallback = R_IIC_MASTER_CallbackSet; + m_getStatus = R_IIC_MASTER_StatusGet; + m_close = R_IIC_MASTER_Close; + + m_i2c_cfg.p_extend = &m_i2c_extend; + m_i2c_cfg.p_callback = WireMasterCallback; + + m_i2c_extend.timeout_mode = IIC_MASTER_TIMEOUT_MODE_SHORT; + m_i2c_extend.timeout_scl_low = IIC_MASTER_TIMEOUT_SCL_LOW_DISABLED; + } + + m_i2c_cfg.channel = channel; + m_i2c_cfg.rate = I2C_MASTER_RATE_STANDARD; + m_i2c_cfg.slave = 0x00; + m_i2c_cfg.addr_mode = (address_mode == ADDRESS_MODE_7_BITS) ? I2C_MASTER_ADDR_MODE_7BIT : I2C_MASTER_ADDR_MODE_10BIT; + m_i2c_cfg.p_transfer_tx = NULL; + m_i2c_cfg.p_transfer_rx = NULL; + + m_i2c_cfg.p_context = &m_i2c_cfg; + m_i2c_cfg.ipl = (12); + + } // if(is_master) { + /* ----------------------------------- + ->>>>> SLAVE initialization + * ----------------------------------- */ + else { + /* a slave device cannot be instatiated on SCI peripheral */ + if(is_sci) { + init_ok = false; + return; + } + TwoWire::g_I2CWires[channel] = this; + + s_open = R_IIC_SLAVE_Open; + s_read = R_IIC_SLAVE_Read; + s_write = R_IIC_SLAVE_Write; + s_setCallback = R_IIC_SLAVE_CallbackSet; + s_close = R_IIC_SLAVE_Close; + + s_i2c_cfg.channel = channel; + s_i2c_cfg.rate = I2C_SLAVE_RATE_STANDARD; + s_i2c_cfg.slave = slave_address; + s_i2c_cfg.addr_mode = (address_mode == ADDRESS_MODE_7_BITS) ? I2C_SLAVE_ADDR_MODE_7BIT : I2C_SLAVE_ADDR_MODE_10BIT; + s_i2c_cfg.general_call_enable = false; + s_i2c_cfg.ipl = (12); + s_i2c_cfg.eri_ipl = (12); + s_i2c_cfg.clock_stretching_enable = false; + s_i2c_cfg.p_callback = WireSlaveCallback; + s_i2c_cfg.p_context = &s_i2c_cfg; + s_i2c_cfg.p_extend = NULL; + } + } + else { + init_ok = false; + return; + } + + I2CIrqReq_t irq_req; + irq_req.mcfg = &m_i2c_cfg; + irq_req.scfg = &s_i2c_cfg; + + if(is_master) { + if(is_sci) { + init_ok &= IRQManager::getInstance().addPeripheral(IRQ_SCI_I2C_MASTER,&irq_req); + } + else { + init_ok &= IRQManager::getInstance().addPeripheral(IRQ_I2C_MASTER,&irq_req); + } + if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { + init_ok &= true; + } + else { + init_ok = false; + } + } + else { + init_ok &= IRQManager::getInstance().addPeripheral(IRQ_I2C_SLAVE,&irq_req); + if(FSP_SUCCESS == s_open(&s_i2c_ctrl,&s_i2c_cfg)) { + init_ok &= true; + } + else { + init_ok = false; + } + } +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::begin(uint16_t address) { +/* -------------------------------------------------------------------------- */ + end(); + is_master = false; + slave_address = address; + /* Address is set inside begin() using slave_address member variable */ + _begin(); + +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::begin(int address) { +/* -------------------------------------------------------------------------- */ + begin((uint16_t)address); +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::begin(uint8_t address) { +/* -------------------------------------------------------------------------- */ + begin((uint16_t)address); +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::end(void) { +/* -------------------------------------------------------------------------- */ + + if(init_ok) { + if(is_master) { + if(m_close != nullptr) { + R_BSP_IrqDisable (m_i2c_cfg.txi_irq); + R_BSP_IrqDisable (m_i2c_cfg.rxi_irq); + R_BSP_IrqDisable (m_i2c_cfg.tei_irq); + R_BSP_IrqDisable (m_i2c_cfg.eri_irq); + m_close(&m_i2c_ctrl); + } + } + else { + if(s_close != nullptr) { + R_BSP_IrqDisable (s_i2c_cfg.txi_irq); + R_BSP_IrqDisable (s_i2c_cfg.rxi_irq); + R_BSP_IrqDisable (s_i2c_cfg.tei_irq); + R_BSP_IrqDisable (s_i2c_cfg.eri_irq); + s_close(&s_i2c_ctrl); + + } + } + } + /* fix for slave that create a sort of lock on the I2C bus when end is called and the master + is not more able to get the I2C buse working */ + R_IOPORT_PinCfg(NULL, g_pin_cfg[sda_pin].pin, IOPORT_CFG_PORT_DIRECTION_INPUT | IOPORT_CFG_PULLUP_ENABLE); + R_IOPORT_PinCfg(NULL, g_pin_cfg[scl_pin].pin, IOPORT_CFG_PORT_DIRECTION_INPUT | IOPORT_CFG_PULLUP_ENABLE); + init_ok = false; +} + + + +/* -------------------------------------------------------------------------- */ +uint8_t TwoWire::read_from(uint8_t address, uint8_t* data, uint8_t length, uint32_t timeout_us, bool sendStop) { +/* -------------------------------------------------------------------------- */ + /* ??? does this function make sense only for MASTER ???? */ + + fsp_err_t err = FSP_ERR_ASSERTION; + if(init_ok) { + if(m_setSlaveAdd != nullptr) { + err = m_setSlaveAdd(&m_i2c_ctrl, address, m_i2c_cfg.addr_mode); + } + if(err == FSP_SUCCESS) { + if(m_read != nullptr) { + bus_status = WIRE_STATUS_UNSET; + err = m_read(&m_i2c_ctrl,data,length,!sendStop); + } + } + + uint32_t const start = micros(); + while (((timeout_us == 0ul) || ((millis() - start) < timeout_us)) && + bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { + } + if ((err == FSP_SUCCESS) && (bus_status == WIRE_STATUS_UNSET)) { + handleTimeout(do_reset_on_timeout); + return 0; + } + } + + if(bus_status == WIRE_STATUS_RX_COMPLETED) { + return length; + } + + return 0; /* ???????? return value ??????? */ +} + +/* -------------------------------------------------------------------------- */ +uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32_t timeout_us , bool sendStop) { +/* -------------------------------------------------------------------------- */ + uint8_t rv = END_TX_OK; + fsp_err_t err = FSP_ERR_ASSERTION; + if(init_ok) { + if(m_setSlaveAdd != nullptr) { + err = m_setSlaveAdd(&m_i2c_ctrl, address, m_i2c_cfg.addr_mode); + } + if(err == FSP_SUCCESS) { + if(m_write != nullptr) { + bus_status = WIRE_STATUS_UNSET; + err = m_write(&m_i2c_ctrl,data,length,!sendStop); + } + } + + uint32_t const start = micros(); + while (((timeout_us == 0ul) || ((millis() - start) < timeout_us)) && + bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { + } + + if(err != FSP_SUCCESS) { + rv = END_TX_ERR_FSP; + } + else if(data_too_long) { + rv = END_TX_DATA_TOO_LONG; + } + else if(bus_status == WIRE_STATUS_UNSET) { + rv = END_TX_TIMEOUT; + handleTimeout(do_reset_on_timeout); + } + /* as far as I know is impossible to distinguish between NACK on ADDRESS and + NACK on DATA */ + else if(bus_status == WIRE_STATUS_TRANSACTION_ABORTED) { + rv = END_TX_NACK_ON_ADD; + } + } + else { + rv = END_TX_NOT_INIT; + } + + + return rv; +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::setClock(uint32_t freq) { +/* -------------------------------------------------------------------------- */ + if(init_ok && is_master) { + if(m_close != nullptr) { + m_close(&m_i2c_ctrl); + } + } + + if(is_master) { + m_i2c_cfg.rate = (i2c_master_rate_t)freq; + + int clock_divisor = (R_FSP_SystemClockHzGet(BSP_FEATURE_SCI_CLOCK) / 48000000u) - 1; + + if (is_sci) { + m_sci_i2c_extend.clock_settings.clk_divisor_value = 0; + m_sci_i2c_extend.clock_settings.cycles_value = 15; + m_sci_i2c_extend.clock_settings.snfr_value = (1); + switch (m_i2c_cfg.rate) { + case I2C_MASTER_RATE_STANDARD: + m_sci_i2c_extend.clock_settings.brr_value = 14; + m_sci_i2c_extend.clock_settings.mddr_value = 255; + m_sci_i2c_extend.clock_settings.bitrate_modulation = false; + break; + case I2C_MASTER_RATE_FAST: + default: + m_sci_i2c_extend.clock_settings.brr_value = 2; + m_sci_i2c_extend.clock_settings.mddr_value = 204; + m_sci_i2c_extend.clock_settings.bitrate_modulation = true; + break; + } + } else { + switch (m_i2c_cfg.rate) { + case I2C_MASTER_RATE_STANDARD: + m_i2c_extend.clock_settings.brl_value = 27; + m_i2c_extend.clock_settings.brh_value = 26; + m_i2c_extend.clock_settings.cks_value = 2 + clock_divisor; + break; + case I2C_MASTER_RATE_FAST: + m_i2c_extend.clock_settings.brl_value = 16; + m_i2c_extend.clock_settings.brh_value = 15; + m_i2c_extend.clock_settings.cks_value = 0 + clock_divisor; + break; +#if BSP_FEATURE_IIC_FAST_MODE_PLUS + case I2C_MASTER_RATE_FASTPLUS: + m_i2c_extend.clock_settings.brl_value = 6; + m_i2c_extend.clock_settings.brh_value = 5; + m_i2c_extend.clock_settings.cks_value = 0; + break; +#endif + } + } + } + + if(init_ok) { + if(m_open != nullptr) { + if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { + init_ok &= true; + } + else { + init_ok = false; + } + } + } +} + +/*** + * Sets the I2C timeout. + * + * This limits the maximum time to wait for the I2C hardware. If more time passes, the bus is assumed + * to have locked up (e.g. due to noise-induced glitches or faulty slaves) and the transaction is aborted. + * Optionally, the I2C hardware is also reset, which can be required to allow subsequent transactions to + * succeed in some cases (in particular when noise has made the I2C hardware think there is a second + * master that has claimed the bus). + * + * When a timeout is triggered, a flag is set that can be queried with `getWireTimeoutFlag()` and is cleared + * when `clearWireTimeoutFlag()` or `setWireTimeoutUs()` is called. + * + * Note that this timeout can also trigger while waiting for clock stretching or waiting for a second master + * to complete its transaction. So make sure to adapt the timeout to accommodate for those cases if needed. + * A typical timeout would be 25ms (which is the maximum clock stretching allowed by the SMBus protocol), + * but (much) shorter values will usually also work. + * + * In the future, a timeout will be enabled by default, so if you require the timeout to be disabled, it is + * recommended you disable it by default using `setWireTimeoutUs(0)`, even though that is currently + * the default. + * + * @param timeout a timeout value in microseconds, if zero then timeout checking is disabled + * @param reset_with_timeout if true then I2C interface will be automatically reset on timeout + * if false then I2C interface will not be reset on timeout + + */ + +/* -------------------------------------------------------------------------- */ +void TwoWire::setWireTimeout(uint32_t timeout, bool reset_with_timeout){ +/* -------------------------------------------------------------------------- */ + timed_out_flag = false; + timeout_us = timeout; + do_reset_on_timeout = reset_with_timeout; +} + +/*** + * Returns the timeout flag. + * + * @return true if timeout has occurred since the flag was last cleared. + */ +bool TwoWire::getWireTimeoutFlag(void){ + return(timed_out_flag); +} + +/*** + * Clears the timeout flag. + */ +/* -------------------------------------------------------------------------- */ +void TwoWire::clearWireTimeoutFlag(void){ +/* -------------------------------------------------------------------------- */ + timed_out_flag = false; +} + +/* + * Function handleTimeout + * Desc this gets called whenever a while loop here has lasted longer than + * timeout_us microseconds. always sets timed_out_flag + * Input reset: true causes this function to reset the hardware interface + * Output none + */ +/* -------------------------------------------------------------------------- */ +void TwoWire::handleTimeout(bool reset){ +/* -------------------------------------------------------------------------- */ + timed_out_flag = true; + if (reset) { //TBD; What do we do here? like fixHungWire()? + // TBD, Is this the way to go to reset the bus? + // Do we need more to handle devices that hangs the bus? + if(m_abort != nullptr) { + bus_status = WIRE_STATUS_UNSET; + fsp_err_t err = m_abort(&m_i2c_ctrl); + } + // TDB, Is this the right way to get back after reset? + //if(m_open != nullptr) { + // if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { + // init_ok &= true; + // } + //} + } +} + + + +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * TRANSMISSION BEGIN + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +/* -------------------------------------------------------------------------- */ +void TwoWire::beginTransmission(uint32_t address) { +/* -------------------------------------------------------------------------- */ + if (init_ok) { + data_too_long = false; + master_tx_address = address; + transmission_begun = true; + tx_index = 0; + } +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::beginTransmission(uint16_t address) { +/* -------------------------------------------------------------------------- */ + beginTransmission((uint32_t)address); +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::beginTransmission(uint8_t address){ +/* -------------------------------------------------------------------------- */ + beginTransmission((uint32_t)address); +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::beginTransmission(int address) { +/* -------------------------------------------------------------------------- */ + beginTransmission((uint32_t)address); +} + +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * TRANSMISSION END + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +/* -------------------------------------------------------------------------- */ +uint8_t TwoWire::endTransmission(bool sendStop) { +/* -------------------------------------------------------------------------- */ + uint8_t ret = write_to(master_tx_address, tx_buffer, tx_index, timeout_us, sendStop); + transmission_begun = false; + return ret; +} + +/* -------------------------------------------------------------------------- */ +uint8_t TwoWire::endTransmission(void) { +/* -------------------------------------------------------------------------- */ + return endTransmission(true); +} + +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * REQUEST FROM + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +/* -------------------------------------------------------------------------- */ +size_t TwoWire::requestFrom(uint8_t address, size_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) { +/* -------------------------------------------------------------------------- */ + if(init_ok) { + + if (isize > 0) { + // send internal address; this mode allows sending a repeated start to access + // some devices' internal registers. This function is executed by the hardware + // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) + + beginTransmission(address); + + // the maximum size of internal address is 3 bytes + if (isize > 3){ + isize = 3; + } + + // write internal register address - most significant byte first + while (isize-- > 0) { + write((uint8_t)(iaddress >> (isize*8))); + } + + endTransmission(false); + } + + // clamp to buffer length + if(quantity > I2C_BUFFER_LENGTH){ + quantity = I2C_BUFFER_LENGTH; + } + // perform blocking read into buffer + uint8_t read = read_from(address, rx_buffer, quantity, timeout_us, sendStop); + // set rx buffer iterator vars + rx_index = read; + rx_extract_index = 0; + + return (size_t)read; + } + else { + return 0; + } +} + +/* -------------------------------------------------------------------------- */ +size_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool sendStop) { +/* -------------------------------------------------------------------------- */ + return requestFrom((uint8_t)address, quantity, (uint32_t)0, (uint8_t)0, sendStop); +} + +/* -------------------------------------------------------------------------- */ +size_t TwoWire::requestFrom(uint8_t address, size_t quantity) { +/* -------------------------------------------------------------------------- */ + return requestFrom((uint8_t)address, quantity, true); +} + +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * WRITE + * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +/* -------------------------------------------------------------------------- */ +size_t TwoWire::write(uint8_t data) { +/* -------------------------------------------------------------------------- */ + if(init_ok) { + if(is_master) { + if(transmission_begun) { + if(tx_index >= I2C_BUFFER_LENGTH) { + data_too_long = true; + setWriteError(); + return 0; + } + tx_buffer[tx_index] = data; + tx_index++; + } + } + else { + if(s_write != nullptr) { + s_write(&s_i2c_ctrl,(uint8_t *)&data,1); + } + } + return 1; + } + return 0; + +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +/* -------------------------------------------------------------------------- */ +size_t TwoWire::write(const uint8_t *data, size_t quantity) { +/* -------------------------------------------------------------------------- */ + if(init_ok) { + if(is_master) { + // in master transmitter mode + for(size_t i = 0; i < quantity; ++i){ + write(data[i]); + } + } + else{ + if(s_write != nullptr) { + s_write(&s_i2c_ctrl,(uint8_t *)data,quantity); + } + } + return quantity; + } + else { + return 0; + } +} + + +// sets function called on slave write +/* -------------------------------------------------------------------------- */ +void TwoWire::onReceive( I2C_onRxCallback_f f ) { +/* -------------------------------------------------------------------------- */ + rx_callback = f; +} + +// sets function called on slave read +/* -------------------------------------------------------------------------- */ +void TwoWire::onRequest( I2C_onTxCallback_f f ) { +/* -------------------------------------------------------------------------- */ + tx_callback = f; +} + + + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) + +/* -------------------------------------------------------------------------- */ +int TwoWire::available(void) { +/* -------------------------------------------------------------------------- */ + return rx_index - rx_extract_index; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +/* -------------------------------------------------------------------------- */ +int TwoWire::read(void) { +/* -------------------------------------------------------------------------- */ + int rv = -1; + + // get each successive byte on each call + if(rx_extract_index < rx_index){ + rv = rx_buffer[rx_extract_index]; + rx_extract_index++; + } + + return rv; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +/* -------------------------------------------------------------------------- */ +int TwoWire::peek(void) { +/* -------------------------------------------------------------------------- */ + int rv = -1; + + // get each successive byte on each call + if(rx_extract_index < rx_index){ + rv = rx_buffer[rx_extract_index]; + } + + return rv; +} + +/* -------------------------------------------------------------------------- */ +void TwoWire::flush(void) { +/* -------------------------------------------------------------------------- */ + while(bus_status != WIRE_STATUS_TX_COMPLETED && bus_status != WIRE_STATUS_TRANSACTION_ABORTED) {} +} + + + + +#if WIRE_HOWMANY > 0 +TwoWire Wire(WIRE_SCL_PIN, WIRE_SDA_PIN); +#endif + +#if WIRE_HOWMANY > 1 +TwoWire Wire1(WIRE1_SCL_PIN, WIRE1_SDA_PIN); +#endif + +#if WIRE_HOWMANY > 2 +TwoWire Wire2(WIRE2_SCL_PIN, WIRE2_SDA_PIN); +#endif + +#if WIRE_HOWMANY > 3 +TwoWire Wire3(WIRE3_SCL_PIN, WIRE3_SDA_PIN); +#endif + + diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h index 8b1378917..a4145c9d2 100644 --- a/libraries/Wire/Wire.h +++ b/libraries/Wire/Wire.h @@ -1 +1,255 @@ +/* + Copyright (c) 2016 Arduino LLC. All right reserved. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#define _TIMEVAL_DEFINED +#define _SYS_SELECT_H + +#include "Arduino.h" +#include "IRQManager.h" +#include "api/HardwareI2C.h" +#include "api/Stream.h" +#include + +#include "bsp_api.h" + +#include "r_iic_master.h" +#include "r_sci_i2c.h" +#include "r_i2c_master_api.h" +#include "r_i2c_slave_api.h" + +extern "C" { + void i2c_callback(i2c_master_callback_args_t *p_args); +} + +using I2C_masterOpen_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, i2c_master_cfg_t const *const p_cfg); +using I2C_masterRead_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint8_t *const p_dest, uint32_t const bytes, bool const restart); +using I2C_masterWrite_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint8_t *constp_src, uint32_t const bytes, bool const restart); +using I2C_masterAbort_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl); +using I2C_masterSetSlaveAdd_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, uint32_t const slave, i2c_master_addr_mode_t const addr_mode); +using I2C_masterSetCallBack_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, void(*p_callback)(i2c_master_callback_args_t *), void const *const p_context, i2c_master_callback_args_t *const p_callback_memory); +using I2C_masterGetStatus_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl, i2c_master_status_t *p_status); +using I2C_masterClose_f = fsp_err_t (*)(i2c_master_ctrl_t *const p_api_ctrl); + +using I2C_slaveOpen_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, i2c_slave_cfg_t const *const p_cfg); +using I2C_slaveRead_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, uint8_t *const p_dest, uint32_t const bytes); +using I2C_slaveWrite_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, uint8_t *const p_src, uint32_t const bytes); +using I2C_slaveSetCallBack_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl, void(*p_callback)(i2c_slave_callback_args_t *), void const *const p_context, i2c_slave_callback_args_t *const p_callback_memory); +using I2C_slaveClose_f = fsp_err_t (*)(i2c_slave_ctrl_t *const p_api_ctrl); + +using I2C_onRxCallback_f = void (*)(int); +using I2C_onTxCallback_f = void (*)(void); + + +#define I2C_BUFFER_LENGTH 255 + +#define TWOWIRE_MAX_I2C_CHANNELS (3) // IIC0 to IIC2 +#define TWOWIRE_MAX_SCI_CHANNELS (10) // SCI0 to SCI9 + +#ifdef __cplusplus + +#ifndef __ARDUINO_WIRE_IMPLEMENTATION__ +#define __ARDUINO_WIRE_IMPLEMENTATION__ + +// WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + +// WIRE_HAS_TIMEOUT means Wire has setWireTimeout(), getWireTimeoutFlag +// and clearWireTimeoutFlag() +#define WIRE_HAS_TIMEOUT 1 + +// When not configured, these settings are used for the timeout +#define WIRE_DEFAULT_TIMEOUT 25000 +#define WIRE_DEFAULT_RESET_WITH_TIMEOUT 0 + +#define END_TX_OK 0 +#define END_TX_DATA_TOO_LONG 1 +#define END_TX_NACK_ON_ADD 2 +#define END_TX_NACK_ON_DATA 3 +#define END_TX_ERR_FSP 4 +#define END_TX_TIMEOUT 5 +#define END_TX_NOT_INIT 6 + + +typedef enum { + ADDRESS_MODE_7_BITS, + ADDRESS_MODE_10_BITS +} WireAddressMode_t; + +typedef enum { + WIRE_STATUS_UNSET, + WIRE_STATUS_RX_COMPLETED, + WIRE_STATUS_TX_COMPLETED, + WIRE_STATUS_TRANSACTION_ABORTED, + WIRE_STATUS_RX_REQUEST, + WIRE_STATUS_TX_REQUEST, + WIRE_STATUS_GENERAL_CALL +} WireStatus_t; + +class TwoWire : public arduino::HardwareI2C { + + public: + TwoWire(int scl_pin, int sda_pin, WireAddressMode_t am = ADDRESS_MODE_7_BITS, bool prefer_sci = false); + void begin(); + void begin(uint8_t); + void begin(uint16_t); + void begin(int); + void end(); + void setClock(uint32_t); + + void setWireTimeout(uint32_t timeout = 25000, bool reset_with_timeout = false); + bool getWireTimeoutFlag(void); + void clearWireTimeoutFlag(void); + + void beginTransmission(uint32_t); + void beginTransmission(uint16_t); + void beginTransmission(uint8_t); + void beginTransmission(int); + + uint8_t endTransmission(void); + uint8_t endTransmission(bool); + size_t requestFrom(uint8_t, size_t); + size_t requestFrom(uint8_t, size_t, bool); + size_t requestFrom(uint8_t, size_t, uint32_t, uint8_t, uint8_t); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *, size_t); + virtual int available(void); + virtual int read(void); + virtual int peek(void); + virtual void flush(void); + void onReceive( void (*)(int) ); + void onRequest( void (*)(void) ); + + void setBusStatus(WireStatus_t); + + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } + using Print::write; + + volatile uint32_t tmp_i = 0; + + void cpy_rx_buffer(uint32_t h) { + memcpy(rx_buffer,tmp_buff,h); + rx_index = h; + tmp_i = 0; + rx_extract_index = 0; + memset(tmp_buff, 0x00,I2C_BUFFER_LENGTH); + } + + fsp_err_t slave_read(volatile uint32_t d) { + if(s_read != nullptr) { + return s_read(&s_i2c_ctrl,tmp_buff + tmp_i,d); + } + else { + return FSP_ERR_ASSERTION; + } + } + + private: + + static TwoWire *g_SCIWires[TWOWIRE_MAX_SCI_CHANNELS]; + static TwoWire *g_I2CWires[TWOWIRE_MAX_I2C_CHANNELS]; + + static void WireSCIMasterCallback(i2c_master_callback_args_t *); + static void WireMasterCallback(i2c_master_callback_args_t *); + static void WireSlaveCallback(i2c_slave_callback_args_t *); + + void _begin(); + + int scl_pin; + int sda_pin; + bool init_ok; + bool is_master; + int channel; + bool is_sci; + WireAddressMode_t address_mode; + + uint32_t timeout_us; + volatile bool timed_out_flag; + bool do_reset_on_timeout; + + void handleTimeout(bool reset); + + bool transmission_begun; + bool data_too_long; + + volatile WireStatus_t bus_status; + + sci_i2c_extended_cfg_t m_sci_i2c_extend; + + iic_master_extended_cfg_t m_i2c_extend; + iic_master_instance_ctrl_t m_i2c_ctrl; + i2c_master_cfg_t m_i2c_cfg; + + iic_slave_instance_ctrl_t s_i2c_ctrl; + i2c_slave_cfg_t s_i2c_cfg; + uint16_t slave_address; + + uint32_t master_tx_address; + + I2C_masterOpen_f m_open = nullptr; + I2C_masterRead_f m_read = nullptr; + I2C_masterWrite_f m_write = nullptr; + I2C_masterAbort_f m_abort = nullptr; + I2C_masterSetSlaveAdd_f m_setSlaveAdd = nullptr; + I2C_masterSetCallBack_f m_setCallback = nullptr; + I2C_masterGetStatus_f m_getStatus = nullptr; + I2C_masterClose_f m_close = nullptr; + + I2C_slaveOpen_f s_open = nullptr; + I2C_slaveRead_f s_read = nullptr; + I2C_slaveWrite_f s_write = nullptr; + I2C_slaveSetCallBack_f s_setCallback = nullptr; + I2C_slaveClose_f s_close = nullptr; + + uint8_t tmp_buff[I2C_BUFFER_LENGTH]; + uint8_t tx_buffer[I2C_BUFFER_LENGTH]; + uint8_t rx_buffer[I2C_BUFFER_LENGTH]; + size_t rx_index; + size_t tx_index; + uint8_t rx_extract_index; + + bool require_sci; + + uint8_t read_from(uint8_t, uint8_t*, uint8_t, uint32_t, bool); + uint8_t write_to(uint8_t, uint8_t*, uint8_t, uint32_t, bool); + + bool cfg_pins(int max_index); + + I2C_onRxCallback_f rx_callback; + I2C_onTxCallback_f tx_callback; + +}; + +#if WIRE_HOWMANY > 0 +extern TwoWire Wire; +#endif +#if WIRE_HOWMANY > 1 +extern TwoWire Wire1; +#endif +#if WIRE_HOWMANY > 2 +extern TwoWire Wire2; +#endif +#if WIRE_HOWMANY > 3 +extern TwoWire Wire3; +#endif + +#endif +#endif From 7a5325db374a632cd9fb5e762d162da53f0cd1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Thu, 9 Oct 2025 22:36:57 +0200 Subject: [PATCH 13/14] Fixed a bug in timeout logic where millis() was used instead of micros() --- libraries/Wire/Wire.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index afed9b543..ad9e9ef34 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -489,7 +489,7 @@ uint8_t TwoWire::read_from(uint8_t address, uint8_t* data, uint8_t length, uint3 } uint32_t const start = micros(); - while (((timeout_us == 0ul) || ((millis() - start) < timeout_us)) && + while (((timeout_us == 0ul) || ((micros() - start) < timeout_us)) && bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { } if ((err == FSP_SUCCESS) && (bus_status == WIRE_STATUS_UNSET)) { @@ -522,7 +522,7 @@ uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32 } uint32_t const start = micros(); - while (((timeout_us == 0ul) || ((millis() - start) < timeout_us)) && + while (((timeout_us == 0ul) || ((micros() - start) < timeout_us)) && bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { } @@ -680,6 +680,7 @@ void TwoWire::clearWireTimeoutFlag(void){ void TwoWire::handleTimeout(bool reset){ /* -------------------------------------------------------------------------- */ timed_out_flag = true; + if (reset) { //TBD; What do we do here? like fixHungWire()? // TBD, Is this the way to go to reset the bus? // Do we need more to handle devices that hangs the bus? @@ -689,15 +690,18 @@ void TwoWire::handleTimeout(bool reset){ } // TDB, Is this the right way to get back after reset? //if(m_open != nullptr) { - // if(FSP_SUCCESS == m_open(&m_i2c_ctrl,&m_i2c_cfg)) { + // fsp_err_t err = m_open(&m_i2c_ctrl,&m_i2c_cfg); + // if(FSP_SUCCESS == err) { // init_ok &= true; // } //} - } + } } + + /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * TRANSMISSION BEGIN * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ From 066923bd45eb2744fdfbe49a7219bbdd5aac5388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanz=20H=C3=A4ger?= Date: Mon, 13 Oct 2025 03:58:00 +0200 Subject: [PATCH 14/14] New version that is better tested, still test version This version has more testing and some refinements for handling of timeout It still has some printouts and comments that might be useful for others review and testing When reviewed and tested, I will remove this I have also packaged the same files as an independent library that is easy to download and install as a library This can be found at: https://github.com/HanzHager/Wire --- libraries/Wire/Wire.cpp | 66 +++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index ad9e9ef34..fce1c5434 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -72,13 +72,13 @@ void TwoWire::WireSCIMasterCallback(i2c_master_callback_args_t *arg) { ptr->setBusStatus(WIRE_STATUS_TX_COMPLETED); } } - } /* -------------------------------------------------------------------------- */ void TwoWire::WireMasterCallback(i2c_master_callback_args_t *arg) { /* -------------------------------------------------------------------------- */ /* +++++ MASTER I2C not SCI Callback ++++++ */ + i2c_master_cfg_t *cfg = (i2c_master_cfg_t *)arg->p_context; TwoWire *ptr = nullptr; @@ -212,8 +212,6 @@ TwoWire::TwoWire(int scl, int sda, WireAddressMode_t am /*= ADDRESS_MODE_7_BITS* s_i2c_cfg.txi_irq = FSP_INVALID_VECTOR; s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; s_i2c_cfg.tei_irq = FSP_INVALID_VECTOR; - - } /* -------------------------------------------------------------------------- */ @@ -336,7 +334,7 @@ void TwoWire::_begin(void) { m_i2c_cfg.p_callback = WireMasterCallback; m_i2c_extend.timeout_mode = IIC_MASTER_TIMEOUT_MODE_SHORT; - m_i2c_extend.timeout_scl_low = IIC_MASTER_TIMEOUT_SCL_LOW_DISABLED; + m_i2c_extend.timeout_scl_low = IIC_MASTER_TIMEOUT_SCL_LOW_ENABLED; } m_i2c_cfg.channel = channel; @@ -483,7 +481,7 @@ uint8_t TwoWire::read_from(uint8_t address, uint8_t* data, uint8_t length, uint3 } if(err == FSP_SUCCESS) { if(m_read != nullptr) { - bus_status = WIRE_STATUS_UNSET; + setBusStatus(WIRE_STATUS_UNSET); err = m_read(&m_i2c_ctrl,data,length,!sendStop); } } @@ -501,7 +499,7 @@ uint8_t TwoWire::read_from(uint8_t address, uint8_t* data, uint8_t length, uint3 if(bus_status == WIRE_STATUS_RX_COMPLETED) { return length; } - + return 0; /* ???????? return value ??????? */ } @@ -512,15 +510,30 @@ uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32 fsp_err_t err = FSP_ERR_ASSERTION; if(init_ok) { if(m_setSlaveAdd != nullptr) { + setBusStatus(WIRE_STATUS_UNSET); err = m_setSlaveAdd(&m_i2c_ctrl, address, m_i2c_cfg.addr_mode); } - if(err == FSP_SUCCESS) { + if((err == FSP_SUCCESS) && (bus_status != WIRE_STATUS_TRANSACTION_ABORTED)) { + if(m_write != nullptr) { - bus_status = WIRE_STATUS_UNSET; + setBusStatus(WIRE_STATUS_UNSET); err = m_write(&m_i2c_ctrl,data,length,!sendStop); } - } + if (err==FSP_ERR_INVALID_SIZE) { + rv = END_TX_DATA_TOO_LONG; + Serial.println(F("Invalid size when trying to write")); + } + + } else // No FSP_SUCCESS in m_setSlaveAdd or WIRE_STATUS_TRANSACTION_ABORTED + if (err == FSP_ERR_IN_USE) { + Serial.println(F("An I2C Transaction is in progress. when setting slave address")); + } else + if (bus_status == WIRE_STATUS_TRANSACTION_ABORTED){ + rv = END_TX_NACK_ON_ADD; + Serial.println(F("Transaction aborted -> NACK on ADDR")); + } + // If FSP_SUCCESS, wait for change in bus_status or timeout uint32_t const start = micros(); while (((timeout_us == 0ul) || ((micros() - start) < timeout_us)) && bus_status == WIRE_STATUS_UNSET && err == FSP_SUCCESS) { @@ -531,6 +544,7 @@ uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32 } else if(data_too_long) { rv = END_TX_DATA_TOO_LONG; + Serial.println(F("Trying to write more than II2C_BUFFER_LENGTH, buffer truncated before written")); } else if(bus_status == WIRE_STATUS_UNSET) { rv = END_TX_TIMEOUT; @@ -539,7 +553,8 @@ uint8_t TwoWire::write_to(uint8_t address, uint8_t* data, uint8_t length, uint32 /* as far as I know is impossible to distinguish between NACK on ADDRESS and NACK on DATA */ else if(bus_status == WIRE_STATUS_TRANSACTION_ABORTED) { - rv = END_TX_NACK_ON_ADD; + if (length==0) rv = END_TX_NACK_ON_ADD; + if (rv != END_TX_NACK_ON_ADD) rv = END_TX_NACK_ON_DATA; } } else { @@ -593,13 +608,13 @@ void TwoWire::setClock(uint32_t freq) { m_i2c_extend.clock_settings.brh_value = 15; m_i2c_extend.clock_settings.cks_value = 0 + clock_divisor; break; -#if BSP_FEATURE_IIC_FAST_MODE_PLUS case I2C_MASTER_RATE_FASTPLUS: +#if BSP_FEATURE_IIC_FAST_MODE_PLUS m_i2c_extend.clock_settings.brl_value = 6; m_i2c_extend.clock_settings.brh_value = 5; m_i2c_extend.clock_settings.cks_value = 0; - break; #endif + break; } } } @@ -640,9 +655,7 @@ void TwoWire::setClock(uint32_t freq) { * @param timeout a timeout value in microseconds, if zero then timeout checking is disabled * @param reset_with_timeout if true then I2C interface will be automatically reset on timeout * if false then I2C interface will not be reset on timeout - */ - /* -------------------------------------------------------------------------- */ void TwoWire::setWireTimeout(uint32_t timeout, bool reset_with_timeout){ /* -------------------------------------------------------------------------- */ @@ -680,28 +693,31 @@ void TwoWire::clearWireTimeoutFlag(void){ void TwoWire::handleTimeout(bool reset){ /* -------------------------------------------------------------------------- */ timed_out_flag = true; + Serial.println(F("Handling TwoWire::handleTimeout()")); if (reset) { //TBD; What do we do here? like fixHungWire()? // TBD, Is this the way to go to reset the bus? // Do we need more to handle devices that hangs the bus? + Serial.print(F("with reset Abort result: ")); if(m_abort != nullptr) { - bus_status = WIRE_STATUS_UNSET; + //setBusStatus(WIRE_STATUS_TRANSACTION_ABORTED); fsp_err_t err = m_abort(&m_i2c_ctrl); + Serial.println(err); } // TDB, Is this the right way to get back after reset? - //if(m_open != nullptr) { - // fsp_err_t err = m_open(&m_i2c_ctrl,&m_i2c_cfg); - // if(FSP_SUCCESS == err) { - // init_ok &= true; - // } - //} + if(m_open != nullptr) { + fsp_err_t err = m_open(&m_i2c_ctrl,&m_i2c_cfg); + if(FSP_SUCCESS == err) { + init_ok &= true; + } + Serial.print(F(" Open result: ")); + Serial.println(err); + } + // Is it neccesarry to do the open after the abort? + // Is that more to be done after the abort to get back to same settings } } - - - - /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * TRANSMISSION BEGIN * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */