• AVR Freaks

Helpful ReplyHot!Is it possible to interface an LCD without using delays?

Page: 12 > Showing page 1 of 2
Author
Mr_Waffles
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2019/08/05 14:12:56
  • Location: 0
  • Status: offline
2019/08/10 17:43:36 (permalink)
0

Is it possible to interface an LCD without using delays?

Greetings.
 
I was implementing my own library for a 16x2 LCD (with HD44780 driver), so I used delays between the pulses of sending data to the LCD. But I had problems using interrupts to do multitasking code, because I'm using timer0 and delays cause code processing lags.

So, I have a question: Is it possible not to use delays in LCD subroutines? Instead, use the interrupts themselves to generate pauses between the sending pulses.
 
I am using the PIC16F690.
 
Thank you very much in advance.
#1
jack@kksound
code tags!
  • Total Posts : 3203
  • Reward points : 0
  • Joined: 2014/05/14 10:03:19
  • Location: 0
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/12 09:54:04 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 16:04:13
+2 (2)
Many 16x2 character LCDs have a busy flag that you can read, usually the MSB of the command port. This requires that you control the R/W line rather then connect it to ground (always in write mode) which is the more common method with these small displays. During initialization sequences you will still need to place long delays between commands.
#2
Nikolay_Po
Super Member
  • Total Posts : 1884
  • Reward points : 0
  • Joined: 2012/04/01 13:49:27
  • Location: Russia, Novorossiysk
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/13 06:25:28 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 16:04:22
+2 (2)
I had a case with a display and interrupts. You may use two approaches:
  1. Keep delays as is. Ensure the display code is operating only in main loop and the interrupts have higher priority over display code execution. Just call display update not too often.
    For such displays the delays between state changes are quite small, in order of microseconds. The displays are not sensitive for data and clock signals jitter. If you are respecting minimum delays it will work with any larger delays. Data amount for character-generating display controller is usually small and the delays will not eat a lot of CPU time. So the CPU cycle loss in case of not very frequent display updating is not a large percent.
    If display delays are interfering with other main loop code then you need to move time-sensitive code into an ISR.
  2. Write a state machine for a display. Call it every main loop cycle. Keep display state to let your machine know which action to do next. Should it be data lines update or clock polarity change - all should be controlled though a state logic. You need some data buffer to place a data for display updating and a flag to inform display state machine that new data needs to be loaded into the display. This way the display will consume less CPU cycles because will work without of a delays. But it is more complicated to develop.
post edited by Nikolay_Po - 2019/08/13 06:29:34
#3
Gort2015
Klaatu Barada Nikto
  • Total Posts : 3233
  • Reward points : 0
  • Joined: 2015/04/30 10:49:57
  • Location: 0
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/13 07:36:20 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 16:04:29
+1 (1)
Do not even consider putting delays in interrupts, the busy flag is there for a reason.
At 37us (average), a 100MHz cpu could execute 3700 instructions.
 
An alternative would be to get one of the CH dual core chips and use the secondary core as a controller and buffer for the LCD.  The master can leave a message in a postbox, fire and forget.
 
post edited by Gort2015 - 2019/08/13 07:37:56

MPLab X playing up, bug in your code? Nevermind, Star Trek:Discovery will be with us soon.
https://www.youtube.com/watch?v=Iu1qa8N2ID0
+ ST:Continues, "What Ships are Made for", Q's back.
#4
Nikolay_Po
Super Member
  • Total Posts : 1884
  • Reward points : 0
  • Joined: 2012/04/01 13:49:27
  • Location: Russia, Novorossiysk
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/13 09:55:21 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 16:04:34
+2 (2)
16x2=32 characters to update whole screen plus 4 bytes (I don't remember how much exactly is needed to start an update from zero character). Total 36 bytes to send. In 4-bit mode two nibbles per byte. So 36*2=72 nibble to update the display. Each nibble requires two steps:
  1. Change data bits and the same time set "E" line logic high. Pause.
  2. Deactivate "E" line. Pause. Go to step 1 for next nibble.
Two pauses per nibble. So 72*2=144 pauses for whole display update. Enable line cycle should be not less that 500ns. And it will be safe to choose the pause of 250ns for each step. 144*250ns=36us for all pauses, whole screen update!
If you're updating the screen 5 times per second, it will require 36us*5=180us for display pauses. This is about 0.02% of CPU time irrespective to the speed. That is why I think the pauses in display code shouldn't harm if they are chosen accordingly the datasheet.
Of course, if the prototype is wired by long wires without signal integrity measures 250ns pauses may not work. But even with 50us pauses the pauses themselves will took only 2.6% of CPU time.
post edited by Nikolay_Po - 2019/08/13 09:56:34
#5
Mr_Waffles
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2019/08/05 14:12:56
  • Location: 0
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 16:16:27 (permalink)
0

Greetings.
I am very grateful for your contribution. Thank you very much.
 
But I still have a doubt about a function I have implemented.
 
I have attached the .txt file containing the function to perform character printing on the LCD display.
 
Note: I could not post the code normally, so I attached a file.
Thank you very much in advance.
#6
ric
Super Member
  • Total Posts : 23545
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Is it possible to interface an LCD without using delays? 2019/08/14 16:42:04 (permalink)
+1 (1)
What is your doubt?
You don't reveal what speed this is running at, so we have no idea how long your NOP() delay is.
Is this still on a PIC16F690?
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#7
1and0
Access is Denied
  • Total Posts : 9607
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 16:59:10 (permalink)
+1 (1)
What are the definitions of LCD_D4 to LCD_D7? Are they a nybble on the same port?
#8
Mr_Waffles
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2019/08/05 14:12:56
  • Location: 0
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:00:48 (permalink)
0
ric
What is your doubt?
You don't reveal what speed this is running at, so we have no idea how long your NOP() delay is.
Is this still on a PIC16F690?



Sorry about that.
I forgot to specify my question and also the frequency of operation.
I am using a PIC16F690 with a 16MHz crystal oscillator.
My question is whether it is possible to re-implement this function without using delays, ie only using interrupts, with the help of timer0, for example.
#9
Mr_Waffles
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2019/08/05 14:12:56
  • Location: 0
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:03:32 (permalink)
0
1and0
What are the definitions of LCD_D4 to LCD_D7? Are they a nybble on the same port?



My intention not to post all the code was to focus on the re-implementation of this function. But answering your last question: yes, the nibbles are connected in the same PORT.
#10
1and0
Access is Denied
  • Total Posts : 9607
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:11:38 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 17:14:06
+1 (1)
Mr_Waffles
I forgot to specify my question and also the frequency of operation.
I am using a PIC16F690 with a 16MHz crystal oscillator.

Then one NOP() is too long short for E high pulse.
 

My question is whether it is possible to re-implement this function without using delays, ie only using interrupts, with the help of timer0, for example.

The only significant delay is the execution time of 40 us or 1.64 ms (for Clear and Home).
 
Mr_Waffles
My intention not to post all the code was to focus on the re-implementation of this function. But answering your last question: yes, the nibbles are connected in the same PORT.

Then you can get rid of the OUTS[] array in that function.
post edited by 1and0 - 2019/08/14 17:15:11
#11
ric
Super Member
  • Total Posts : 23545
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:15:31 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 17:16:46
+1 (1)
If they are all in the same port, then this function can be made MUCH more efficient.
 
You don't need the 1ms delay after the first nybble write.
You do need a delay between each double-nybble transfer. You can do this with a timer, but then what are you going to do if the timer hasn't elapsed yet? Just wait anyway?
 
The alternative would be to create a FIFO buffer for your data, and have an timer interrupt running every few ms, writing one character from the FIFO buffer to the LCD on each interrupt.
 
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#12
Mr_Waffles
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2019/08/05 14:12:56
  • Location: 0
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:20:48 (permalink)
0
I will study your solution alternatives, Gort2015, Nikolay_Po, 1and0 and ric.
 
Many thanks for the guidelines! They will help me a lot.
post edited by Mr_Waffles - 2019/08/14 17:21:49
#13
1and0
Access is Denied
  • Total Posts : 9607
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:24:51 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 17:35:04
+1 (1)
For a 16x2 LCD, that is 32 character writes and 1 address set. Each takes about 40 us for a total of ~1.4 ms. Is that too much of a delay to write the entire LCD? Use the BUSY flag might shorten this time.
 
post edited by 1and0 - 2019/08/14 17:33:55
#14
Mr_Waffles
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2019/08/05 14:12:56
  • Location: 0
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:35:12 (permalink)
0
1and0
For a 16x2 LCD, that is 32 character writes. Each takes about 40 us for a total of ~1.3 ms. Is that too much of a delay to write the entire LCD? Use the BUSY flag might shorten this time.



It's really not a long time, but what motivated me not to use delays was the delay generated in an example program I did, which consisted of viewing the milliseconds spent on the LCD display, but it didn't work correctly due to the delays that the functions of character printing contained. What happened was that always the counter on the display was running behind a timer on my smartphone.
 
About the BUSY flag: Is this the ENABLE pin? If I'm wrong, I didn't see anything about the BUSY flag in the LCD display datasheets.
#15
ric
Super Member
  • Total Posts : 23545
  • Reward points : 0
  • Joined: 2003/11/07 12:41:26
  • Location: Australia, Melbourne
  • Status: online
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:39:30 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 17:42:15
+1 (1)
The LCD datasheet should mention BUSY.
It is bit 7 of any status read of the display. The other 7 bits are the current address pointer.
 
Your code has long generic delays. If you tuned it to only delay 40us after each character write, it would be much faster than what you have now.
You still need longer delays for "clear screen" etc.
 
 

I also post at: PicForum
Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
NEW USERS: Posting images, links and code - workaround for restrictions.
To get a useful answer, always state which PIC you are using!
#16
1and0
Access is Denied
  • Total Posts : 9607
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:41:23 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 17:53:04
+1 (1)
Mr_Waffles
 
It's really not a long time, but what motivated me not to use delays was the delay generated in an example program I did, which consisted of viewing the milliseconds spent on the LCD display, but it didn't work correctly due to the delays that the functions of character printing contained. What happened was that always the counter on the display was running behind a timer on my smartphone.

Then your bottleneck is somewhere else.
 

About the BUSY flag: Is this the ENABLE pin? If I'm wrong, I didn't see anything about the BUSY flag in the LCD display datasheets.

Look up the Read Busy Flag and Address command in your LCD datasheet.
#17
Mr_Waffles
New Member
  • Total Posts : 7
  • Reward points : 0
  • Joined: 2019/08/05 14:12:56
  • Location: 0
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:46:12 (permalink)
0
ric
The LCD datasheet should mention BUSY.
It is bit 7 of any status read of the display. The other 7 bits are the current address pointer.
 
Your code has long generic delays. If you tuned it to only delay 40us after each character write, it would be much faster than what you have now.
You still need longer delays for "clear screen" etc.



Actually, I will modify my code to make the necessary improvements.
 
1and0
 
Look up the Read Busy Flag and Address command in your LCD datasheet.



OK then. I will look more closely at the device datasheet.
 
#18
1and0
Access is Denied
  • Total Posts : 9607
  • Reward points : 0
  • Joined: 2007/05/06 12:03:20
  • Location: Harry's Gray Matter
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 17:47:12 (permalink) ☄ Helpfulby Mr_Waffles 2019/08/14 17:53:11
+1 (1)
ric
You still need longer delays for "clear screen" etc.

If timing is critical, instead of using the CLEAR command, set the address to the home position and then rewrite all 32 characters would be faster. Or, if appropriate, just rewrite whatever is needed on the screen.
#19
Nikolay_Po
Super Member
  • Total Posts : 1884
  • Reward points : 0
  • Joined: 2012/04/01 13:49:27
  • Location: Russia, Novorossiysk
  • Status: offline
Re: Is it possible to interface an LCD without using delays? 2019/08/14 23:50:23 (permalink)
0
With such a low RAM amount as 256 bytes it may be hard to provide 32 for display buffer. In all other cases when 32 bytes of RAM are not a problem I'm preferring to keep a buffer in RAM and one common whole display update  function. It may be simpler to work with a RAM bytes then update whole screen at once after the changes in RAM are completed.
My personal realization uses delays extensively and (I hope) insures the interface will not miss a nibble in case of data bus disturbances. But I used more powerful CPU at 40MIPS and with a lot of interrupt vectors to allow time critical code prioritization over  main loop code with delays.
 
#define FCY 40000000UL

#define Epin LATBbits.LATB11
#define RSpin LATBbits.LATB10
 
typedef struct {
    unsigned unused:9;
    unsigned VO : 1;
    unsigned RS : 1;
    unsigned E : 1;
    unsigned Nibble:4;
} DispPort_t;

#include <libpic30.h> //for delays, FCY should be defined before

void DisplayInit(void); //Initialize display
void UpdateDisplay(uint8_t Data[32], uint8_t CursorPos); //Whole display update function

DispPort_t* DispPtr = (DispPort_t*) & LATB; //A pointer to display data port

//Send a byte as a command (Mode = 0) or data (Mode = 1)

void DispByte(unsigned Byte, unsigned Mode) {
    //Set Command/Data mode
    if (Mode) {
        RSpin = 1;
    } else {
        RSpin = 0;
    }
    __delay32(12); //Address hold pause
    //Write high nibble
    (*DispPtr).Nibble = Byte >> 4;
    Epin = 1;
    __delay32(20); //Delay 500ns
    Epin = 0;
    __delay32(20); //Delay 500ns
    //Write low nibble
    (*DispPtr).Nibble = Byte;
    Epin = 1;
    __delay32(20); //Delay 500ns
    Epin = 0;
    __delay32(20); //Delay 500ns
}

void DisplayInit(void) {
    //Set display control pins to logic zero state
    (*DispPtr).Nibble = 0b0000;
    //Enable display control outputs
    TRISB &= ~_TRISB_TRISB15_MASK //D7
            & ~_TRISB_TRISB14_MASK //D6
            & ~_TRISB_TRISB13_MASK //D5
            & ~_TRISB_TRISB12_MASK //D4
            & ~_TRISB_TRISB11_MASK //E
            & ~_TRISB_TRISB10_MASK //RS
            & ~_TRISB_TRISB9_MASK; //VO converter
    __delay_ms(52); //Delay for VO voltage setup and controller power-up reset
    //Activate 4-bit communication mode as per SED1200 Series Technical Manual
    (*DispPtr).Nibble = 0b0011;
    Epin = 1;
    __delay32(20);
    Epin = 0;
    __delay_us(6150);
    Epin = 1;
    __delay32(20);
    Epin = 0;
    __delay_us(150);
    Epin = 1;
    __delay32(20);
    Epin = 0;
    __delay_us(60);
    (*DispPtr).Nibble = 0b0010;
    Epin = 1;
    __delay32(20);
    Epin = 0;
    __delay_us(60);
    //Now the controller is in 4-bit mode
    DispByte(0b00101000, 0); //Set 2-line mode
    __delay_us(82);
    DispByte(0b00001000, 0); //Set display off, cursor off, blink off
    __delay_us(82);
    DispByte(0b00000001, 0); //Clear display
    __delay_ms(5);
    DispByte(0b00000010, 0); //Increment on, display is not shifted
    __delay_us(3360);
    //Initialization is done

    DispByte(0b00001111, 0); //Turn on the display
    __delay_us(82);
    DispByte(0b10000000, 0); //Set address to 0x00
    __delay_us(82);
    DispByte(0x4F, 1);
    __delay_us(82);
    DispByte(0xBB, 1);
    __delay_us(82);
    DispByte(0x65, 1);
    __delay_us(82);
    DispByte(0xB4, 1);
    __delay_us(82);
    DispByte(0x21, 1);
    __delay_us(82);
}

void UpdateDisplay(uint8_t Data[32], uint8_t CursorPos) {
    DispByte(0b00101000, 0); //Ensure correct mode is set (2-line mode)
    __delay_us(82);
    DispByte(0b00000110, 0); //Entry mode with cursor shift enabled
    __delay_us(82);
    DispByte(0b00000010, 0); //Cursor home command
    __delay_us(3360);
    int i = 0;
    do {
        DispByte(Data[i], 1);
        __delay_us(82);
    } while (++i < 16);
    DispByte(0b10000000 | 0x40, 0); //Set cursor to bottom left position
    __delay_us(82);
    do {
        DispByte(Data[i], 1);
        __delay_us(82);
    } while (++i < 32);
    if (CursorPos) { //Check if the cursor should be displayed?
        CursorPos--; //Change index range 1..32 for 0..31
        if (CursorPos > 15) {
            CursorPos += 0x30; //Increase address if second line is chosen
        }
        DispByte(0b00001110, 0); //Turn on the display, enable the cursor
    } else {
        DispByte(0b00001100, 0); //Turn on the display, disable the cursor
    }
}

post edited by Nikolay_Po - 2019/08/14 23:52:23
#20
Page: 12 > Showing page 1 of 2
Jump to:
© 2019 APG vNext Commercial Version 4.5