Hi, all. I'm using the STM32F7 Discovery board. (STM32F746NGH6 chip) and am trying to implement an I2C driver (bare metal) for the I2C1 port on pins PB8/PB9 which are brought out to the Arduino header so I can connect those lines to an external board.
I just can't get any bus activity, verified by a logic analyzer. No SCL clocks, no data being transmitted. I've checked and double and triple checked the discovery board schematics and those pins are only connected to 2.7KOhm pull-ups on board and the DCMI camera connector.
I have attached my code below. I have stripped down the I2CWriteBytes function to just transmit a single byte (master mode) so I can see if the bus is getting driven at all. The code returns with the timeout errors.
The GPIOSetAltFunc function is a single line call to my own GPIO code which has been proven to work elsewhere in the system.
The I2C peripheral clock is PB1 (54MHz) and the bus speed should be around 100KHz, according to STM's I2C config tool. I cannot verify the bus speed since the SCL line does not clock anything.
Can anyone spot what I am missing? Thanks very much.
void InitI2CBus(I2C_TypeDef *I2Cx)
// Enable the I2C1 PB1 clock.
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
GPIOSetAltFunc(GPIOB, GPIO_Pin_8 | GPIO_Pin_9, GPIO_PuPd_NOPULL, GPIO_OType_OD, GPIO_AF4_I2C1);
// Disable this I2C instance
I2Cx->CR1 &= ~I2C_CR1_PE;
/*---------------------------- I2Cx TIMINGR Configuration ------------------*/
// Configure I2C Bus Frequency.
// These numbers are from CubeMX on 54MHz clock and 100KHz I2C bus speed.
// I2Cx->TIMINGR = 0x20404768; // From CubeMX on 54MHz clock and 100KHz I2C bus speed.
I2Cx->TIMINGR = 0x10907295; // From I2C Timing tool Excel spreadsheet (AN4235).
// Configure I2Cx->CR1: Control Register1
I2Cx->CR1 = 0;
// Configure I2Cx->CR2: Control Register2
I2Cx->CR2 = 0;
// Configure I2Cx: Own Address1 (0) and ack own address1 mode
I2Cx->OAR1 = 0;
// Configure I2Cx: Dual mode and Own Address2
I2Cx->OAR2 = 0;
// Clear Interrupt and Status register
I2Cx->ISR = 0;
// Enable I2Cx Peripheral
I2Cx->CR1 |= I2C_CR1_PE;
I2C_StatusTypeDef I2CWriteBytes(I2C_TypeDef *I2Cx, U8 slaveDeviceAddr, U8 slaveRegisterAddr, U8 regAddrSize, U8 *writeBuff, U16 numBytesToWrite)
// Is I2C bus BUSY?
if ((I2Cx->ISR & I2C_ISR_BUSY) == I2C_ISR_BUSY)
// Setup slaveDeviceAddr address for write and set NBYTES in CR2 to 1
// Need to set the start bit AFTER all these bits are set.
// I2Cx->CR2 = I2C_CR2_CFG_SOFTEND_WRITE(slaveDeviceAddr, 1);
U3 numBytes = 1;
I2Cx->CR2 = (slaveDeviceAddr & I2C_CR2_SADD) | ((numBytes << 16 ) & I2C_CR2_NBYTES);
// Send START condition
I2Cx->CR2 |= I2C_CR2_START;
// Wait for I2C_ISR_TXIS flag - Transmit is ready to start
U32 I2CTimeout = I2C_LONG_TIMEOUT;
while ((I2Cx->ISR & I2C_ISR_TXIS) != I2C_ISR_TXIS)
if (I2CTimeout-- == 0)
// uartprintf(DEBUG_UART, "I2C1WriteBytes-2\r\n");
// Now transmit the slaveDeviceAddr
I2Cx->TXDR = slaveDeviceAddr;
// Test on I2C_ISR_TC - Transmit complete (i.e. 1 Byte sent)
I2CTimeout = I2C_LONG_TIMEOUT;
while ((I2Cx->ISR & I2C_ISR_TC) != I2C_ISR_TC)
if (I2CTimeout-- == 0)
// TEST ONLY
// Send STOP condition
I2Cx->CR2 |= I2C_CR2_STOP;