Skip to main content
Lyubomyr D
Associate II
October 21, 2017
Solved

LCD1602 + pcf8574 (I2C) + STM32F0

  • October 21, 2017
  • 3 replies
  • 2594 views
Posted on October 21, 2017 at 21:04

Hello.

I have some problem with LCD1602+pcf8574 (I2C) and STM32F0. 

I experience the following bugs

1) When I try to display more than three symbols they seem to be ignored

2) If I try to display three symbols, I have to flush the firmware twice(one directly after another) in order to display changes on the LCD1602 screen

It seems that there is some overrun(????), but I can't figure out where.

What am I doing wrong?

Help me, please.

main.c

&sharpinclude 'stm32f0xx.h'

&sharpinclude 'i2c_lcd.h'

&sharpdefine I2C1_OWN_ADDRESS (0x27)

int main(void) {

    SystemInit();

    

gpioInit();

    

i2cInit();

    

InitDelayTIM6();

    

delay_init();

    

lcd_Init();

    

lcd_PrintC('ABC'); //if I try to print ABCD nothing happends; Another three letter can be displayed

    

while(1) { }

}

void gpioInit(void) {

    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;

    GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7)) \

        | (GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1);

    GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7;

    GPIOB->AFR[0] = (GPIOB ->AFR[0] &~ (GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7))\

        | (1 << (6 * 4)) | (1 << (7 * 4));

}

void i2cInit(void) {

    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;

    I2C1->CR1 &= ~(I2C_CR1_PE) ;

/* Timing register value is computed with the AN4235 xls file,

Standard Mode @50kHz with I2CCLK = 48MHz, rise time = 100ns, fall time = 30ns */

    I2C1->TIMINGR = (uint32_t) 0x205078C1; 

    I2C1->CR1 |= I2C_CR1_PE ; 

    I2C1->CR2 |= I2C_CR2_AUTOEND | (1<<16) | (I2C1_OWN_ADDRESS<<1);

}

i2c_lcd.c

&sharpinclude 'i2c_lcd.h'

&sharpinclude 'stm32f0xx_i2c.h' // this one is not used

uint8_t backlightState = 1;

void lcd_PrintC(const uint8_t *str) {

    uint8_t i;

    while (i = *str++){

        lcd_Data(i);

       TIM6delay_ms(2);

    }

}

void lcd_Init(void) {

    TIM6delay_ms(50);

    lcd_FirstCommand();

    

lcd_Command(0x28);// 4bit 2 lines, 5x8 font. Page 8 Function Set. Page 9 Top.

    

lcd_Command(0x08); // display off entirely. Page 6, row 4. Page 8 Display On/Off

    

lcd_Command(0x06); //Page 6 Row 3

    

lcd_Command(0x01);// Clear display. Page 6, first row. Page 7 Clear Display.

    

lcd_Command(0x02); //Return home

    

lcd_Command(0x80);

    

lcd_Command(0x0E);

    TIM6delay_ms(1000);

}

void lcd_Send(uint8_t data) {

    

while((I2C2->ISR & I2C_ISR_BUSY) == (I2C_ISR_BUSY));

    

while(!((I2C1->ISR & I2C_ISR_TXE) == (I2C_ISR_TXE))); // Check Tx empty

    

I2C1->TXDR = data; // Byte to send

    

I2C1->CR2 |= I2C_CR2_START; // Go

    

    

while(!((I2C1->ISR & I2C_ISR_TXE) == (I2C_ISR_TXE)));

    

while((I2C2->ISR & I2C_ISR_BUSY) == (I2C_ISR_BUSY));

}

void lcd_FirstCommand(void) {

    // I am sending 0x33 followed by 0x32. The delays are from datasheet

    // the data is sent as EN changes from High to Low

    

lcd_Send(0x03 |(backlightState & 0x01) << BL);

    

lcd_Send(0x03 | (1 << EN));

    

TIM6delay_us(2);

    

lcd_Send(0x03|((backlightState & 0x01) << BL));

    TIM6delay_us(4100);

    

lcd_Send(0x03|(backlightState & 0x01) << BL);

    

lcd_Send(0x03 | (1 << EN));

    

TIM6delay_us(2);

    

lcd_Send(0x03|((backlightState & 0x01) << BL));

    

TIM6delay_us(100);

    

lcd_Send(0x03|((backlightState & 0x01) << BL));

    

lcd_Send(0x03 | (1 << EN));

    

TIM6delay_us(2);

    

lcd_Send(0x03|((backlightState & 0x01) << BL));

    

lcd_Send(0x02|((backlightState & 0x01) << BL));

    

lcd_Send(0x02 | (1 << EN));

    

TIM6delay_us(2);

    

lcd_Send(0x02|((backlightState & 0x01) << BL));

}

void lcd_Command(uint8_t com) {

    

uint8_t data = 0;

    

data |= (backlightState & 0x01) << BL;

    

data |= (((com & 0x10) >> 4) << DB4);

    

data |= (((com & 0x20) >> 5) << DB5);

    

data |= (((com & 0x40) >> 6) << DB6);

    

data |= (((com & 0x80) >> 7) << DB7);

    

lcd_Send(data);

    

lcd_Send(data | (1 << EN));

    

TIM6delay_us(2);

    

lcd_Send(data);

    

data = 0;

    

data |= (backlightState & 0x01) << BL;

    

data |= (((com & 0x01) >> 0) << DB4);

    

data |= (((com & 0x02) >> 1) << DB5);

    

data |= (((com & 0x04) >> 2) << DB6);

    

data |= (((com & 0x08) >> 3) << DB7);

    

lcd_Send(data);

    

lcd_Send(data | (1 << EN));

    

TIM6delay_us(2);

    

lcd_Send(data);

}

void lcd_Backlight(uint8_t state) {

    

backlightState = (state & 0x01) << BL;

    

lcd_Send(backlightState);

}

void lcd_Data(uint8_t com) {

    

uint8_t data = 0;

// this differes 'data' from 'command' . Data - symbol to be displayed

    

data |= (1 << RS);

    

data |= (backlightState & 0x01) << BL;

    

data |= (((com & 0x10) >> 4) << DB4);

    

data |= (((com & 0x20) >> 5) << DB5);

    

data |= (((com & 0x40) >> 6) << DB6);

    

data |= (((com & 0x80) >> 7) << DB7);

    

    

lcd_Send(data);

    

lcd_Send(data | (1 << EN));

    

TIM6delay_us(2);

    

lcd_Send(data);

    

data = 0;

    

data |= (1 << RS);

    

data |= (backlightState & 0x01) << BL;

    

data |= (((com & 0x01) >> 0) << DB4);

    

data |= (((com & 0x02) >> 1) << DB5);

    

data |= (((com & 0x04) >> 2) << DB6);

    

data |= (((com & 0x08) >> 3) << DB7);

    

lcd_Send(data);

    

lcd_Send(data | (1 << EN));

    

TIM6delay_us(2);

    

lcd_Send(data);

}

I am sorry for such a long question. Thank You very much for Your time!

#lcd1602 #i2c #stm32f0 #funny-bug
This topic has been closed for replies.
Best answer by Lyubomyr D
Posted on October 23, 2017 at 11:46

I solved the problem. It appeared that the screen is very sensitive to proper time delays.

Thank You.

3 replies

waclawek.jan
Super User
October 22, 2017
Posted on October 22, 2017 at 22:35

I2C master is easy to bit-bang. I'd try that to exclude problems with the HW I2C module.

JW

Lyubomyr D
Lyubomyr DAuthorBest answer
Associate II
October 23, 2017
Posted on October 23, 2017 at 11:46

I solved the problem. It appeared that the screen is very sensitive to proper time delays.

Thank You.

shane mattner
Senior
December 11, 2017
Posted on December 11, 2017 at 19:45

I'm having the same problem with a 'NHD-0420D3Z-FL-GBW-V3' LCD and STM32F410RB nucleo board.  I can send more than 3 characters to the LCD but I get inconsistent results.  Sometimes when I send 'test' the display will show 'tes' and sometimes 'tst' or even 'tet'. 

How did you ensure the proper timing to fix the issue?

shane mattner
Senior
December 11, 2017
Posted on December 11, 2017 at 20:27

I got the LCD to display the proper text consistently by lowering the speed to 10kHz instead of 100kHz.  I tried all the speeds in between in 10kHz intervals (90kHz, 80kHz, etc) and only 10kHz gave me consistent results.  Some of the the speeds would give mostly consistent results but I was still getting random letters and symbols popping up when I reset the board a bunch of times for testing.

Anyone have an idea what could be happening here to cause these results?

waclawek.jan
Super User
December 11, 2017
Posted on December 11, 2017 at 20:38

What pullup are you using, and how long interconnections?

Scope SCL/SDA.

JW