Gaetan Kelabra
Gaetan Kelabra

Reputation: 3

f3discovery: trying to use an lcd screen 1602 with an I2C module

I am trying to use an lcd screen on my stm32F3discovery. The screen is made of an lcd 16 characters on 2 lines and an I2C module.

Here is the link of the product: https://www.aliexpress.com/item/32763867041.html?spm=a2g0s.9042311.0.0.27424c4dsV7dLS

On the back of the screen I can see written: QAPASS 1602A On the chip of the I2C module I can see written: PCF8574T

Here is the datasheet of the chip: https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf

I tried to follow this tutoriel (the closest from what I am trying to do): https://www.youtube.com/watch?v=1COFk1M2tak

I use the HAL library, the main function to send data is "HAL_I2C_Master_Transmit".

Here is the description of the function in "HAL_I2C_Master_Transmit":

HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)

//I initialise a buffer
//I use a for loop to find the address of my slave: 0x3D (even tho on the //datasheet it's 0x3F, looks like A1 is bridged :O )
//I use the HAL_I2C_Master_Transmit function
//I move the address one bit to the left
//I reuse the HAL_I2C_Master_Transmit
//Nothing happens on the screen

//Here is my code (I tried to remove the useless comments):

#include "main.h"

I2C_HandleTypeDef hi2c1; // Init generated bu CubeMX
SPI_HandleTypeDef hspi1; // Init generated bu CubeMX
PCD_HandleTypeDef hpcd_USB_FS; // Init generated bu CubeMX

uint16_t adresseLCD; // the variable I put the slave address on
uint8_t buffer[]="123"; // The buffer I wanna see on the screen

void SystemClock_Config(void); // Generated by CubeMX
static void MX_GPIO_Init(void); // Generated by CubeMX
static void MX_I2C1_Init(void); // Generated by CubeMX
static void MX_SPI1_Init(void); // Generated by CubeMX
static void MX_USB_PCD_Init(void); // Generated by CubeMX

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_I2C1_Init();
    MX_SPI1_Init();
    MX_USB_PCD_Init();

    adresseLCD=0x3D;
    HAL_I2C_Master_Transmit(&hi2c1, adresseLCD, buffer, 1, 1000);

    adresseLCD=adresseLCD*2; // Yes I could have used "adresseLCD<<1" but I 
    //am not used to that
    HAL_I2C_Master_Transmit(&hi2c1, adresseLCD, buffer, 1, 1000);

    while(1)
    {
    }
}

I expected something to show on the screen (even random values) but nothing appears (it lights up though). I get no error (only warnings because I use "1" instead of "Pin_ON" when I WritePIn)

Upvotes: 0

Views: 1635

Answers (2)

meteowrite
meteowrite

Reputation: 43

So basically in order to transmit data from you STM32 to the LCD display driver (HD44780) you need to emulate the latter's interface signalling via the I2C interface chip (PCF8574).

In other words, MCU will send I2C commands that will toggle the I2C "backpack" chip such that it should emulate the right signaling for the LCD driver.

This happens somehow easy whne you are using the HAL_I2C_Master_*() methods. In the buffer array you specify the state of the pins on the LCD as you want them and in the order [0], [1], [2]... etc. For example, let's say that we have DB[7:4] connected to the upper 4 bits of the PCF I2C expander. We can setup the following:

buffer[0] = 0xD0 ; // 0b11010000;
buffer[1] = 0xA0 ; // 0b10100000;
buffer[2] = 0xF0 ; // 0b11110000;

HAL_I2C_Master_Transmit(&hi2c1, adresseLCD, buffer, 3, 10); // Note 3 bytes are sent

Once the buffer is prepared, the HAL_I2C_Master_Transmit() call will send the tree bytes consecutively, thus toggling the DB pins as you have mentioned:

DB7: 1 -> 1 -> 1
DB6: 1 -> 0 -> 1
DB5: 0 -> 1 -> 1
DB4: 1 -> 0 -> 1

The same can be applied to all 8 pins on the PCF chip. It is also worth noticing that this sequential IO update also creates a bit less of I2C communication overhead as it only addresses the I2C slave chip once :) .


By the way, I am currently working on a LCD over I2C Library for STM32F1xx (probably it will fit other STM32F series). You can check it out on github (still WIP):

https://github.com/meteowrite/stm32_i2cLcd

Cheers

Upvotes: 0

AterLux
AterLux

Reputation: 4654

You expect it wrong.

First of allб the I2C module, which is soldered on back, it is just simple serial-to parallel convertor. When you write data on I2C bus, it sets its 8 outputs according to 8 received bits in data bytes. When you read data bytes, it switches into input mode and read logical levels on 8 pins and transmits it over serial wire. More detailed description you can read in the datasheet on PCF8574 you have provided.

I.e. this part does not perform any "magic" which will take characters on input and output them on display. That means the outputting of random data is futile.

You need to know two things more:

  1. how this module is connected to the display driver
  2. what kind of display driver is used and how to utilize it.

Answer to the first question may be found in the Internet: I2C LCD module schematic (taken from here)

You can see the display is connected in 4-bit mode, outputs P4-P7 (i.e. what you transmit in four most significant bits of data bytes) are connected to data lines of the display, while outputs P0-P2 are connected to control lines RS, R/W, EH and P3 is used to control the backlight.

Knowing this we came to the second question. I can only suggest, but more likely your display module have Hitachi HD44780 IC on it. In the datasheet on it you can found the information what data should be output on the control lines.

You can find pin description at page 8:

  • bit RS selects whatever it be a command (0) or a data (1)
  • bit R/W chooses write opertion (0) or read (1)
  • and bit E is actually a strobe. On the falling edge, i.e. when it changes from 1 to 0, the display driver reads data from data lines. That means to pass 4 bits of data you should perform 2 write operations: first one with bit 2 is set high, second with all other bits are the same, but the bit 2 is zero.

Now you can read list of instructions at page 25 of datasheet. And initialization sequence for the 4-bit mode at page 46 (Figure 24). Note for each line of bits there you actually send 2 data bytes: with bit 2 high and then with bit 2 low.

Note, in 4-bit mode all commands and data consist of two write phases: first - top half, then bottom half of a byte. Each phase is 2 data writes to I2C module, with E bit high and low, i.e. you'll need to send 4 bytes to output 1 byte of data.

Upvotes: 1

Related Questions