0
\$\begingroup\$

I'm trying to control an I2C Enabled LCD Display using the STM32F0. I have a bunch boards built with the LCDs and a couple of them work all the time, a few work intermittently and a few rarely work at all and I'm not sure where the issue is coming from.

I've tried analyzing the I2C lines and sometimes I see the display NACKing while othertimes I see it ACK but the I2C just stops. Sometimes I even see a bunch of unexpected data being sent.

I'm trying to figure out if this is a hardware issue, LCD issue, or FW issue to start with. From a hardware perspective I've followed the recommended circuit on the datasheet and used ~6k pull-ups. I can only assume the LCD itself is working since sometimes I can get it to display properly. This leads me to believe it's a FW issue. I've noticed that if I play around with the delays between messages I can get it to work sometimes and I can certainly break it. Is there any more error checking or similar that I should be doing do on the uC to improve reliability?

enter image description here

void I2C_LowLevel_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  /* Configure the I2C clock source. The clock is derived from the HSI (8MHz default)*/
  RCC_I2CCLKConfig(RCC_I2C1CLK_HSI);

  /* LCD_I2C_SCL_GPIO_CLK and LCD_I2C_SDA_GPIO_CLK Periph clock enable */
  RCC_AHBPeriphClockCmd(LCD_I2C_SCL_GPIO_CLK | LCD_I2C_SDA_GPIO_CLK, ENABLE);

  /* LCD_I2C Periph clock enable */
  RCC_APB1PeriphClockCmd(LCD_I2C_CLK, ENABLE);

  /* Connect PXx to I2C_SCL*/
  GPIO_PinAFConfig(LCD_I2C_SCL_GPIO_PORT, LCD_I2C_SCL_SOURCE, LCD_I2C_SCL_AF);

  /* Connect PXx to I2C_SDA*/
  GPIO_PinAFConfig(LCD_I2C_SDA_GPIO_PORT, LCD_I2C_SDA_SOURCE, LCD_I2C_SDA_AF);

  /* GPIO configuration */  
  /* Configure LCD_I2C pins: SCL */
  GPIO_InitStructure.GPIO_Pin = LCD_I2C_SCL_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(LCD_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);

  /* Configure LCD_I2C pins: SDA */
  GPIO_InitStructure.GPIO_Pin = LCD_I2C_SDA_PIN;
  GPIO_Init(LCD_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
}


void I2C_Initialize(void)
{ 
  I2C_InitTypeDef  I2C_InitStructure;

  I2C_LowLevel_Init();

  /* I2C configuration */
  /* LCD_I2C configuration */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
  I2C_InitStructure.I2C_DigitalFilter = 0x00;
  I2C_InitStructure.I2C_OwnAddress1 = 0x00;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_Timing = I2C_TIMING;

  /* Apply LCD_I2C configuration after enabling it */
  I2C_Init(LCD_I2C, &I2C_InitStructure);

  /* LCD_I2C Peripheral Enable */
  I2C_Cmd(LCD_I2C, ENABLE);

  /* Select the LCD device address */
  I2C_Address = I2C_HW_ADDRESS;
  Delay(10);
}

uint32_t LCD_Initialize(void)
{
  static int initBuffer[8] = {0x14, LCD_CONTRAST_RESET, 0x5E, 0x6D, LCD_DISPLAY_ON, LCD_CLEAR, 0x06};
  static char welcomeMessage1[LCD_MAX_LINE_SIZE + 1] = "HELLO WORLD";
  int n = 0;

  /* Send Start Bit and I2C Device Address */
  I2C_TransferHandling(LCD_I2C, (LCD_DEVICE_ADDRESS << 1), 10, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);

  /* Wait for TXIS to be set */
  //lcdTimeout = LCD_LONG_TIMEOUT;
  while(I2C_GetFlagStatus(LCD_I2C, I2C_ISR_TXIS) == RESET)
  {
    //if((lcdTimeout--) == 0) return LCD_INITIALIZE_FAIL;
  }

  I2C_SendData(LCD_I2C, 0x00);          /* CMD Byte- Only Data to Follow */
  Delay(1);
  I2C_SendData(LCD_I2C, LCD_BASIC_CONFIG);
  Delay(10);
  I2C_SendData(LCD_I2C, LCD_EXTENDED_CONFIG);
  Delay(10);

  /* Send Remaining Initialization Buffer Data */
  for (n=0; n<7; n++)
  {
    I2C_SendData(LCD_I2C, initBuffer[n]);
    Delay(1);
  }

  Delay(10);


  /* Display welcome message to confirm LCD initialization */
  LCD_Display(LCD_LINE1_START, welcomeMessage1);
  Delay(1000);
  LCD_Clear();
  return LCD_INITIALIZE_PASS;
}
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

6K seems a bit wimpy for the pullup resistors; normally, you want them to be passing 2-3 mA when the line is low. 2700 Ω is a commonly-used value in 5V systems.

\$\endgroup\$
3
  • \$\begingroup\$ I've tried a variety of resistors including just the internal PU on the micro and it's the same results. \$\endgroup\$
    – spizzak
    Commented May 29, 2014 at 17:31
  • \$\begingroup\$ The internal PU is likely to be too big. \$\endgroup\$ Commented May 29, 2014 at 17:57
  • \$\begingroup\$ Too big as in too weak? I thought this as well, but like I said even with those it works just about as often as with the external ones. \$\endgroup\$
    – spizzak
    Commented May 29, 2014 at 18:07
1
\$\begingroup\$

Where are you setting your I2C clock speed? See http://dangerousprototypes.com/forum/viewtopic.php?f=23&t=2138

Try explicitly setting I2C_InitStructure.I2C_ClockSpeed to something reasonable.

\$\endgroup\$
3
  • \$\begingroup\$ I believe this is covered in 'I2C_InitStructure.I2C_Timing = I2C_TIMING;' I used the STM timing calculator where the I2C speed (100kHz) was one of the parameters. \$\endgroup\$
    – spizzak
    Commented May 29, 2014 at 17:36
  • \$\begingroup\$ There's a I2C config tool described at stmcu.org/download/index.php?act=down&id=5779. You might give that a peek. \$\endgroup\$ Commented May 29, 2014 at 17:53
  • \$\begingroup\$ I've tried using stronger pull-ups and changing the I2C timing. I'm now running at 10kHz and I'm still seeing the display NACK- I attached a screen capture above. \$\endgroup\$
    – spizzak
    Commented May 29, 2014 at 21:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.