2014-02-09 06:09 AM
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 #stm32f42016-08-14 08:56 AM
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.
2016-10-05 01:28 PM