Interfacing displays with mbed and nucleo boards

Hi,
I am new to STM32 and I want to use displays with my nucleo F413ZH. I have looked and tried different PIO libraries for interfacing with an I2C 4x20 LCD (classic ones with a PCF8574 used with arduino) but nothing works. I tried this one PlatformIO Registry on PIO which is supposed to work but I can’t get anything to print with the given example.

I also wanted to try a ST7789 with SPI but I can’t find a suitable library on PIO.

Has anyone had anyluck with STM32’s? And is it possible to use the more popular PIO libraries that use arduino header files for a nucleo board? the problem if I try to do this right now is that it cannot compile due to the Wire.h and other includes from the arduino environment but unknown to the mbed environment

How can I use an I2C LCD (or a ST7789) with mbed on PIO? thanks!

I tried 2 or 3 configurations of pins but none worked

I just tried the I2C scanner (I didnt think of it before as I know the address of the device) and the code does not seem to work. It acknowledges all of the 128 i2c addresses, even when I unplug my i2c lines…

I know the contrast nob is adjusted!

#include "mbed.h"
I2C i2c(D14, D15);       // sda, scl
Serial pc(USBTX, USBRX); // tx, rx

int main()
{
  while (1)
  {
pc.printf("RUN\r\n");

for (int i = 0; i < 128; i++)
{
  i2c.start();
  if (i2c.write(i << 1))
    pc.printf("0x%x ACK \r\n", i); // Send command string
  i2c.stop();
}

thread_sleep_for(500);
  }
}

So when I upload, it continuously prints the 128 addresses with ACK on each. This clearly isnt normal, what can be causing this?

Thanks!

Hm maybe the scanner sketch has the wrong logic, can you try

Because that has the ACK logic inverted. However if all 128 addresses return “ACK” then this sketch will just return 0 devices. But it’s worth a try. Make sure to adapt the I2C and serial pins again ( D14, D15, USBTX, USBRX)

Have you tried powering the LCD also from 5V? The STM32 pins are 5V-tolerant so it won’t hurt them.

Do you also have a simple Arduino on hand to connect the LCD module to and run the I2C Scanner sketch to see if it returns a valid address?

Ok, so I managed to identify the I2C address of my LCD with a single set of I2C pins on the Nucleo F413HZ. Most of them didnt find the address, which is really weird…

I already knew what the address was, it is a classic LCD 4x20 with an address of 0x27, I used it plenty with arduinos.

So I managed to print device found at 0x27 with this code:
#include <mbed.h>

I2C i2c(PB_11, PB_10);     // SDA pin, SCL pin    // PB_9, PC_6 not working, make the weird LD1 flash and no comm

Serial pc(USBTX, USBRX); // TX pin, RX pin

int main()

{

  pc.baud(9600);

  while (1)

  {

    pc.printf("Hello World!\n");

    thread_sleep_for(1000);

    

    int count = 0;

    for (int address = 0; address < 127; address++)

    {

      if (!i2c.write(address << 1, NULL, 0)) // 0 returned is ok

      {

        pc.printf("I2C device found at address 0x%02X (0x%02X in 8-bit)\n", address, address << 1);

        count++;

      }

      thread_sleep_for(20);

    }

    if (count)

      pc.printf("%d", count);

    else

      pc.printf("No");

    pc.printf(" device found\n\n");

  }

}

I decided to try my lcd printing code again, since now I knew that the device address was at least identified, but no luck. Still nothing showing up. Played with the nob again to make sure. I never had used 5V before, I believed the pins were only 3v3 tolerant, but it didn’t seem to work either. Here is the code I am using (maybe the firmware I wrote is the problem):

#include <mbed.h>

I2C i2c(PB_11, PB_10);     // SDA pin, SCL pin    // PB_9, PC_6 not working, make the weird LD1 flash and no comm

Serial pc(USBTX, USBRX); // TX pin, RX pin

int main()

{

  pc.baud(9600);

  while (1)

  {

    pc.printf("Hello World!\n");

    thread_sleep_for(1000);

    

    int count = 0;

    for (int address = 0; address < 127; address++)

    {

      if (!i2c.write(address << 1, NULL, 0)) // 0 returned is ok

      {

        pc.printf("I2C device found at address 0x%02X (0x%02X in 8-bit)\n", address, address << 1);

        count++;

      }

      thread_sleep_for(20);

    }

    if (count)

      pc.printf("%d", count);

    else

      pc.printf("No");

    pc.printf(" device found\n\n");

  }

}

That is probably because the library gives you a default address of (source)

/**
 * @brief default I2C address
 */
#define I2CLCD_ADDR 0x7c

so in the example code just use the actual address

I2CLCD i2clcd(i2c, 0x27);

(or if needs it in 8-bit format 0x4e) . Also it’s best to change back the supply to 3V3 and the I2C pins to where they work. It’s a weird hardware thing… Maybe something to do with needing explicit 4.7k pullups to 3.3V on the two I2C lines? o_O. There are also some commented out lines regarding I2C pullups, maybe that helps?

But first check if you can get the LCD example to work now with the correctly identified I2C address.

I’m so sorry I made a mistake on the last message… I posted the I2C scanner code twice!! My code for writing to the LCD is here, and I do specify the address and it doesn’t work at 5v and 3.3V, with or without 4.7K pullups… Here is the code:

#include <mbed.h>
#include "TextLCD.h"

int main() {

I2C i2c_lcd(PB_11, PB_10);
TextLCD_I2C lcd(&i2c_lcd, 0x27, TextLCD::LCD20x4);
//DigitalOut led(PG_0);
DigitalOut led_in(LED2);
Serial pc(USBTX, USBRX);
//Thread thread;

  while(1) {
    // put your main code here, to run repeatedly:
    lcd.printf("Hello World!\n");
    //led = !led;
    led_in = !led_in;
    pc.printf("led is %d\n\r", led_in.read());
    //wait_ms(500);
    thread_sleep_for(500);
    //ThisThread::sleep_for(500000);
  }
}

By the way I don’t know if it was a mistake but the API you used
I2CLCD i2clcd(i2c, 0x27);
doesnt seem to exist in the library im using, Im using this one:
TextLCD_I2C lcd(&i2c_lcd, 0x27, TextLCD::LCD20x4);

Thanks again… I don’t know what I can do now…

I’m looking at the PlatformIO Registry library you posted above and it’s a valid class there o_O.

But actually the I2CLED library might also be wrong because it’s written for some custom display with an ATTiny2313 which probably doesn’t implement the same protocol as the PCF8574.

So now you seem to be using the TextLCD_I2C - | Mbed library.

Have you tried with 0x27 << 1 as the address? The Code doesn’t seem to internally left-shift the address.

Also it maybe makes sense to integrate the I2C scanner code into the mbed-os firmware itself as a self-check.

I’m looking at the PlatformIO Registry library you posted above and it’s a valid class there o_O.

You are right, I didn’t mention textLCD and that was the one I was trying at the moment. I just retried I2CLCD with the pins that worked on the I2C scanner, but no luck. If it is not meant to be used with a PCF8574 chip, that would be the reason! That was my code:

#include <mbed.h>

#include <I2CLCD.h>

I2C i2c(PB_11, PB_10);

I2CLCD i2clcd(i2c, 0x27);

DigitalOut myled(LED2);

int main() {

    int i = 1;

   

    while (1)

    {

          myled = 1;

    i2clcd.putc('0' + i);

    i2clcd.putc('A' + i);

    i2clcd.putc('a' + i);

    i2clcd.printf("123456789abcdefghikjlmn");

    myled = 0;

    thread_sleep_for(500);

    wait_ms(500);

    }

}

And I also tried what you told me on the textLCD library code, I shifted 1 bit left on the I2C address. Unfortunately, still nothing. code:

#include <mbed.h>

#include <TextLCD.h>

int main() {

I2C i2c_lcd(PB_11, PB_10);

TextLCD_I2C lcd(&i2c_lcd, 0x27 << 1, TextLCD::LCD20x4);

//DigitalOut led(PG_0);

DigitalOut led_in(LED2);

Serial pc(USBTX, USBRX);

//Thread thread;

  while(1) {

    // put your main code here, to run repeatedly:

    lcd.printf("Hello World!\n");

    //led = !led;

    led_in = !led_in;

    pc.printf("led is %d\n\r", led_in.read());

    //wait_ms(500);

    thread_sleep_for(500);

    //ThisThread::sleep_for(500000);

  }

}

I was thinking I might need a little bit of I2C theory in order to stop being so dependent on libraries. I was not aware of the fact that the address needs to be shifted one position left, and there is probably a bunch of stuff I don<t know too. I just fear it would be very time consuming to try writing to an I2C LCD without a library, only with the mbed API. What do you think? And would you know a good resource for learning advanced I2C firmware writing?

Thanks again for all your help…