2014-07-14 12:38 PM
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-i2c2014-07-14 12:55 PM
I don't recall seeing any errata, the original STM32F4-DISCO uses PB6/PB9
2014-07-15 12:22 PM
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:does not produce an interrupt
#include ''stm32f4xx.h''
// Last I2C1.SR1 register readingvolatile uint16_t lastSr1 = 0xBEEF;// I2C1 Event interrupt handlerextern ''C'' void I2C1_EV_IRQHandler(void){ // Read the SR1 register lastSr1 = I2C_ReadRegister(I2C1, I2C_Register_SR1);}// I2C1 Error interrupt handlerextern ''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 (;;) { }}2014-07-15 03:23 PM
Does seem a little weird, pushed to moderation
2014-10-31 01:53 AM
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.
2014-11-02 01:14 AM
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. JW2015-08-17 03:06 AM
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!
2015-08-17 08:18 AM
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.
2015-08-18 02:28 AM
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!daBull2015-08-18 04:39 AM
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