2017-10-21 12:04 PM
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-bugSolved! Go to Solution.
2017-10-23 02:46 AM
I solved the problem. It appeared that the screen is very sensitive to proper time delays.
Thank You.
2017-10-22 01:35 PM
I2C master is easy to bit-bang. I'd try that to exclude problems with the HW I2C module.
JW
2017-10-23 02:46 AM
I solved the problem. It appeared that the screen is very sensitive to proper time delays.
Thank You.
2017-12-11 10:45 AM
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?
2017-12-11 12:27 PM
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?
2017-12-11 12:38 PM
What pullup are you using, and how long interconnections?
Scope SCL/SDA.
JW
2017-12-11 10:35 PM
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.