cancel
Showing results for 
Search instead for 
Did you mean: 

Can't get STM32F7 I2C1 working at all.

anonymous.8
Senior II
Posted on January 03, 2017 at 21:25

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;

}
3 REPLIES 3
Oliver Beirne
Senior
Posted on January 04, 2017 at 12:28

Hi

Harrison.David.002

I have moved your post to the

https://community.st.com/community/stm32-community/stm32-forum?sr=search&ampsearchId=ca825b27-6ca9-469a-9d35-3574089f8d7f&ampsearchIndex=0

where product related questions are posted. All the best finding the assistance you need.

Thanks

Oli

Seb
ST Employee
Posted on January 04, 2017 at 17:39

If using the debugger, check the peripheral registers (if all look like 0x00 it means the peripheral was not clock enabled)

Have you also checked the GPIO register in debugger? Same check, check the alternate function is correct.

If the pins don't toggle, I would manually in the debugger toggle the pin a Push pull output high and low to really make sure.

In a first step, it is also possible to try out a SW I2C with GPIO which is in the I2C

Some clues here:

https://community.st.com/0D50X00009XkW1mSAF

Posted on January 06, 2017 at 15:29

So I first of al checked out the port pins by setting them as regular push-pull GPIO outputs and I could toggle them at will, then set them as open drain and I could still toggle them so the pull-up resistors were working. Then I checked my pin initialization code (which happens much earlier than the call to InitI2CBus()). It turns out that I was inadvertently setting those pins as push-pull GPIO outputs soon after the start of main() which meant those lines were being pulled low. But since they had pull-up resistors, as soon as power was applied, the lines would have been high, then were pulled low. It was that high to low transition which was triggering my logic analyzer and the lines stayed low for about 200ms until the InitI2CBus() function was called when they would be correctly configured as open drain and therefore go high again.

It was that 200ms period of both lines staying low that fooled me into thinking nothing was happening. After I removed the erroneous initialization as push-pull GPIO outputs and re-configured the trigger conditions for my logic analyzer, I was able to see some bus activity. It wasn't the right activity, but at least I got some. Now I should be able to find out what is wrong now that I can see what activity is transpiring on the bus. I am using an I2C interpreter in the logic analyzer so I see the data values being transmitted, or received.