cancel
Showing results for 
Search instead for 
Did you mean: 

LCD1602 + pcf8574 (I2C) + STM32F0

Lyubomyr D
Associate II
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
1 ACCEPTED SOLUTION

Accepted Solutions
Lyubomyr D
Associate II
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.

View solution in original post

6 REPLIES 6
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
Associate II
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
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?

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?

Posted on December 11, 2017 at 20:38

What pullup are you using, and how long interconnections?

Scope SCL/SDA.

JW

Posted on December 12, 2017 at 06:35

I used the internal pull-up initially and then I tried with external 4.7k resistors.  But they had no effect at any speed (10kHz still works fine).  I'm using jumper wires that are maybe 5' long.  I've never had a problem with other processors when using jumpers of this (and longer) length with LCD's.

Good idea on scoping the communication.  I'll try that out.