AnsweredAssumed Answered

Can't get STM32F7 I2C1 working at all.

Question asked by David Harrison on Jan 3, 2017
Latest reply on Jan 6, 2017 by David Harrison

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)
{
   uartprint(DEBUG_UART, "I2C1WriteBytes-0\r\n");

   // Is I2C bus BUSY?
   if ((I2Cx->ISR & I2C_ISR_BUSY) == I2C_ISR_BUSY)
      return I2C_BUSY_STATE;

 

   uartprint(DEBUG_UART, "I2C1WriteBytes-1\r\n");

   // 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)
         return I2C_TIMEOUT_UserCallback("I2CWriteBytes-1");
   }

 

 //  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)
         return I2C_TIMEOUT_UserCallback("I2C1WriteBytes-2");
   }

 

   // TEST ONLY
   // Send STOP condition
   I2Cx->CR2 |= I2C_CR2_STOP;

   uartprint(DEBUG_UART, "I2C1WriteBytes-3\r\n");
  
   return I2C_TESTERROR_STATE;
}

Outcomes