cancel
Showing results for 
Search instead for 
Did you mean: 

Proper Initialization of the I2C Peripheral

dibs
Associate II
Posted on February 09, 2014 at 15:09

I am starting this post to hopefully determine the proper initialization procedure for the I2C peripheral. I am specifically using an STM32F407, but I am assuming that this will be helping in a broader sense.

The background is that I wrote an I2C driver that, at first past, was extremely unreliable. It had the problem that it would sometimes start up fine, sometimes start up with a bus error, and sometimes start up every or every other time with the BUSY flag never clearing.

In my case, I was testing my code with a dev kit connected to an external LCD screen which hosted the pull up resistors for the bus. I noticed that as I moved around my initialization code, the start up behavior would change. The confusing part was that scoping the SDA and SCL lines generally showed no difference, electrically, on the bus. In order to solve the problem, I disconnected the display, enabled the internal pull ups, and scoped the lines. This showed me the culprit:

    GPIO_InitStructure.GPIO_Pin   = LCD_SCL_GPIO_Pin_x | LCD_SDA_GPIO_Pin_x;

    GPIO_Init(LCD_GPIOx, &GPIO_InitStructure);

What I could then see, was SDA going hi and then SCL going hi. In my interpretation, this action was interpreted by the processor as an external I2C master trying to communicate with it. It may have been waiting for a STOP condition before it would respond to any commands.

The real problem was that I had tried issuing START and STOP commands, waiting it out, and various other things, but the peripheral would just not respond when it was stuck in BUSY mode.

I will post my init code below, but any thoughts on how to be sure that one can avoid this issue? The primary issue here is that I should not be able to lose control of the bus. If this kind of thing can happen, what would I do to reset at start up and then anytime afterwards.

http://www.best-microcontroller-projects.com/i2c-tutorial.html

void init_lcd(void) {

    GPIO_InitTypeDef GPIO_InitStructure;

    I2C_InitTypeDef  I2C_InitStructure;

    DMA_InitTypeDef  DMA_InitStructure;

    // I2C Clock Enable

    RCC_APB1PeriphClockCmd(LCD_APB1Periph_I2Cx, ENABLE);

    // GPIOx clock enable

    RCC_AHB1PeriphClockCmd(LCD_AHB1Periph_GPIOx, ENABLE);

    // Reset I2C peripheral

    RCC_APB1PeriphResetCmd(LCD_APB1Periph_I2Cx, ENABLE);

    RCC_APB1PeriphResetCmd(LCD_APB1Periph_I2Cx, DISABLE);

    // Connect I2C pins to AF

    GPIO_PinAFConfig(LCD_GPIOx, LCD_SCL_GPIO_PinSourcex, LCD_GPIO_AF_I2Cx);

    GPIO_PinAFConfig(LCD_GPIOx, LCD_SDA_GPIO_PinSourcex, LCD_GPIO_AF_I2Cx);

    // I2C GPIO pin configuration

    GPIO_StructInit(&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;

    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;

    GPIO_InitStructure.GPIO_Pin   = LCD_SCL_GPIO_Pin_x;

    GPIO_InitStructure.GPIO_Pin   = LCD_SCL_GPIO_Pin_x | LCD_SDA_GPIO_Pin_x;

    GPIO_Init(LCD_GPIOx, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = LCD_SDA_GPIO_Pin_x;

    GPIO_Init(LCD_GPIOx, &GPIO_InitStructure);

    // I2C struct init

    I2C_StructInit(&I2C_InitStructure);

    I2C_InitStructure.I2C_ClockSpeed          = I2C_SPEED;

    I2C_InitStructure.I2C_Mode                = I2C_Mode_I2C;

    I2C_InitStructure.I2C_DutyCycle           = I2C_DUTYCYCLE;

    //I2C_InitStructure.I2C_Ack                 = I2C_Ack_Disable;

    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;

    I2C_Init(LCD_I2Cx,&I2C_InitStructure);

    //Enable Clock Stretching

    I2C_StretchClockCmd(LCD_I2Cx,ENABLE);

    // Clear any set flags on the DMA TX stream

    DMA_ClearFlag(LCD_DMA_STREAM_TX, LCD_DMA_FLAG_TCIFx | LCD_DMA_FLAG_FEIFx | LCD_DMA_FLAG_DMEIx |

            LCD_DMA_FLAG_TEIx | LCD_DMA_FLAG_HTIx);

    // Disable the I2C Tx DMA stream

    DMA_Cmd(LCD_DMA_STREAM_TX, DISABLE);

    //Deinit I2C TX DMA

    DMA_DeInit(LCD_DMA_STREAM_TX);

    DMA_InitStructure.DMA_Channel             = LCD_DMA_CHANNEL;

    DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)(&(LCD_I2Cx->DR));

    DMA_InitStructure.DMA_PeripheralInc       = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc           = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize  = DMA_PeripheralDataSize_Byte;

    DMA_InitStructure.DMA_MemoryDataSize      = DMA_MemoryDataSize_Byte;

    DMA_InitStructure.DMA_Mode                = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority            = DMA_Priority_VeryHigh;

    DMA_InitStructure.DMA_FIFOMode            = DMA_FIFOMode_Disable;

    DMA_InitStructure.DMA_FIFOThreshold       = DMA_FIFOThreshold_Full;

    DMA_InitStructure.DMA_MemoryBurst         = DMA_MemoryBurst_Single;

    DMA_InitStructure.DMA_PeripheralBurst     = DMA_PeripheralBurst_Single;

    DMA_InitStructure.DMA_DIR                 = DMA_DIR_MemoryToPeripheral;

    DMA_InitStructure.DMA_Memory0BaseAddr     = (uint32_t)txBuff;

    DMA_InitStructure.DMA_BufferSize          = sizeof(txBuff);

    DMA_DeInit(LCD_DMA_STREAM_TX);

    DMA_Init(LCD_DMA_STREAM_TX, &DMA_InitStructure);

} // end - void init_lcd(void) {

#i2c #ii2c #stm32f4
11 REPLIES 11
Posted on August 14, 2016 at 17:56

Ok, but what does that actually mean? If you don't enable the GPIO bank clock you aren't going to be able to able configure the pins or mux.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
kwikius
Associate II
Posted on October 05, 2016 at 22:28