check if I²C is forwarded

This commit is contained in:
King Kévin 2022-07-11 10:56:03 +02:00
parent e2cdc89a30
commit d247e2e1e8
1 changed files with 39 additions and 19 deletions

58
main.c
View File

@ -18,6 +18,7 @@
#define SDA_PU_PIN PC3
#define SCL_PU_PORT GPIO_PC
#define SCL_PU_PIN PC4
static bool i2c_fwd = false; // if the I²C source lines are connected to sink
// external EEPROM write protect pin
#define WP_PORT GPIO_PC
#define WP_PIN PC5
@ -110,12 +111,29 @@ void main(void)
// configure I²C pull-ups
SDA_PU_PORT->DDR.reg |= SDA_PU_PIN; // switch pin to output
SDA_PU_PORT->CR1.reg |= SDA_PU_PIN; // switch pin to push pull
SDA_PU_PORT->ODR.reg |= SDA_PU_PIN; // pull up SDA line
SDA_PU_PORT->CR1.reg &= ~SDA_PU_PIN; // switch pin to open-drain
SDA_PU_PORT->ODR.reg &= ~SDA_PU_PIN; // pull SDA line low
wait_10us(0); // wait shortly to clear tristate
SDA_PU_PORT->DDR.reg &= ~SDA_PU_PIN; // switch pin to input (already floating)
if (SDA_PU_PORT->IDR.reg & SDA_PU_PIN) { // line is pulled up
i2c_fwd = true; // remember the I²C line(s) are forwarded
}
SCL_PU_PORT->DDR.reg |= SCL_PU_PIN; // switch pin to output
SCL_PU_PORT->CR1.reg |= SCL_PU_PIN; // switch pin to push pull
SCL_PU_PORT->ODR.reg |= SCL_PU_PIN; // pull up SCL line
// TODO verify if I²C lines are connected to monitor
SCL_PU_PORT->CR1.reg &= ~SCL_PU_PIN; // switch pin to open-drain
SCL_PU_PORT->ODR.reg &= ~SCL_PU_PIN; // pull SDA line low
wait_10us(0); // wait shortly to clear tristate
SCL_PU_PORT->DDR.reg &= ~SCL_PU_PIN; // switch pin to input (already floating)
if (SCL_PU_PORT->IDR.reg & SCL_PU_PIN) { // line is pulled up
i2c_fwd = true; // remember the I²C line(s) are forwarded
}
if (!i2c_fwd) { // I²C lines are not pulled up
SDA_PU_PORT->DDR.reg |= SDA_PU_PIN; // switch pin to output
SDA_PU_PORT->CR1.reg |= SDA_PU_PIN; // switch pin to push pull
SDA_PU_PORT->ODR.reg |= SDA_PU_PIN; // pull up SDA line
SCL_PU_PORT->DDR.reg |= SCL_PU_PIN; // switch pin to output
SCL_PU_PORT->CR1.reg |= SCL_PU_PIN; // switch pin to push pull
SCL_PU_PORT->ODR.reg |= SCL_PU_PIN; // pull up SCL line
}
// configure external EEPROM (actually not used)
WP_PORT->DDR.reg |= WP_PIN; // switch pin to output
@ -123,20 +141,22 @@ void main(void)
WP_PORT->ODR.reg |= WP_PIN; // let write protect pulled up
// configure I²C
GPIO_PB->CR1.reg |= (PB4 | PB5); // enable internal pull-up on SCL/SDA
GPIO_PB->DDR.reg &= ~(PB4 | PB5); // set SCL/SDA as input before it is used as alternate function by the peripheral
I2C_CR1 |= I2C_CR1_PE; // enable I²C peripheral (must be done before any other register is written)
I2C_CR2 |= I2C_CR2_STOP; // release lines
I2C_CR2 |= I2C_CR2_SWRST; // reset peripheral, in case we got stuck and the dog bit
while (0 == (GPIO_PB->IDR.reg & PB4)); // wait for SCL line to be released
while (0 == (GPIO_PB->IDR.reg & PB5)); // wait for SDA line to be released
I2C_CR2 &= ~I2C_CR2_SWRST; // release reset
I2C_CR1 |= I2C_CR1_PE; // re-enable I²C peripheral
I2C_FREQR = 16; // the peripheral frequency is 4 MHz (must match CPU frequency)
I2C_CR2 |= I2C_CR2_ACK; // enable acknowledgement if address matches
// since we are slave and not master, we don't have to set CCR
I2C_OARL = (0x50U << 1U); // set slave address for EEPROM
I2C_ITR |= (I2C_ITR_ITBUFEN | I2C_ITR_ITEVTEN); // enable buffer and event interrupts
if (!i2c_fwd) { // we will act as I²C slave EEPROM
GPIO_PB->CR1.reg |= (PB4 | PB5); // enable internal pull-up on SCL/SDA
GPIO_PB->DDR.reg &= ~(PB4 | PB5); // set SCL/SDA as input before it is used as alternate function by the peripheral
I2C_CR1 |= I2C_CR1_PE; // enable I²C peripheral (must be done before any other register is written)
I2C_CR2 |= I2C_CR2_STOP; // release lines
I2C_CR2 |= I2C_CR2_SWRST; // reset peripheral, in case we got stuck and the dog bit
while (0 == (GPIO_PB->IDR.reg & PB4)); // wait for SCL line to be released
while (0 == (GPIO_PB->IDR.reg & PB5)); // wait for SDA line to be released
I2C_CR2 &= ~I2C_CR2_SWRST; // release reset
I2C_CR1 |= I2C_CR1_PE; // re-enable I²C peripheral
I2C_FREQR = 16; // the peripheral frequency is 4 MHz (must match CPU frequency)
I2C_CR2 |= I2C_CR2_ACK; // enable acknowledgement if address matches
// since we are slave and not master, we don't have to set CCR
I2C_OARL = (0x50U << 1U); // set slave address for EEPROM
I2C_ITR |= (I2C_ITR_ITBUFEN | I2C_ITR_ITEVTEN); // enable buffer and event interrupts
}
// configure hot plug detect
HPD_PORT->DDR.reg |= HPD_PIN; // switch pin to output