cancel
Showing results for 
Search instead for 
Did you mean: 

I2C commands to LCD

SScot.3
Associate II

I am learning this new 32-bit from my 8-bit world as well as new IDE on top of re-learning C. So be gentle....

I am trying to use the CubeIDE to talk to an I2C LCD. I am following a tutorial but the LCD does not respond at all.

Some of the code below:

/* LCD Commands */

#define LCD_CLEARDISPLAY  0x01

#define LCD_RETURNHOME   0x02

#define LCD_ENTRYMODESET  0x04

#define LCD_DISPLAYCONTROL 0x08

#define LCD_CURSORSHIFT   0x10

#define LCD_FUNCTIONSET   0x20

#define LCD_SETCGRAMADDR  0x40

#define LCD_SETDDRAMADDR  0x80

/* Commands bitfields */

//1) Entry mode Bitfields

#define LCD_ENTRY_SH   0x01

#define LCD_ENTRY_ID   0x02

//2) Display control

#define LCD_DISPLAY_B   0x01

#define LCD_DISPLAY_C   0x02

#define LCD_DISPLAY_D   0x04

//3) Shift control

#define LCD_SHIFT_RL   0x04

#define LCD_SHIFT_SC   0x08

//4) Function set control

#define LCD_FUNCTION_F  0x04

#define LCD_FUNCTION_N  0x08

#define LCD_FUNCTION_DL  0x10

/* I2C Control bits */

#define LCD_RS    (1 << 0)

#define LCD_RW    (1 << 1)

#define LCD_EN    (1 << 2)

#define LCD_BK_LIGHT (1 << 3)

/* Library variables */

static I2C_HandleTypeDef* lcd16x2_i2cHandle;

static uint8_t LCD_I2C_SLAVE_ADDRESS=0;

#define LCD_I2C_SLAVE_ADDRESS_0 0x4E

#define LCD_I2C_SLAVE_ADDRESS_1 0x7E

/* Private functions */

static void lcd16x2_i2c_sendCommand(uint8_t command)

{

 const uint8_t command_0_3 = (0xF0 & (command<<4));

 const uint8_t command_4_7 = (0xF0 & command);

 uint8_t i2cData[4] =

 {

   command_4_7 | LCD_EN | LCD_BK_LIGHT,

   command_4_7 | LCD_BK_LIGHT,

   command_0_3 | LCD_EN | LCD_BK_LIGHT,

   command_0_3 | LCD_BK_LIGHT,

 };

 HAL_I2C_Master_Transmit(lcd16x2_i2cHandle, LCD_I2C_SLAVE_ADDRESS, i2cData, 4, 200);

}

static void lcd16x2_i2c_sendData(uint8_t data)

{

 const uint8_t data_0_3 = (0xF0 & (data<<4));

 const uint8_t data_4_7 = (0xF0 & data);

 uint8_t i2cData[4] =

 {

   data_4_7 | LCD_EN | LCD_BK_LIGHT | LCD_RS,

   data_4_7 | LCD_BK_LIGHT | LCD_RS,

   data_0_3 | LCD_EN | LCD_BK_LIGHT | LCD_RS,

   data_0_3 | LCD_BK_LIGHT | LCD_RS,

 };

 HAL_I2C_Master_Transmit(lcd16x2_i2cHandle, LCD_I2C_SLAVE_ADDRESS, i2cData, 4, 200);

}

I have a logic analyzer set to display I2C on the SCL and SDA pins and the results after a reset are:

write to 0x1F nak

read to 0x1F ack

read to 0x1F ack

read to 0x1F ack data:0x3F

read to 0x1E ack data: 0x6D

read to 0x79 ack

read to 0x36 nak

read to 0x36 nak

I have checked with a different tutorial for using the I2C LCD and the defines seem to match.

There are no jumpers on the A0 A1 or A2 lines which suggest it is at address 0x4E for write and 0x4F for read.

I suspect this may be simple but I have been looking for sometime and it seems to evade me.

Any suggestions would be greatly appreciated.

Regards to All.

17 REPLIES 17
SScot.3
Associate II

The original Youtube video showed the author using a STM32 Discovery board and I am using a Nucleo-H723ZG board.

Could I be missing something in the way I set up the chip in the IOC?

Feeling frustrated as this code apparently does work - perhaps not easily on my board however?

Right here:

bool lcd16x2_i2c_init(I2C_HandleTypeDef *pI2cHandle)
{
  HAL_Delay(50);
  lcd16x2_i2cHandle = pI2cHandle;
  if(HAL_I2C_IsDeviceReady(lcd16x2_i2cHandle, LCD_I2C_SLAVE_ADDRESS_0, 5, 500) != HAL_OK)
  {
    if(HAL_I2C_IsDeviceReady(lcd16x2_i2cHandle, LCD_I2C_SLAVE_ADDRESS_1, 5, 500) != HAL_OK)
    {
      return false;
    }
    else
    {
      LCD_I2C_SLAVE_ADDRESS = LCD_I2C_SLAVE_ADDRESS_1;
    }
  }
  else
  {
    LCD_I2C_SLAVE_ADDRESS = LCD_I2C_SLAVE_ADDRESS_0;
  }
  ...

If you feel a post has answered your question, please click "Accept as Solution".

I feel so stupid. I have looked at this code for quite a while and did not see that.

To your question, how would I know if HAL_OK?

There's a few options:
* Put some breakpoints in the code in relevant spots. Infer the return value from which one gets hit.
* Rewrite the code to save the return value, and view that variable in the debugger.
These are pretty basic debugging skills. If you want to develop programs, you'll need to get comfortable there.
You should also be able to find examples that look for all I2C devices on the bus. Here is one of many:
https://deepbluembedded.com/stm32-i2c-scanner-hal-code-example/
I2C should work on the STM32H7 the same as the other families. The HAL does the lower level work to make the user-facing functions the same on all families. Basic rules still apply. I2C needs external pullups, or internal pullups with a very low clock speed. If you can see SDA/SCL signals, and they have clear edges, and the clock speed is correct, it's probably wired correctly. Still need to power the external device, and provide ground.
If you feel a post has answered your question, please click "Accept as Solution".

Thanks TDK. In my 8-bit world I would push data to a serial port and use it for debug.

I have tried

bool lcd16x2_i2c_init(I2C_HandleTypeDef *pI2cHandle)

{

 HAL_Delay(50);

 lcd16x2_i2cHandle = pI2cHandle;

 if(HAL_I2C_IsDeviceReady(lcd16x2_i2cHandle, LCD_I2C_SLAVE_ADDRESS_0, 5, 500) != HAL_OK)

 {

  if(HAL_I2C_IsDeviceReady(lcd16x2_i2cHandle, LCD_I2C_SLAVE_ADDRESS_1, 5, 500) != HAL_OK)

  {

   return false;

  }

  else

  {

   LCD_I2C_SLAVE_ADDRESS = LCD_I2C_SLAVE_ADDRESS_1;

   printf("** Addr=1 ** \n\r");

  }

 }

 else

 {

  LCD_I2C_SLAVE_ADDRESS = LCD_I2C_SLAVE_ADDRESS_0;

  printf("** Addr=0 ** \n\r");

 }

However, it does not print to the console feature pf the IDE. I am sure I don't yet have a grasp on it.

I will look at your example given to see if I can get some insight.

Should I be able to print directly to the console for debug purposes?

TDK, I will use a couple of LEDs to let me know if addr0 or addr1 is used.

TDK, I have tried several ways to get an LED to fire based on which address.

How would you do it with the following code?

My attempt has been commented out:

bool lcd16x2_i2c_init(I2C_HandleTypeDef *pI2cHandle)
{
  HAL_Delay(50);
  lcd16x2_i2cHandle = pI2cHandle;
  if(HAL_I2C_IsDeviceReady(lcd16x2_i2cHandle, LCD_I2C_SLAVE_ADDRESS_0, 5, 500) != HAL_OK)
  //	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);			//GREEN LED
  {
    if(HAL_I2C_IsDeviceReady(lcd16x2_i2cHandle, LCD_I2C_SLAVE_ADDRESS_1, 5, 500) != HAL_OK)
    {
      return false;
    }
    else
    {
      LCD_I2C_SLAVE_ADDRESS = LCD_I2C_SLAVE_ADDRESS_1;
    }
  }
  else
  {
    LCD_I2C_SLAVE_ADDRESS = LCD_I2C_SLAVE_ADDRESS_0;
  }

There are some basic C syntax logic issues here with the if/then syntax and your added line of code. Brackets are significant. If you have someone physically closer that you can ask for quick help and act as a mentor, that would be a good idea. There are no doubt many tutorials out there on debugging, stepping through code, examining variables, etc. I'm not sure I'm up for teaching the basics on all of these in a thread here.
If you feel a post has answered your question, please click "Accept as Solution".