From c7dbb1dc0c0ac6c44dd6c1e0c6b2325e0e35c5c8 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 21 Jul 2022 00:04:25 +0200 Subject: [PATCH] RP2040: Fix I2C lockups and improve error handling Problem: * in edge-case scenarios the tx empty interrupt was still enabled after a transmission was finished. This would lead to endless interrupt tail chaining that completely starved the system. Solution: * all irqs are now disabled at the end of a transaction by default Error handling: * all error condition irqs like over and underruns of tx and rx fifos are now enabled and handled with an wake-up of the sleeping thread plus disabling of all irqs Optimizations: * irq status register is only read once for evalutation in the irq handler * better utilization of the rx fifos during reception, which are now only read if all data has been successfully received. --- os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.c | 452 ++++++++++++++++-------- os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.h | 12 +- 2 files changed, 314 insertions(+), 150 deletions(-) diff --git a/os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.c b/os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.c index a89ed73bb6..340a159263 100644 --- a/os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.c +++ b/os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.c @@ -1,4 +1,6 @@ /* + ChibiOS - Copyright (C) 2022 Stefan Kerkmann + ChibiOS - Copyright (C) 2021 Hanya ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio Licensed under the Apache License, Version 2.0 (the "License"); @@ -52,140 +54,276 @@ I2CDriver I2CD2; /* Driver local variables and types. */ /*===========================================================================*/ +#define I2C_OVERRUN_ERRORS \ + (I2C_IC_INTR_STAT_M_RX_OVER | I2C_IC_INTR_STAT_M_RX_UNDER | \ + I2C_IC_INTR_STAT_M_TX_OVER) + +#define I2C_ERROR_INTERRUPTS \ + (I2C_IC_INTR_MASK_M_TX_ABRT | I2C_IC_INTR_MASK_M_TX_OVER | \ + I2C_IC_INTR_MASK_M_RX_OVER | I2C_IC_INTR_MASK_M_RX_UNDER) + /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ +/** + * @brief Calculates the waiting time which is 10 times the SCL period duration. + */ +static sysinterval_t i2c_lld_get_wait_time(I2CDriver *i2cp){ + uint32_t baudrate = i2cp->config->baudrate; + if (baudrate <= 100000U) { + return OSAL_US2I(100); + } else if (baudrate <= 400000U) { + return OSAL_US2I(25); + } else { + return OSAL_US2I(10); + } +} + +/** + * @brief Tries to disable the I2C peripheral. + */ +static msg_t i2c_lld_disable(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + systime_t start, end; + + /* Calculating the time window for the timeout on the enable condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, i2c_lld_get_wait_time(i2cp)); + + dp->ENABLE &= ~I2C_IC_ENABLE_ENABLE; + while ((dp->ENABLESTATUS & I2C_IC_ENABLE_STATUS_IC_EN) != 0U) { + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + return MSG_TIMEOUT; + } + } + + return MSG_OK; +} + +/** + * @brief Aborts any ongoing transmission of the I2C peripheral. + */ +static msg_t i2c_lld_abort_transmission(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + systime_t start, end; + + /* Calculating the time window for the timeout on the abort condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, i2c_lld_get_wait_time(i2cp)); + + /* Disable all interrupts as a pre-caution. */ + dp->INTRMASK = 0U; + /* Enable peripheral to issue abort. */ + dp->ENABLE |= I2C_IC_ENABLE_ENABLE; + /* Issue abort. */ + dp->ENABLE |= I2C_IC_ENABLE_ABORT; + + /* Wait for transmission the be aborted */ + while((dp->RAWINTRSTAT & I2C_IC_INTR_STAT_M_TX_ABRT) == 0U) { + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { + return MSG_TIMEOUT; + } + } + + (void)dp->CLRTXABRT; + return MSG_OK; +} + +/** + * @brief Handles transmission errors by waking the sleeping thread + * and setting the error reasons. + */ +void i2c_lld_handle_errors(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + + if (dp->TXABRTSOURCE & I2C_IC_TX_ABRT_SOURCE_ARB_LOST) { + i2cp->errors |= I2C_ARBITRATION_LOST; + } + + if (dp->RAWINTRSTAT & I2C_OVERRUN_ERRORS) { + i2cp->errors |= I2C_OVERRUN; + } + + /* Disable all interrupts. */ + dp->INTRMASK = 0U; + (void)dp->CLRINTR; + (void)dp->CLRTXABRT; + _i2c_wakeup_error_isr(i2cp); +} + /** * @brief Calculates and set up clock settings. */ -static void setup_frequency(I2CDriver *i2cp) { +static void i2c_lld_setup_frequency(I2CDriver *i2cp) { I2C_TypeDef *dp = i2cp->i2c; - // [us] SS FS FS+ - // MIN_SCL_LOWtime_FS: 4.7 1.3 0.5 - // MIN_SCL_HIGHtime_FS: 4.0 0.6 0.26 - // max tSP: - 0.05 0.05 - // min tSU:DAT: 0.25 0.1 0.05 - // tHD:DAT: 0 0 0 + /* [us] SS FS FS+ + * MIN_SCL_LOWtime_FS: 4.7 1.3 0.5 + * MIN_SCL_HIGHtime_FS: 4.0 0.6 0.26 + * max tSP: - 0.05 0.05 + * min tSU:DAT: 0.25 0.1 0.05 + * tHD:DAT: 0 0 0 + */ uint32_t minLowfs, minHighfs; uint32_t baudrate = i2cp->config->baudrate; - if (baudrate <= 100000) { + if (baudrate <= 100000U) { // ns - minLowfs = 4700; - minHighfs = 4000; - } else if (baudrate <= 400000) { - minLowfs = 1300; - minHighfs = 600; + minLowfs = 4700U; + minHighfs = 4000U; + } else if (baudrate <= 400000U) { + minLowfs = 1300U; + minHighfs = 600U; } else { - minLowfs = 500; - minHighfs = 260; + minLowfs = 500U; + minHighfs = 260U; } - uint32_t sys_clk = halClockGetPointX(clk_sys) / 100000; - //uint32_t lcntfs = (minLowfs * sys_clk) / 10000 + 1; - uint32_t hcntfs = (minHighfs * sys_clk) / 10000 + 1; - uint32_t lcntfs = (minLowfs * hcntfs) / ((10000000 / baudrate) * 100 - minLowfs) + 1; + halfreq_t sys_clk = halClockGetPointX(clk_sys) / 100000; + uint32_t hcntfs = (minHighfs * sys_clk) / 10000U + 1U; + uint32_t lcntfs = (minLowfs * hcntfs) / ((10000000U / baudrate) * 100U - minLowfs) + 1U; - uint32_t sdahd; - if (baudrate < 1000000) { - //sdahd = (sys_clk * 300) * (1/1e9) ; - sdahd = (sys_clk * 3) / 100 + 1; + uint32_t sdahd = 0U; + if (baudrate < 1000000U) { + sdahd = (sys_clk * 3U) / 100U + 1U; } else { - //sdahd = (sys_clk * 120) * (1/1e9); - sdahd = (sys_clk * 3) / 250 + 1; + sdahd = (sys_clk * 3U) / 250U + 1U; } - dp->ENABLE = 0; - /* Always Fast Mode */ - dp->FSSCLHCNT = hcntfs - 7; - dp->FSSCLLCNT = lcntfs - 1; - dp->FSSPKLEN = 2; + dp->FSSCLHCNT = hcntfs - 7U; + dp->FSSCLLCNT = lcntfs - 1U; + dp->FSSPKLEN = 2U; - dp->SDAHOLD |= (sdahd << I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD_Pos) & I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD; - - //dp->ENABLE = 1; + dp->SDAHOLD |= sdahd & I2C_IC_SDA_HOLD_IC_SDA_TX_HOLD; } /** - * @brief Interrupt processing. + * @brief Requests data to be received, actual reception is done in the interrupt handler. */ -static void serve_interrupt(I2CDriver *i2cp) { +static void i2c_lld_request_data(I2CDriver *i2cp) { I2C_TypeDef *dp = i2cp->i2c; + uint32_t data = I2C_IC_DATA_CMD_CMD; - if (i2cp->state == I2C_ACTIVE_TX) { - /* Transmission phase. */ - if (dp->INTRSTAT & I2C_IC_INTR_STAT_R_TX_EMPTY_Msk) { - if (i2cp->txbytes) { - while (i2cp->txbytes && (dp->TXFLR & I2C_IC_TXFLR_TXFLR_Msk) < 16) { - dp->DATACMD = (uint32_t)i2cp->txbuf[i2cp->txindex] | - (i2cp->txbytes == 1 ? I2C_IC_DATA_CMD_STOP : 0); - i2cp->txindex++; - i2cp->txbytes--; - } - - if (i2cp->txbytes == 0U) { - // Disable TX_EMPTY irq - dp->CLR.CON = I2C_IC_CON_TX_EMPTY_CTRL; - dp->CLR.INTRMASK = I2C_IC_INTR_MASK_M_TX_EMPTY; - } - return; - } + /* RP2040 Designware I2C peripheral has FIFO depth of 16 elements. As we + * specify that the TX_EMPTY interrupt only fires if the TX FIFO is + * truly empty we don't need to check the current fill level. */ + uint32_t batch = MIN(16U, i2cp->rxbytes); + + if (i2cp->send_restart) { + data |= I2C_IC_DATA_CMD_RESTART; + i2cp->send_restart = false; + } + + /* Setup RX FIFO trigger level to only trigger when the batch has been + * completely received. Therefore we don't need to check if there are any + * bytes still pending to be received. */ + dp->RXTL = batch > 1U ? batch - 1U : 0U; + + while (batch > 0U) { + /* Send STOP after last byte. */ + if (i2cp->rxbytes == 1U) { + data |= I2C_IC_DATA_CMD_STOP; } - } else { - /* Receive phase. */ - if (dp->INTRSTAT & I2C_IC_INTR_STAT_R_RX_FULL_Msk) { - /* Read out received data. */ - i2cp->rxbuf[i2cp->rxindex] = (uint8_t)dp->DATACMD; - i2cp->rxindex++; - i2cp->rxbytes--; - if (i2cp->rxbytes > 0) { - // Set to master read - dp->DATACMD = I2C_IC_DATA_CMD_CMD | - (i2cp->rxbytes == 1 ? I2C_IC_DATA_CMD_STOP : 0); - return; - } + dp->DATACMD = data; + + batch--; + i2cp->rxbytes--; + data = I2C_IC_DATA_CMD_CMD; + } + + /* Clear TX FIFO empty interrupt, it will be re-activated when data has been + * received. */ + dp->CLR.INTRMASK = I2C_IC_INTR_MASK_M_TX_EMPTY; + /* Enable RX FULL interrupt to process received data. */ + dp->SET.INTRMASK = I2C_IC_INTR_STAT_R_RX_FULL; +} + +/** + * @brief Fills TX FIFO with data to be send. + */ +static void i2c_lld_transmit_data(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + uint32_t data; + + while (i2cp->txbytes > 0U && dp->STATUS & I2C_IC_STATUS_TFNF) { + data = (uint32_t)*i2cp->txptr; + + /* Send STOP after last byte */ + if (i2cp->txbytes == 1U) { + data |= I2C_IC_DATA_CMD_STOP; } + dp->DATACMD = data; + + i2cp->txptr++; + i2cp->txbytes--; } - if (dp->INTRSTAT & I2C_IC_INTR_STAT_R_STOP_DET) { - /* Clear irq flag. */ - (void)dp->CLRSTOPDET; + /* Nothing more to send, disable TX FIFO empty interrupt. */ + if (i2cp->txbytes == 0U) { + dp->CLR.INTRMASK = I2C_IC_INTR_MASK_M_TX_EMPTY; + } +} + +/** + * @brief I2C shared ISR code. + * + * @param[in] i2cp pointer to the @p I2CDriver object + */ +static void i2c_lld_serve_interrupt(I2CDriver *i2cp) { + I2C_TypeDef *dp = i2cp->i2c; + uint32_t intr = dp->INTRSTAT; + + /* Transmission error detected. */ + if (intr & I2C_ERROR_INTERRUPTS) { + return i2c_lld_handle_errors(i2cp); + } + + /* If the TX FIFO is empty we can request or send more data. */ + if (intr & I2C_IC_INTR_STAT_R_TX_EMPTY) { if (i2cp->state == I2C_ACTIVE_TX) { - /* TX end. */ - if (i2cp->rxbytes > 0U) { - /* Setup RX. */ - /* Set interrupt mask. */ - dp->INTRMASK = I2C_IC_INTR_MASK_M_STOP_DET | - I2C_IC_INTR_MASK_M_TX_ABRT | - I2C_IC_INTR_MASK_M_RX_FULL; - - /* Set read flag. */ - dp->DATACMD = I2C_IC_DATA_CMD_CMD | - I2C_IC_CON_IC_RESTART_EN | - (i2cp->rxbytes == 1 ? I2C_IC_DATA_CMD_STOP : 0); - - /* State change to RX. */ - i2cp->state = I2C_ACTIVE_RX; - return; - } + i2c_lld_transmit_data(i2cp); } else { - /* RX end. */ - dp->CLR.INTRMASK = I2C_IC_INTR_MASK_M_RX_FULL; + i2c_lld_request_data(i2cp); } + return; } - if (dp->INTRSTAT & I2C_IC_INTR_STAT_R_TX_ABRT_Msk) { - // Reason, dp->TXABRTSOURCE - i2cp->errors = dp->TXABRTSOURCE; + if (intr & I2C_IC_INTR_STAT_R_RX_FULL) { + while (dp->STATUS & I2C_IC_STATUS_RFNE) { + /* Read out received data. */ + *i2cp->rxptr= (uint8_t)dp->DATACMD; + i2cp->rxptr++; + } - _i2c_wakeup_error_isr(i2cp); + if (i2cp->rxbytes == 0U) { + /* Everything is received, therefore disable all FIFO IRQs. */ + dp->CLR.INTRMASK = I2C_IC_INTR_MASK_M_RX_FULL | I2C_IC_INTR_STAT_R_TX_EMPTY; + } else { + /* Enable TX FIFO empty IRQ to request more data. */ + dp->SET.INTRMASK = I2C_IC_INTR_STAT_R_TX_EMPTY; + } + return; } - /* Clear interrupt flags. */ - (void)dp->CLRINTR; + if (intr & I2C_IC_INTR_STAT_R_STOP_DET) { + /* Clear irq flag. */ + (void)dp->CLRSTOPDET; + if (i2cp->state == I2C_ACTIVE_TX && i2cp->rxbytes > 0U) { + /* State change to RX. */ + i2cp->state = I2C_ACTIVE_RX; + /* Restart communication. */ + i2cp->send_restart = true; + + /* Enable TX FIFO empty IRQ to request more data to be received. */ + dp->SET.INTRMASK = I2C_IC_INTR_STAT_R_TX_EMPTY; + return; + } + } + /* Transmission complete, disable and clear all interrupts. */ + dp->INTRMASK = 0U; + (void)dp->CLRINTR; _i2c_wakeup_isr(i2cp); } @@ -196,9 +334,10 @@ static void serve_interrupt(I2CDriver *i2cp) { #if (RP_I2C_USE_I2C0 == TRUE) || defined(__DOXYGEN__) OSAL_IRQ_HANDLER(RP_I2C0_IRQ_HANDLER) { - OSAL_IRQ_PROLOGUE(); - serve_interrupt(&I2CD1); + + i2c_lld_serve_interrupt(&I2CD1); + OSAL_IRQ_EPILOGUE(); } @@ -207,9 +346,10 @@ OSAL_IRQ_HANDLER(RP_I2C0_IRQ_HANDLER) { #if (RP_I2C_USE_I2C1 == TRUE) || defined(__DOXYGEN__) OSAL_IRQ_HANDLER(RP_I2C1_IRQ_HANDLER) { - OSAL_IRQ_PROLOGUE(); - serve_interrupt(&I2CD2); + + i2c_lld_serve_interrupt(&I2CD2); + OSAL_IRQ_EPILOGUE(); } @@ -274,8 +414,10 @@ void i2c_lld_start(I2CDriver *i2cp) { #endif } - /* Disable for setup. */ - dp->ENABLE = 0; + /* Disable i2c peripheral for setup phase. */ + if (i2c_lld_disable(i2cp) != MSG_OK) { + return; + } dp->CON = I2C_IC_CON_IC_SLAVE_DISABLE | I2C_IC_CON_IC_RESTART_EN | @@ -283,12 +425,24 @@ void i2c_lld_start(I2CDriver *i2cp) { I2C_IC_CON_IC_10BITADDR_MASTER | #endif (2U << I2C_IC_CON_SPEED_Pos) | // Always Fast Mode - I2C_IC_CON_MASTER_MODE; + I2C_IC_CON_MASTER_MODE | + I2C_IC_CON_STOP_DET_IF_MASTER_ACTIVE | + I2C_IC_CON_TX_EMPTY_CTRL; + + + dp->RXTL = 0U; + dp->TXTL = 0U; - dp->RXTL = 0; - dp->TXTL = 0; + i2c_lld_setup_frequency(i2cp); - setup_frequency(i2cp); + /* Clear interrupt mask. */ + dp->INTRMASK = 0U; + + /* Enable peripheral */ + dp->ENABLE = I2C_IC_ENABLE_ENABLE; + + /* Clear interrupts. */ + (void)dp->CLRINTR; } /** @@ -301,7 +455,9 @@ void i2c_lld_start(I2CDriver *i2cp) { void i2c_lld_stop(I2CDriver *i2cp) { if (i2cp->state != I2C_STOP) { - + if (i2c_lld_disable(i2cp) != MSG_OK) { + i2c_lld_abort_transmission(i2cp); + } #if RP_I2C_USE_I2C0 == TRUE if (&I2CD1 == i2cp) { nvicDisableVector(RP_I2C0_IRQ_NUMBER); @@ -317,7 +473,6 @@ void i2c_lld_stop(I2CDriver *i2cp) { hal_lld_peripheral_reset(RESETS_ALLREG_I2C1); } #endif - } } @@ -345,7 +500,6 @@ void i2c_lld_stop(I2CDriver *i2cp) { msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, uint8_t *rxbuf, size_t rxbytes, sysinterval_t timeout) { - msg_t msg; systime_t start, end; I2C_TypeDef *dp = i2cp->i2c; @@ -364,8 +518,11 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, break; } + /* Attempt to clear activity bit. */ + (void)dp->CLRACTIVITY; + /* If the system time went outside the allowed window then a timeout - condition is returned.*/ + condition is returned. */ if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) { return MSG_TIMEOUT; } @@ -374,40 +531,43 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, } i2cp->txbytes = 0U; + i2cp->txptr = NULL; i2cp->rxbytes = rxbytes; - i2cp->txindex = 0U; - i2cp->rxindex = 0U; - i2cp->txbuf = NULL; - i2cp->rxbuf = rxbuf; + i2cp->rxptr = rxbuf; + i2cp->send_restart = false; - dp->ENABLE = 0; + /* Disable I2C peripheral during setup phase. */ + msg = i2c_lld_disable(i2cp); + if (msg != MSG_OK) { + return msg; + } /* Set address. */ dp->TAR = addr & I2C_IC_TAR_IC_TAR_Msk; - /* Set interrupt mask, active low. */ - dp->INTRMASK = I2C_IC_INTR_MASK_M_STOP_DET | - I2C_IC_INTR_MASK_M_TX_ABRT | - I2C_IC_INTR_MASK_M_RX_FULL; + /* Clear interrupt mask. */ + dp->INTRMASK = 0U; + + /* Enable peripheral */ + dp->ENABLE = I2C_IC_ENABLE_ENABLE; - dp->ENABLE = 1; + /* Clear interrupts. */ + (void)dp->CLRINTR; - /* Read flag. */ - dp->DATACMD = I2C_IC_DATA_CMD_CMD | - (i2cp->rxbytes == 1 ? I2C_IC_DATA_CMD_STOP : 0); + /* Set interrupt mask. */ + dp->INTRMASK = I2C_IC_INTR_MASK_M_STOP_DET | + I2C_IC_INTR_MASK_M_TX_EMPTY | + I2C_ERROR_INTERRUPTS; /* Waits for the operation completion or a timeout.*/ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); - /* In case of a software timeout a STOP is sent as an extreme attempt - to release the bus and DMA is forcibly disabled.*/ if (msg == MSG_TIMEOUT) { - /* Clear irq flags. */ + /* Disable and clear interrupts. */ + dp->INTRMASK = 0U; (void)dp->CLRINTR; } - dp->ENABLE = 0; - return msg; } @@ -453,9 +613,11 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, while (true) { osalSysLock(); - if ((dp->STATUS & I2C_IC_STATUS_ACTIVITY) == 0) { + if ((dp->STATUS & I2C_IC_STATUS_ACTIVITY) == 0U) { break; } + /* Attempt to clear activity bit. */ + (void)dp->CLRACTIVITY; /* If the system time went outside the allowed window then a timeout condition is returned.*/ @@ -467,37 +629,43 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, } i2cp->txbytes = txbytes; + i2cp->txptr = txbuf; i2cp->rxbytes = rxbytes; - i2cp->txindex = 0U; - i2cp->rxindex = 0U; - i2cp->txbuf = txbuf; - i2cp->rxbuf = rxbuf; + i2cp->rxptr = rxbuf; + i2cp->send_restart = false; - dp->ENABLE = 0; + /* disabel i2c peripheral during setup phase. */ + msg = i2c_lld_disable(i2cp); + if (msg != MSG_OK) { + return msg; + } /* Set target address. */ - dp->TAR = addr & I2C_IC_TAR_IC_TAR_Msk; + dp->TAR = addr & I2C_IC_TAR_IC_TAR; + + /* Clear interrupt mask. */ + dp->INTRMASK = 0U; - /* TX_EMPTY irq active. */ - dp->CON |= I2C_IC_CON_TX_EMPTY_CTRL; + /* Enable peripheral */ + dp->ENABLE = I2C_IC_ENABLE_ENABLE; + + /* Clear interrupts. */ + (void)dp->CLRINTR; /* Set interrupt mask. */ dp->INTRMASK = I2C_IC_INTR_MASK_M_STOP_DET | - I2C_IC_INTR_MASK_M_TX_ABRT | - I2C_IC_INTR_MASK_M_TX_EMPTY; - - dp->ENABLE = 1; + I2C_IC_INTR_MASK_M_TX_EMPTY | + I2C_ERROR_INTERRUPTS; /* Waits for the operation completion or a timeout.*/ msg = osalThreadSuspendTimeoutS(&i2cp->thread, timeout); if (msg == MSG_TIMEOUT) { - /* Clear irq flags. */ + /* Disable and clear interrupts. */ + dp->INTRMASK = 0U; (void)dp->CLRINTR; } - dp->ENABLE = 0; - return msg; } diff --git a/os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.h b/os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.h index ff278adeef..4f6dddeff2 100644 --- a/os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.h +++ b/os/hal/ports/RP/LLD/I2Cv1/hal_i2c_lld.h @@ -140,21 +140,17 @@ struct I2CDriver { */ size_t rxbytes; /** - * @brief Next index of data in TX buffer. + * @brief Send restart on next transmission. */ - size_t txindex; - /** - * @brief Next index of RX buffer. - */ - size_t rxindex; + bool send_restart; /** * @brief Buffer for TX. */ - const uint8_t *txbuf; + const uint8_t *txptr; /** * @brief Buffer for RX. */ - uint8_t *rxbuf; + uint8_t *rxptr; }; /*===========================================================================*/