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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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 * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */