case ARM_I2C_BUS_SPEED: pclk = HAL_RCC_GetPCLK1Freq(); switch (arg) { case ARM_I2C_BUS_SPEED_STANDARD: /* Clock = 100kHz, Rise Time = 1000ns */ if (pclk > 50000000U) { return ARM_DRIVER_ERROR_UNSUPPORTED; } if (pclk < 2000000U) { return ARM_DRIVER_ERROR_UNSUPPORTED; } ccr = (pclk / 100000U) / 2U; trise = (pclk / 1000000U) + 1U; break; case ARM_I2C_BUS_SPEED_FAST: /* Clock = 400kHz, Rise Time = 300ns */ if (pclk > 50000000U) { return ARM_DRIVER_ERROR_UNSUPPORTED; } if (pclk < 4000000U) { return ARM_DRIVER_ERROR_UNSUPPORTED; } if ((pclk >= 10000000U) && ((pclk % 10000000U) == 0U)) { ccr = I2C_CCR_FS | I2C_CCR_DUTY | ((pclk / 400000U) / 25U); } else { ccr = I2C_CCR_FS | ((pclk / 400000U) / 3U); } trise = (pclk / 333333U) + 1U; break; default: return ARM_DRIVER_ERROR_UNSUPPORTED; } i2c->reg->CR1 &= ~I2C_CR1_PE; /* Disable I2C peripheral */ i2c->reg->CR2 &= ~I2C_CR2_FREQ; i2c->reg->CR2 |= pclk / 1000000U; i2c->reg->CCR = ccr; i2c->reg->TRISE = trise;
if pclk is 42MHz, trise is 127, but i2c->reg->TRISE is 6bits register.
Hi, you can use the following sentence to get the correct value
trise = (((pclk / 1000000U) * 300U) / 1000U) + 1U;
300 ns is 0.3 us or 0.0003 ms or 0.0000003 seconds.
1/0.0000003 = 3333333 (7 digits)
But your formula had the constant 333333 which has only 6 digits. So your result is 10 times too large and that is why it doesn't fit.
This is part of Keil::STM32F4xx_DFP.
This typo has existed since Version 1.0.7. ^-^
And with 127 being truncated into 63, the end result is 1.5us rise time instead of 0.3us, i.e. 5 times too slow rise time.
That's the danger with using "semi-cooked" constants in the code, instead of actually having the value 300 clearly visible in the formula - it's very hard to spot the number of used/expected digits in that 33333... constant.