Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

MCU interrupts interfering with HD48870 LCD operation

Status
Not open for further replies.

jmur

New Member
Im working with an ARM lpc2106. Today I attempted to add an LCD to my application. I noticed that at times random chars were being displayed on the LCD, and other times nothing at all was displayed. After some debugging I realized that timer interrupts (that have nothing to do with the LCD) were the cause. Is there a work around to this kind of problem? (beside removing interrupts)

Regards,
J
 
Im working with an ARM lpc2106. Today I attempted to add an LCD to my application. I noticed that at times random chars were being displayed on the LCD, and other times nothing at all was displayed. After some debugging I realized that timer interrupts (that have nothing to do with the LCD) were the cause. Is there a work around to this kind of problem? (beside removing interrupts)

Regards,
J

Possibilities
Timer interrupts are taking too long. Make them as short as possible.
Momentarily disable interrupts when writing to the LCD. The outputs only need to be stable for the time that the -CS is asserted to the LCD-chip'
 
Thanks wade and tunedwolf for your reply's. I think I will need to use another MCU for the LCD part of the application as one of the interrupts is firing at a rate of as little as few uSeconds apart. Temporarily disabling the interrupts in any way isn't an option as this would render the application unusable.

Regards,
J
 
As a last resort, you could synchronize the LCD-writes (which I assume are low priority, non-interrupt functions,) to the interrupt:
Code:
// LCD byte-write function
LCD_Write( char data, char data_or_ctrl) {
    (set up all outputs except '-CS' to LCD)
     Sync_Flag  = 0;  while ( !Sync_Flag);   // wait for clearance from interrupt
     CS_n = 0;                                           // we have a few microseconds available ..
     delay_us(1);
     CS_n = 1;                                           // .. so give a .CS-pulse
}

// add this to interrupt-routine
     Sync_Flag = 1;

This would make the LCD-writes safe as long as there is time for the CS_n to be asserted between interrupts.: 'a few microseconds' is plenty
I know there's an official computer-sciencese term for such klugery, but I don't know it.
It's something to be avoided, unless it saves you from a re-design
 
As a last resort, you could synchronize the LCD-writes (which I assume are low priority, non-interrupt functions,) to the interrupt:
Code:
// LCD byte-write function
LCD_Write( char data, char data_or_ctrl) {
    (set up all outputs except '-CS' to LCD)
     Sync_Flag  = 0;  while ( !Sync_Flag);   // wait for clearance from interrupt
     CS_n = 0;                                           // we have a few microseconds available ..
     delay_us(1);
     CS_n = 1;                                           // .. so give a .CS-pulse
}

// add this to interrupt-routine
     Sync_Flag = 1;

This would make the LCD-writes safe as long as there is time for the CS_n to be asserted between interrupts.: 'a few microseconds' is plenty
I know there's an official computer-sciencese term for such klugery, but I don't know it.
It's something to be avoided, unless it saves you from a re-design

Semaphore (programming) - Wikipedia, the free encyclopedia
https://www.electro-tech-online.com/custompdfs/2010/04/downey05semaphores.pdf

Twisty little passages, all different.
https://en.wikipedia.org/wiki/Colossal_Cave_Adventure
 
Last edited:
As a last resort, you could synchronize the LCD-writes (which I assume are low priority, non-interrupt functions,) to the interrupt:
Code:
// LCD byte-write function
LCD_Write( char data, char data_or_ctrl) {
    (set up all outputs except '-CS' to LCD)
     Sync_Flag  = 0;  while ( !Sync_Flag);   // wait for clearance from interrupt
     CS_n = 0;                                           // we have a few microseconds available ..
     delay_us(1);
     CS_n = 1;                                           // .. so give a .CS-pulse
}

// add this to interrupt-routine
     Sync_Flag = 1;

This would make the LCD-writes safe as long as there is time for the CS_n to be asserted between interrupts.: 'a few microseconds' is plenty
I know there's an official computer-sciencese term for such klugery, but I don't know it.
It's something to be avoided, unless it saves you from a re-design

Thanks not a bad idea I though that would work. Unfortunately it didn't. I messed around with interrupt rates and have determined that It works ok if the if interrupts are more than 220usec apart, though this is not much good to me.

Regards,
J
 
Last edited:
Thanks not a bad idea I though that would work. Unfortunately it didn't. I messed around with interrupt rates and have determined that It works ok if the if interrupts are more than 220usec apart, though this is not much good to me.

Regards,
J

Is there a critical section where you are reading/writing common data in the main program and the ISR? The problem might be elsewhere but the LCD is showing the result of scrambled data as the interrupt rate increases.
 
Last edited:
Is there a critical section where you are reading/writing common data in the main program and the ISR? The problem might be elsewhere but the LCD is showing the result of scrambled data as the interrupt rate increases.

I'm with him: writing to a parallel LCD should take no more than 5 uSec, even with generous setup times.
Stretching the interrupt time to 220uS is probably just making the problem very rare, not fixing it.
Do you have debugger that can trap accesses to the LCD's I/O port?
 
Is there a critical section where you are reading/writing common data in the main program and the ISR? The problem might be elsewhere but the LCD is showing the result of scrambled data as the interrupt rate increases.

No not yet, for now Im just printing "Testing LCD"
 
I'm with him: writing to a parallel LCD should take no more than 5 uSec, even with generous setup times.
Stretching the interrupt time to 220uS is probably just making the problem very rare, not fixing it.
Do you have debugger that can trap accesses to the LCD's I/O port?

No unfortunately I have no hardware debugger
 
Ive been doing some tests. I added a 1us delay before EN is brought low. Now the program works with interrupt intervals of approx of 11us, the output gets progressivley worse after this, at about 9us interval the second line deintinitializes.

Code:
void lcd_data_write(unsigned char display_data)
{
	GPIO_IOSET = LCD_RS;
	GPIO_IOSET = LCD_EN;
	GPIO_IOSET = display_data << 24;
	GPIO_IOCLR = ~display_data << 24;
	lcd_wait(2);		//1us
	GPIO_IOCLR = LCD_EN;
	lcd_wait(7500);		// 5ms 
}
 
Ive been doing some tests. I added a 1us delay before EN is brought low. Now the program works with interrupt intervals of approx of 11us, the output gets progressivley worse after this, at about 9us interval the second line deintinitializes.

Code:
void lcd_data_write(unsigned char display_data)
{
	GPIO_IOSET = LCD_RS;
	GPIO_IOSET = LCD_EN;
	GPIO_IOSET = display_data << 24;
	GPIO_IOCLR = ~display_data << 24;
	lcd_wait(2);		//1us
	GPIO_IOCLR = LCD_EN;
	lcd_wait(7500);		// 5ms 
}

Look at the lcd.h code. Maybe your ISR is using some of its resources/timing at a critical point.

lcd.h example code: http://www.avrbeginners.net/interfacing/24C16/lcd.h
Code:
//LCD_getaddress reads the address counter and busy flag. For the address only,
//mask off bit7 of the return value.
char LCD_getaddr(void)
{
	//make var for the return value
	char address;
	//PortD is input
	DDRD = 0;
	//RW high, strobe enable
	PORTC |= ((1<<LCD_RW)|(1<<LCD_E));
	asm volatile ("nop");
	asm volatile ("nop");
	//while E is high, get data from LCD
	address = PIND;
	//reset RW to low, E low (for strobe)
	PORTC &= ~((1<<LCD_RW)|(1<<LCD_E));
	//return address and busy flag
	return address;
}

//LCD_wait reads the address counter (which contains the busy flag) and loops until
//the busy flag is cleared.
void LCD_wait(void)
{
	//get address and busy flag
	//and loop until busy flag cleared
	while((LCD_getaddr() & 0x80) == 0x80);
}
 
Last edited:
Code:
void lcd_data_write(unsigned char display_data)
{
	GPIO_IOSET = LCD_RS;
	[COLOR="red"]//GPIO_IOSET = LCD_EN;                   move this[/COLOR]
	GPIO_IOSET = display_data << 24;
	GPIO_IOCLR = ~display_data << 24;
	[COLOR="red"]GPIO_IOSET = LCD_EN;//                   here[/COLOR]
	lcd_wait(2);		//1us
	GPIO_IOCLR = LCD_EN;
	lcd_wait(7500);		// 5ms 
}

Why are you enabling the LCD before setting up the data lines?
 
Last edited:
Look at the lcd.h code. Maybe your ISR is using some of its resources/timing at a critical point.

lcd.h example code: http://www.avrbeginners.net/interfacing/24C16/lcd.h
Code:
//LCD_getaddress reads the address counter and busy flag. For the address only,
//mask off bit7 of the return value.
char LCD_getaddr(void)
{
	//make var for the return value
	char address;
	//PortD is input
	DDRD = 0;
	//RW high, strobe enable
	PORTC |= ((1<<LCD_RW)|(1<<LCD_E));
	asm volatile ("nop");
	asm volatile ("nop");
	//while E is high, get data from LCD
	address = PIND;
	//reset RW to low, E low (for strobe)
	PORTC &= ~((1<<LCD_RW)|(1<<LCD_E));
	//return address and busy flag
	return address;
}

//LCD_wait reads the address counter (which contains the busy flag) and loops until
//the busy flag is cleared.
void LCD_wait(void)
{
	//get address and busy flag
	//and loop until busy flag cleared
	while((LCD_getaddr() & 0x80) == 0x80);
}

Are you saying I should use the busy flag? if so thats not an option..

Regards,
V
 
Why are you enabling the LCD before setting up the data lines?

Thats the way I was thought in college. Is this not the standard way to do it?

Im in middle of implementing nested interrupts, so once Iv sorted that Ill give your suggestion a go, it can't hurt!

Regards,
V
 
Are you saying I should use the busy flag? if so thats not an option..

Regards,
V

You have hard-coded delays, checking the flag might be quicker at times and less clock dependent. Check table 6 of the HD44780 datasheet .
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top