From 155be34a1d2b782a73318cc507315b33cc86cc49 Mon Sep 17 00:00:00 2001 From: Nick Brassel Date: Sun, 2 Jun 2019 09:04:09 +1000 Subject: [PATCH] Parameterise STM32 I2C pin modes and timing parameters. (#5671) I2C timing parameters were seemingly set up for an STM32F303 target MCU, at a specific clock speed. This commit allows specifying the timing parameters via config.h, allowing other STM32 MCUs to be targeted, potentially at different clock frequencies. Alternate function modes for the I2C pins are now also configurable, allowing for remapping to other pins. --- docs/i2c_driver.md | 29 ++++++++++++++++++++++++----- drivers/arm/i2c_master.c | 16 +++++++--------- drivers/arm/i2c_master.h | 40 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/docs/i2c_driver.md b/docs/i2c_driver.md index bb1a2d74ff..4a47a92b11 100644 --- a/docs/i2c_driver.md +++ b/docs/i2c_driver.md @@ -65,11 +65,30 @@ By default the I2C1 hardware driver is assumed to be used. If another hardware d STM32 MCUs allows a variety of pins to be configured as I2C pins depending on the hardware driver used. By default B6 and B7 are set to I2C. You can use these defines to set your i2c pins: -| Variable | Description | Default | -|-------------|----------------------------------------------|---------| -| `I2C1_BANK` | The bank of pins (`GPIOA`, `GPIOB`, `GPIOC`) | `GPIOB` | -| `I2C1_SCL` | The pin number for the SCL pin (0-9) | `6` | -| `I2C1_SDA` | The pin number for the SDA pin (0-9) | `7` | +| Variable | Description | Default | +|--------------------------|----------------------------------------------------------------------------------------------|---------| +| `I2C1_SCL_BANK` | The bank of pins (`GPIOA`, `GPIOB`, `GPIOC`) to use for SCL | `GPIOB` | +| `I2C1_SDA_BANK` | The bank of pins (`GPIOA`, `GPIOB`, `GPIOC`) to use for SDA | `GPIOB` | +| `I2C1_SCL` | The pin number for the SCL pin (0-9) | `6` | +| `I2C1_SDA` | The pin number for the SDA pin (0-9) | `7` | +| `I2C1_BANK` (deprecated) | The bank of pins (`GPIOA`, `GPIOB`, `GPIOC`), superceded by `I2C1_SCL_BANK`, `I2C1_SDA_BANK` | `GPIOB` | + +STM32 MCUs allow for different timing parameters when configuring I2C. These can be modified using the following parameters, using https://www.st.com/en/embedded-software/stsw-stm32126.html as a reference: + +| Variable | Default | +|-----------------------|---------| +| `I2C1_TIMINGR_PRESC` | `15U` | +| `I2C1_TIMINGR_SCLDEL` | `4U` | +| `I2C1_TIMINGR_SDADEL` | `2U` | +| `I2C1_TIMINGR_SCLH` | `15U` | +| `I2C1_TIMINGR_SCLL` | `21U` | + +STM32 MCUs allow for different "alternate function" modes when configuring GPIO pins. These are required to switch the pins used to I2C mode. See the respective datasheet for the appropriate values for your MCU. + +| Variable | Default | +|---------------------|---------| +| `I2C1_SCL_PAL_MODE` | `4` | +| `I2C1_SDA_PAL_MODE` | `4` | You can also overload the `void i2c_init(void)` function, which has a weak attribute. If you do this the configuration variables above will not be used. Please consult the datasheet of your MCU for the available GPIO configurations. The following is an example initialization function: diff --git a/drivers/arm/i2c_master.c b/drivers/arm/i2c_master.c index 7369398cc4..5814375f37 100644 --- a/drivers/arm/i2c_master.c +++ b/drivers/arm/i2c_master.c @@ -32,12 +32,10 @@ static uint8_t i2c_address; -// This configures the I2C clock to 400khz assuming a 72Mhz clock -// For more info : https://www.st.com/en/embedded-software/stsw-stm32126.html static const I2CConfig i2cconfig = { - STM32_TIMINGR_PRESC(15U) | - STM32_TIMINGR_SCLDEL(4U) | STM32_TIMINGR_SDADEL(2U) | - STM32_TIMINGR_SCLH(15U) | STM32_TIMINGR_SCLL(21U), + STM32_TIMINGR_PRESC(I2C1_TIMINGR_PRESC) | + STM32_TIMINGR_SCLDEL(I2C1_TIMINGR_SCLDEL) | STM32_TIMINGR_SDADEL(I2C1_TIMINGR_SDADEL) | + STM32_TIMINGR_SCLH(I2C1_TIMINGR_SCLH) | STM32_TIMINGR_SCLL(I2C1_TIMINGR_SCLL), 0, 0 }; @@ -58,13 +56,13 @@ __attribute__ ((weak)) void i2c_init(void) { // Try releasing special pins for a short time - palSetPadMode(I2C1_BANK, I2C1_SCL, PAL_MODE_INPUT); - palSetPadMode(I2C1_BANK, I2C1_SDA, PAL_MODE_INPUT); + palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_INPUT); + palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_INPUT); chThdSleepMilliseconds(10); - palSetPadMode(I2C1_BANK, I2C1_SCL, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); - palSetPadMode(I2C1_BANK, I2C1_SDA, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); + palSetPadMode(I2C1_SCL_BANK, I2C1_SCL, PAL_MODE_ALTERNATE(I2C1_SCL_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); + palSetPadMode(I2C1_SDA_BANK, I2C1_SDA, PAL_MODE_ALTERNATE(I2C1_SDA_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN); //i2cInit(); //This is invoked by halInit() so no need to redo it. } diff --git a/drivers/arm/i2c_master.h b/drivers/arm/i2c_master.h index a15f1702dd..1bb74c800f 100644 --- a/drivers/arm/i2c_master.h +++ b/drivers/arm/i2c_master.h @@ -26,9 +26,19 @@ #include "ch.h" #include -#ifndef I2C1_BANK - #define I2C1_BANK GPIOB +#ifdef I2C1_BANK + #define I2C1_SCL_BANK I2C1_BANK + #define I2C1_SDA_BANK I2C1_BANK #endif + +#ifndef I2C1_SCL_BANK + #define I2C1_SCL_BANK GPIOB +#endif + +#ifndef I2C1_SDA_BANK + #define I2C1_SDA_BANK GPIOB +#endif + #ifndef I2C1_SCL #define I2C1_SCL 6 #endif @@ -36,6 +46,32 @@ #define I2C1_SDA 7 #endif +// The default PAL alternate modes are used to signal that the pins are used for I2C +#ifndef I2C1_SCL_PAL_MODE + #define I2C1_SCL_PAL_MODE 4 +#endif +#ifndef I2C1_SDA_PAL_MODE + #define I2C1_SDA_PAL_MODE 4 +#endif + +// The default timing values below configures the I2C clock to 400khz assuming a 72Mhz clock +// For more info : https://www.st.com/en/embedded-software/stsw-stm32126.html +#ifndef I2C1_TIMINGR_PRESC + #define I2C1_TIMINGR_PRESC 15U +#endif +#ifndef I2C1_TIMINGR_SCLDEL + #define I2C1_TIMINGR_SCLDEL 4U +#endif +#ifndef I2C1_TIMINGR_SDADEL + #define I2C1_TIMINGR_SDADEL 2U +#endif +#ifndef I2C1_TIMINGR_SCLH + #define I2C1_TIMINGR_SCLH 15U +#endif +#ifndef I2C1_TIMINGR_SCLL + #define I2C1_TIMINGR_SCLL 21U +#endif + #ifndef I2C_DRIVER #define I2C_DRIVER I2CD1 #endif