cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F429 + I2C1 on PB7(SDA) and PB8(SCL)

malcolm23
Associate III
Posted on July 14, 2014 at 21:38

Greetings all,

The STM32F429 data sheet lists the following pinmux options:

 PB6: AF4=I2C1_SCL

 PB7: AF4=I2C1_SDA

 PB8: AF4=I2C1_SCL

 PB9: AF4=I2C1_SDA

 

I have a custom board which brings the I2C1 bus out on PB7(SDA) and PB8(SCL); however it doesn't appear to function with this pinmux configuration:

// Configure pins for I2C1 (PB7: I2C1.SDA, PB8: I2C1.SCL)

GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);

GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);

// Configure pins for I2C1 (PB7: I2C1.SDA, PB8: I2C1.SCL)

GPIO_InitTypeDef gpioInit;

gpioInit.GPIO_Pin  = GPIO_Pin_7 | GPIO_Pin_8;

gpioInit.GPIO_Mode = GPIO_Mode_AF;

gpioInit.GPIO_Speed = GPIO_Speed_2MHz;

gpioInit.GPIO_OType = GPIO_OType_OD;

gpioInit.GPIO_PuPd = GPIO_PuPd_UP;

GPIO_Init(GPIOB, &gpioInit);

If I hack the code to use PB6(SCL) and PB7(SDA) then I see data on the PB7 line. If I hack the code to use PB8(SCL) and PB9(SDA) then I see clocks on the PB8 line.

I'm wondering if there's an undocumented limitation where only PB6/PB7 and PB8/PB9 are allowed configurations? Is it possible to use PB7/PB8 or PB6/PB9?

- Malcolm Nixon

#stm32f4-stm32f429-i2c #stm32f4-stm32f429-i2c
9 REPLIES 9
Posted on July 14, 2014 at 21:55

I don't recall seeing any errata, the original STM32F4-DISCO uses PB6/PB9

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
malcolm23
Associate III
Posted on July 15, 2014 at 21:22

It's definitely something to do with the pins. 

I have a test program below to demonstrate the issue. It does an I2C_GenerateSTART and test if any interrupts fire as a response. The results are as follows:

  • No Pins: I2C_GenerateSTART does not produce an interrupt
  • PB6/PB7: I2C_GenerateSTART produces I2C1_EV_IRQn interrupt with SR1 = 0x0001
  • PB6/PB9: I2C_GenerateSTART produces I2C1_EV_IRQn interrupt with SR1 = 0x0001
  • PB7/PB8: I2C_GenerateSTART

    does not produce an interrupt

  • PB8/PB9: I2C_GenerateSTART produces I2C1_EV_IRQn interrupt with SR1 = 0x0001
The following is the test program:

#include ''stm32f4xx.h''

// Last I2C1.SR1 register reading

volatile uint16_t lastSr1 = 0xBEEF;

// I2C1 Event interrupt handler

extern ''C'' void I2C1_EV_IRQHandler(void)

{

    // Read the SR1 register

    lastSr1 = I2C_ReadRegister(I2C1, I2C_Register_SR1);

}

// I2C1 Error interrupt handler

extern ''C'' void I2C1_ER_IRQHandler(void)

{

    // Read the SR1 register

    lastSr1 = I2C_ReadRegister(I2C1, I2C_Register_SR1);

}

int main()

{

    GPIO_InitTypeDef GPIO_init;

    I2C_InitTypeDef I2C_init;

    NVIC_InitTypeDef NVIC_init;

    

    // Enable clocks

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    // Configure pins for I2C1 --- CHANGE PINS HERE FOR TESTING

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource8,  GPIO_AF_I2C1);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource9,  GPIO_AF_I2C1);

    

    // Configure pins for I2C1 --- CHANGE PINS HERE FOR TESTING

    GPIO_init.GPIO_Pin  = GPIO_Pin_8 | GPIO_Pin_9;

    GPIO_init.GPIO_Mode = GPIO_Mode_AF;

    GPIO_init.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_init.GPIO_OType = GPIO_OType_OD;

    GPIO_init.GPIO_PuPd = GPIO_PuPd_NOPULL;

    GPIO_Init(GPIOB, &GPIO_init);

    

    // Enable the I2C Event Interrupt

    NVIC_init.NVIC_IRQChannel = I2C1_EV_IRQn;

    NVIC_init.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_init.NVIC_IRQChannelSubPriority = 0;

    NVIC_init.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_init);    

    // Enable the I2C Error Interrupt

    NVIC_init.NVIC_IRQChannel = I2C1_ER_IRQn;

    NVIC_init.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_init.NVIC_IRQChannelSubPriority = 0;

    NVIC_init.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_init);    

    // Configure I2C1

    I2C_init.I2C_ClockSpeed = 400000;

    I2C_init.I2C_Mode = I2C_Mode_I2C;

    I2C_init.I2C_DutyCycle = I2C_DutyCycle_2;

    I2C_init.I2C_OwnAddress1 = 0;

    I2C_init.I2C_Ack = I2C_Ack_Enable;

    I2C_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

    I2C_Init(I2C1, &I2C_init);

    I2C_Cmd(I2C1, ENABLE);

    // Enable interrupts on event or error

    I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_ERR, ENABLE);

    

    // Generate a START

    I2C_GenerateSTART(I2C1, ENABLE);

    

    // Loop forever

    for (;;) { }

}

Posted on July 16, 2014 at 00:23

Does seem a little weird, pushed to moderation

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Amel NASRI
ST Employee
Posted on October 31, 2014 at 09:53

Back to this old discussion: you can avoid such issue if you enable I2C clock after configuring GPIOs & enabling alternate functions. This is the safest way to do it with any pins combination to be used as I2C SDA & SCL.

-Mayla-

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Posted on November 02, 2014 at 10:14

Mayla,

did you try to reproduce the problem and is the suggested solution proven to remedy the original problem?

 

This sounds very unlikely, given other combinations of pins appear to work...

Also, it would mean that the I2C module's state machine can't be reset to a known ''base'' state by resetting the bits in its control registers. It is a very unsettling idea.

JW

h239955
Associate II
Posted on August 17, 2015 at 12:06

I’ve just encountered this same problem. I can confirm that Mayla’s suggestion does not remedy the situation. Can anyone suggest a workaround?

void i2c_init(void)

{

  GPIO_InitTypeDef  GPIO_InitStruct;

  I2C_InitTypeDef  I2C_InitStructure;

 

  // Enable GPIO Peripheral Clock

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

 

  // GPIO settings for SCL and SDA pins

  GPIO_InitStruct.GPIO_Pin       = GPIO_Pin_7 | GPIO_Pin_8;  //***

  GPIO_InitStruct.GPIO_Mode      = GPIO_Mode_AF;

  GPIO_InitStruct.GPIO_PuPd      = GPIO_PuPd_UP;

  GPIO_InitStruct.GPIO_Speed     = GPIO_Speed_100MHz;

  GPIO_InitStruct.GPIO_OType     = GPIO_OType_OD;

  GPIO_Init(GPIOB, &GPIO_InitStruct);

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);  // ***

  // Enable I2C Peripheral Clock

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

  // I2C settings

  I2C_InitStructure.I2C_ClockSpeed = 336000;  // 336kHz

  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_16_9;

  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;

  I2C_Init(I2C1, &I2C_InitStructure);

  // Enable I2C1

  I2C_Cmd(I2C1, ENABLE);

}

I have a breakpoint where I generate the START signal and I have a ‘scope on the SDA pin.

With the code as is, execution of,

  I2C_GenerateSTART(I2C1, ENABLE);

does NOT produce any signal on the SDA line. However if I change the two lines marked “//***�? to use pin 6 rather than 8 for I2C1_SCL then the same experiment shows the SDA line behaving as I’d expect it to. As per Mayla’s suggestion, the I2C clock has been enabled only after configuring GPIOs and enabling alternate functions.

For info, we are using a STMF439IIT6.

We have just bought £500 of boards and solder stencils with the pins mapped as above so any help to get around this would be greatly appreciated!

Amel NASRI
ST Employee
Posted on August 17, 2015 at 17:18

HidaBull,

I’ve just encountered this same problem.

Do you mean that ''Busy'' flag is set? Do you have same issue with this code:

void

i2c_init(

void

)
{
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStructure;
// Enable GPIO Peripheral Clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
// GPIO settings for SCL and SDA pins
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);

// ***

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8;

//***

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
GPIO_Init(GPIOB, &GPIO_InitStruct);
// Enable I2C Peripheral Clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// I2C settings
I2C_InitStructure.I2C_ClockSpeed = 336000;

// 336kHz

I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_16_9;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_Init(I2C1, &I2C_InitStructure);
// Enable I2C1
I2C_Cmd(I2C1, ENABLE);
}

-Mayla-

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

h239955
Associate II
Posted on August 18, 2015 at 11:28

SOLVED

Hi Mayla,

Yes, the ''Busy'' flag was set whenever the initialisation of the I2C wasn't working.

Yes, your code does work! I had no idea that the order of setting up the AF functions and GPIO settings for the pins would make a difference. Thank you so much for your help!

daBull

Posted on August 18, 2015 at 13:39

This is even more unsettling.

Mayla, can you please explain, why the old code failed, why does your one work, and why did the old one work with different pins?

JW