diff --git a/src/shared/drivers/i2c/I2CDriver-f7.cpp b/src/shared/drivers/i2c/I2CDriver-f7.cpp index 27f9c32a2430baee304607ec268943f08f74f8e8..2ef687279bbbe89860c99ed77d2a2d19d493035f 100644 --- a/src/shared/drivers/i2c/I2CDriver-f7.cpp +++ b/src/shared/drivers/i2c/I2CDriver-f7.cpp @@ -41,17 +41,23 @@ static const int N_SCL_BITBANG = static const uint8_t I2C_PIN_ALTERNATE_FUNCTION = 4; ///< Alternate Function number of the I2C peripheral pins -static uint8_t PRESC_STD; ///< PRESC for STANDARD speed -static uint8_t SCLH_STD; ///< SCLH for STANDARD speed -static uint8_t SCLL_STD; ///< SCLL for STANDARD speed - -static uint8_t PRESC_F; ///< PRESC for FAST speed -static uint8_t SCLH_F; ///< SCLH for FAST speed -static uint8_t SCLL_F; ///< SCLL for FAST speed - -static uint8_t PRESC_FP; ///< PRESC for FAST PLUS speed -static uint8_t SCLH_FP; ///< SCLH for FAST PLUS speed -static uint8_t SCLL_FP; ///< SCLL for FAST PLUS speed +static uint8_t PRESC_STD; ///< PRESC for STANDARD speed +static uint8_t SCLH_STD; ///< SCLH for STANDARD speed +static uint8_t SCLL_STD; ///< SCLL for STANDARD speed +static uint8_t SCLDEL_STD; ///< SCLDEL for STANDARD speed +static uint8_t SDADEL_STD; ///< SDADEL for STANDARD speed + +static uint8_t PRESC_F; ///< PRESC for FAST speed +static uint8_t SCLH_F; ///< SCLH for FAST speed +static uint8_t SCLL_F; ///< SCLL for FAST speed +static uint8_t SCLDEL_F; ///< SCLDEL for FAST speed +static uint8_t SDADEL_F; ///< SDADEL for FAST speed + +static uint8_t PRESC_FP; ///< PRESC for FAST PLUS speed +static uint8_t SCLH_FP; ///< SCLH for FAST PLUS speed +static uint8_t SCLL_FP; ///< SCLL for FAST PLUS speed +static uint8_t SCLDEL_FP; ///< SCLDEL for FAST PLUS speed +static uint8_t SDADEL_FP; ///< SDADEL for FAST PLUS speed } // namespace I2CConsts /** @@ -59,14 +65,14 @@ static uint8_t SCLL_FP; ///< SCLL for FAST PLUS speed * peripheral */ void calculateTimings(uint32_t f, uint32_t fi2c, uint8_t *presc, uint8_t *sclh, - uint8_t *scll) + uint8_t *scll, uint8_t *scldel, uint8_t *sdadel) { // The formula for the clock is: // t_SCL = [(SCLL + 1) + (SCLH + 1)] * (PRESC + 1) * t_I2CCLK + t_sync; // calculating the "smallest" prescaler so that we can handle in a more // refined way (with SCLL and SCLH) the length of high and low phases. - uint32_t temp_presc = f / (256 * fi2c); + uint32_t temp_presc = f / (64 * fi2c); // presc is 4 bit long, so avoiding overflow if (temp_presc >= 16) @@ -86,6 +92,31 @@ void calculateTimings(uint32_t f, uint32_t fi2c, uint8_t *presc, uint8_t *sclh, // correcting for the 250ns delay of the peripheral (250ns = 12 I2C clocks) // distributing the correction on SCLL and SCLH *sclh = *scll = (f / (fi2c * 2 * (*presc + 1)) - 1) - (7 / (*presc + 1)); + + // SCLDEL >= (t_r + t_su) / ((PRESC+1)*t_i2c) - 1 ; approximated without + // subtracting 1 + uint32_t scldly = 0, sdadly = 0; + if (fi2c == 100) + { + scldly = 1250 * f / (*presc + 1) / 1000000; + sdadly = (3450 - 1000 - 260) * f / (*presc + 1) / 1000000; + } + else if (fi2c == 400) + { + scldly = 400 * f / (*presc + 1) / 1000000; + sdadly = (900 - 300 - 260) * f / (*presc + 1) / 1000000; + } + else if (fi2c == 1000) + { + scldly = 170 * f / (*presc + 1) / 1000000; + sdadly = (450 - 120 - 260) * f / (*presc + 1) / 1000000; + } + + // max value of scldel is 15 + *scldel = ((scldly < 16) ? (scldly - 1) : 15); + + // max value of sdadel is 15 m + *sdadel = ((sdadly < 16) ? (sdadly - 1) : 15); } #ifdef I2C1 @@ -380,21 +411,25 @@ void I2CDriver::init() ClockUtils::getAPBPeripheralsClock(ClockUtils::APB::APB1) / 1000; calculateTimings(f, 100, &I2CConsts::PRESC_STD, &I2CConsts::SCLH_STD, - &I2CConsts::SCLL_STD); + &I2CConsts::SCLL_STD, &I2CConsts::SCLDEL_STD, + &I2CConsts::SDADEL_STD); calculateTimings(f, 400, &I2CConsts::PRESC_F, &I2CConsts::SCLH_F, - &I2CConsts::SCLL_F); + &I2CConsts::SCLL_F, &I2CConsts::SCLDEL_F, + &I2CConsts::SDADEL_F); calculateTimings(f, 1000, &I2CConsts::PRESC_FP, &I2CConsts::SCLH_FP, - &I2CConsts::SCLL_FP); + &I2CConsts::SCLL_FP, &I2CConsts::SCLDEL_FP, + &I2CConsts::SDADEL_FP); // I2CCLK < (t_low - t_filters) / 4 // I2CCLK < t_high // I2CCLK < 4/3 * t_SCL + i2c->CR1 |= I2C_CR1_PE; } bool I2CDriver::read(const I2CSlaveConfig &slaveConfig, void *buffer, - size_t nBytes) + const size_t &nBytes) { // Setting up the read transaction transaction.operation = Operation::READ; @@ -413,7 +448,7 @@ bool I2CDriver::read(const I2CSlaveConfig &slaveConfig, void *buffer, }; bool I2CDriver::write(const I2CSlaveConfig &slaveConfig, const void *buffer, - size_t nBytes, bool generateStop) + const size_t &nBytes, bool generateStop) { // Setting up the write transaction transaction.operation = Operation::WRITE; @@ -518,28 +553,29 @@ void I2CDriver::setupPeripheral(const I2CSlaveConfig &slaveConfig) if (slaveConfig.speed == Speed::STANDARD) { i2c->TIMINGR = - (I2CConsts::PRESC_STD << I2C_TIMINGR_PRESC_Pos) | // PRESC - (I2CConsts::SCLL_STD << I2C_TIMINGR_SCLL_Pos) | // SCLL - (I2CConsts::SCLH_STD << I2C_TIMINGR_SCLH_Pos) | // SCLH - (0x1 << I2C_TIMINGR_SDADEL_Pos) | // SDADEL - (0x1 << I2C_TIMINGR_SCLDEL_Pos); // SCLDEL + (I2CConsts::PRESC_STD << I2C_TIMINGR_PRESC_Pos) | // PRESC + (I2CConsts::SCLL_STD << I2C_TIMINGR_SCLL_Pos) | // SCLL + (I2CConsts::SCLH_STD << I2C_TIMINGR_SCLH_Pos) | // SCLH + (I2CConsts::SCLDEL_STD << I2C_TIMINGR_SCLDEL_Pos) | // SCLDEL + (I2CConsts::SDADEL_STD << I2C_TIMINGR_SDADEL_Pos); // SDADEL } else if (slaveConfig.speed == Speed::FAST) { - i2c->TIMINGR = (I2CConsts::PRESC_F << I2C_TIMINGR_PRESC_Pos) | // PRESC - (I2CConsts::SCLL_F << I2C_TIMINGR_SCLL_Pos) | // SCLL - (I2CConsts::SCLH_F << I2C_TIMINGR_SCLH_Pos) | // SCLH - (0x1 << I2C_TIMINGR_SDADEL_Pos) | // SDADEL - (0x1 << I2C_TIMINGR_SCLDEL_Pos); // SCLDEL + i2c->TIMINGR = + (I2CConsts::PRESC_F << I2C_TIMINGR_PRESC_Pos) | // PRESC + (I2CConsts::SCLL_F << I2C_TIMINGR_SCLL_Pos) | // SCLL + (I2CConsts::SCLH_F << I2C_TIMINGR_SCLH_Pos) | // SCLH + (I2CConsts::SCLDEL_F << I2C_TIMINGR_SCLDEL_Pos) | // SCLDEL + (I2CConsts::SDADEL_F << I2C_TIMINGR_SDADEL_Pos); // SDADEL } else if (slaveConfig.speed == Speed::FAST_PLUS) { i2c->TIMINGR = - (I2CConsts::PRESC_FP << I2C_TIMINGR_PRESC_Pos) | // PRESC - (I2CConsts::SCLL_FP << I2C_TIMINGR_SCLL_Pos) | // SCLL - (I2CConsts::SCLH_FP << I2C_TIMINGR_SCLH_Pos) | // SCLH - (0x1 << I2C_TIMINGR_SDADEL_Pos) | // SDADEL - (0x1 << I2C_TIMINGR_SCLDEL_Pos); // SCLDEL + (I2CConsts::PRESC_FP << I2C_TIMINGR_PRESC_Pos) | // PRESC + (I2CConsts::SCLL_FP << I2C_TIMINGR_SCLL_Pos) | // SCLL + (I2CConsts::SCLH_FP << I2C_TIMINGR_SCLH_Pos) | // SCLH + (I2CConsts::SCLDEL_FP << I2C_TIMINGR_SCLDEL_Pos) | // SCLDEL + (I2CConsts::SDADEL_FP << I2C_TIMINGR_SDADEL_Pos); // SDADEL } else { @@ -575,15 +611,16 @@ void I2CDriver::setupReload() { if ((transaction.nBytes - transaction.nBytesDone) <= 0xffu) { - i2c->CR2 &= ~I2C_CR2_RELOAD; - i2c->CR2 |= ((transaction.nBytes - transaction.nBytesDone) - << I2C_CR2_NBYTES_Pos); + i2c->CR2 = + (i2c->CR2 & ~(I2C_CR2_NBYTES_Msk | + I2C_CR2_RELOAD)) | // clearing NBYTES and RELOAD + ((transaction.nBytes - transaction.nBytesDone) + << I2C_CR2_NBYTES_Pos); // Reloading right number of bytes } else { - i2c->CR2 |= - (I2C_CR2_RELOAD | // There must be a reload - (0xff << I2C_CR2_NBYTES_Pos)); // maximum bytes that can be sent + i2c->CR2 |= (I2C_CR2_RELOAD | // There must be a reload + I2C_CR2_NBYTES_Msk); // maximum bytes that can be sent } } @@ -716,6 +753,12 @@ void I2CDriver::IRQhandleInterrupt() return; } + // Transfer complete reload: setting registers for the remaining bytes + if (i2c->ISR & I2C_ISR_TCR) + { + setupReload(); + } + if (transaction.nBytesDone < transaction.nBytes) { // Performing the read/write @@ -733,12 +776,6 @@ void I2CDriver::IRQhandleInterrupt() } } - // Transfer complete reload: setting registers for the remaining bytes - if (i2c->ISR & I2C_ISR_TCR) - { - setupReload(); - } - // when stop detected on the bus if (i2c->ISR & I2C_ISR_STOPF) { diff --git a/src/tests/drivers/i2c/test-i2c-driver.cpp b/src/tests/drivers/i2c/test-i2c-driver.cpp index ce9d8ceebe2d091c282167427e8e191441e02bab..0b40f814e233ea2f727dfdf913cc0160c6b41992 100644 --- a/src/tests/drivers/i2c/test-i2c-driver.cpp +++ b/src/tests/drivers/i2c/test-i2c-driver.cpp @@ -89,20 +89,15 @@ I2CDriver::I2CSlaveConfig BME280Config{BME280.addressSensor, I2CDriver::Addressing::BIT7, I2CDriver::Speed::STANDARD}; -I2CDriver::I2CSlaveConfig OLEDConfig_F{ - OLED.addressSensor, I2CDriver::Addressing::BIT7, I2CDriver::Speed::FAST}; - -#ifdef _ARCH_CORTEXM7_STM32F7 -I2CDriver::I2CSlaveConfig OLEDConfig_FP{OLED.addressSensor, - I2CDriver::Addressing::BIT7, - I2CDriver::Speed::FAST_PLUS}; -#endif // _ARCH_CORTEXM7_STM32F7 +I2CDriver::I2CSlaveConfig OLEDConfig{OLED.addressSensor, + I2CDriver::Addressing::BIT7, + I2CDriver::Speed::STANDARD}; bool i2cDriver(I2CDriver &i2c, I2CSensor sensor, I2CDriver::I2CSlaveConfig sensorConfig) { - uint8_t buffer[10] = {0}; - const uint8_t nRead = 1; + const size_t nRead = 300; + uint8_t buffer[nRead] = {0}; i2c.flushBus(); @@ -132,31 +127,41 @@ bool i2cDriver(I2CDriver &i2c, I2CSensor sensor, int main() { - int nRepeat = 50; + int nRepeat = 10; - // thread that uses 100% CPU - std::thread t( - []() - { - while (1) - ; - }); + // // thread that uses 100% CPU + // std::thread t( + // []() + // { + // while (1) + // ; + // }); + + I2CDriver i2c(I2C1, i1scl2::getPin(), i1sda2::getPin()); for (;;) { - I2CDriver i2c(I2C1, i1scl2::getPin(), i1sda2::getPin()); - // resetting status of read sensors bool statusOLED = true; bool statusBMP = true; for (int i = 0; i < nRepeat; i++) { - statusBMP &= i2cDriver(i2c, BMP180, BMP180Config); - statusOLED &= i2cDriver(i2c, OLED, OLEDConfig_F); + for (I2CDriver::Speed speed : + {I2CDriver::Speed::STANDARD, I2CDriver::Speed::FAST #ifdef _ARCH_CORTEXM7_STM32F7 - statusOLED &= i2cDriver(i2c, OLED, OLEDConfig_FP); + , + I2CDriver::Speed::FAST_PLUS #endif // _ARCH_CORTEXM7_STM32F7 + }) + { + statusBMP &= i2cDriver( + i2c, BMP180, + {BMP180.addressSensor, I2CDriver::Addressing::BIT7, speed}); + statusOLED &= i2cDriver( + i2c, OLED, + {OLED.addressSensor, I2CDriver::Addressing::BIT7, speed}); + } } printf("OLED:%d\tBMP:%d\n", statusOLED, statusBMP); diff --git a/src/tests/drivers/i2c/test-i2c.cpp b/src/tests/drivers/i2c/test-i2c.cpp index ac292392e681fbcf4b81a18f4f81553544240805..caa0dde6af61b53f6ec7064d24fe0141c7b7fb36 100644 --- a/src/tests/drivers/i2c/test-i2c.cpp +++ b/src/tests/drivers/i2c/test-i2c.cpp @@ -24,7 +24,6 @@ #include "drivers/i2c/I2C.h" #include "miosix.h" -#include "scheduler/TaskScheduler.h" #include "string" #include "string.h" #include "thread" @@ -67,6 +66,8 @@ typedef miosix::Gpio<GPIOH_BASE, 8> i3scl2; * one sensor (in order to provoke a locked state). */ +uint8_t buffer = 0; + typedef struct { // cppcheck-suppress unusedStructMember @@ -88,21 +89,14 @@ I2CDriver::I2CSlaveConfig BME280Config{BME280.addressSensor, I2CDriver::Addressing::BIT7, I2CDriver::Speed::STANDARD}; -I2CDriver::I2CSlaveConfig OLEDConfig_F{ - OLED.addressSensor, I2CDriver::Addressing::BIT7, I2CDriver::Speed::FAST}; - -#ifdef _ARCH_CORTEXM7_STM32F7 -I2CDriver::I2CSlaveConfig OLEDConfig_FP{OLED.addressSensor, - I2CDriver::Addressing::BIT7, - I2CDriver::Speed::FAST_PLUS}; -#endif // _ARCH_CORTEXM7_STM32F7 +I2CDriver::I2CSlaveConfig OLEDConfig{OLED.addressSensor, + I2CDriver::Addressing::BIT7, + I2CDriver::Speed::STANDARD}; bool i2cDriver(I2C &i2c, I2CSensor sensor, I2CDriver::I2CSlaveConfig sensorConfig) { - uint8_t whoamiContent = 0; - const size_t nRead = 300; - uint8_t buffer[nRead] = {0}; + buffer = 48; // reset the sensor and then read the whoami if (!(i2c.probe(sensorConfig) && @@ -132,29 +126,39 @@ int main() { int nRepeat = 10; - // thread that uses 100% CPU - std::thread t( - []() - { - while (1) - ; - }); + // // thread that uses 100% CPU + // std::thread t( + // []() + // { + // while (1) + // ; + // }); + + SyncedI2C i2c(I2C1, i1scl2::getPin(), i1sda2::getPin()); for (;;) { - SyncedI2C i2c(I2C1, i1scl2::getPin(), i1sda2::getPin()); - // resetting status of read sensors bool statusOLED = true; bool statusBMP = true; for (int i = 0; i < nRepeat; i++) { - statusBMP &= i2cDriver(i2c, BMP180, BMP180Config); - statusOLED &= i2cDriver(i2c, OLED, OLEDConfig_F); + for (I2CDriver::Speed speed : + {I2CDriver::Speed::STANDARD, I2CDriver::Speed::FAST #ifdef _ARCH_CORTEXM7_STM32F7 - statusOLED &= i2cDriver(i2c, OLED, OLEDConfig_FP); + , + I2CDriver::Speed::FAST_PLUS #endif // _ARCH_CORTEXM7_STM32F7 + }) + { + statusBMP &= i2cDriver( + i2c, BMP180, + {BMP180.addressSensor, I2CDriver::Addressing::BIT7, speed}); + statusOLED &= i2cDriver( + i2c, OLED, + {OLED.addressSensor, I2CDriver::Addressing::BIT7, speed}); + } } printf("OLED:%d\tBMP:%d\n", statusOLED, statusBMP);