Hd44780Lcd busy flag
#1
Posted 17 April 2013 - 09:18 PM
#2
Posted 18 April 2013 - 10:30 AM
I think the LCD busy flag just says the LCD controller is busy performing a command and that you have to wait before issuing another command. Since the driver class is bitbanging the LCD controller (if using Stefans toolbox), the busy flag should never assert since communication is very slow compared to what the LCD controller should be capable of. This means you don't have to worry about the busy flag.
Instead my guess is that simultaneous operations on the LCD, originating from different threads, somehow slip through anyway even though you got the semaphore. I almost always use the lock statement to do mutual exclusion since its much easier to use than semaphores. You can use the lock statement like in this pseudo code:
lock(_lcd){ _lcd.WriteSting("Hello");}
That will make sure only one thread at a time can write a string to the LCD. You can use the lock statement on several places in your code and as long as you always lock on the same object (_lcd), it will guarantee mutually exclusive access to the LCD.
Another solution, however more complex, would be to let threads do LCD operations asynchronously by buffering them in a monitored queue. You then have a dedicated worker thread eating off the queue performing operations against the LCD synchronously according to the FIFO principle. By letting the LCD worker thread sleep for a little while in between dequeuing and performing each LCD write operation, you would make sure that each message will be displayed for at least a brief moment (equal to the sleep duration) before the next message gets displayed. This should work well as long as operations do not come in too frequently causing the queue to build up and eventually overflow.
#3
Posted 18 April 2013 - 03:17 PM
thanks for your clarification, i already thought about the second method but i will try the lock mechanism first..
#4
Posted 18 April 2013 - 09:34 PM
After how many minutes/hours this happens?
You haven't mentioned if you are using the LCD in SPI or i2c mode, I am not at home right now but maybe the Toobox is meant for i2C only. Anyway, I remember having the same issue when using SPI mode and reducing the LCD's clock rate fixed the problem. Try 600 and let me know how it goes.
#5
Posted 19 April 2013 - 07:48 AM
#6
Posted 19 April 2013 - 08:25 AM
#7
Posted 21 April 2013 - 10:08 AM
yes i am using stefan's tools box , and now i solved the whole problem by implementing my own class below
namespace SLCD{ class SLCD { private bool _busyflag = false; private Hd44780Lcd _lcd; private int _rows, _cols; private byte _posr, _posc; [MethodImpl(MethodImplOptions.Synchronized)] public SLCD(Hd44780Lcd objlcd) { _lcd = objlcd; _rows = _lcd.Rows; _cols = _lcd.Columns; _posc = 0; _posr = 0; } [MethodImpl(MethodImplOptions.Synchronized)] public void write(string str, byte row, byte col,bool retpos) { if (row >= _rows || col >= _cols) return; while (_busyflag) { } lock (_lcd) { byte cr = _posr; byte cc = _posc; bool bp = _lcd.BlinkPosition; _busyflag = true; _lcd.BlinkPosition = false; cp(row, col); _lcd.Write(str); _lcd.ChangePosition(cr, cc); _lcd.BlinkPosition = bp; _busyflag = false; } } [MethodImpl(MethodImplOptions.Synchronized)] public void write(string str,byte row,byte col) { if (row >= _rows || col >= _cols) return; while (_busyflag) { } lock (_lcd) { _busyflag = true; cp(row, col); _lcd.Write(str); _posc += (byte)str.Length; //_posc -= 1; _posr = row; _busyflag = false; } } [MethodImpl(MethodImplOptions.Synchronized)] public void write(string str) { while (_busyflag) { } lock (_lcd) { _busyflag = true; _lcd.Write(str); _posc += (byte)str.Length; //_posc -= 1; _busyflag = false; } } [MethodImpl(MethodImplOptions.Synchronized)] public void cp(byte row, byte col) { lock (_lcd) { _lcd.ChangePosition(row, col); _posr = row; _posc = col; } } }}
#8
Posted 21 April 2013 - 01:34 PM
#9
Posted 22 April 2013 - 07:02 AM
great notes,
i'll start to deploy and i'll inform you about the results
thanks ...
#10
Posted 22 April 2013 - 07:48 AM
yep it is working great ...... thanks again....
namespace SLCD{ class SLCD { private Hd44780Lcd _lcd; private int _rows, _cols; private byte _posr, _posc; private bool _ShowCursor, _BlinkPosition; public SLCD(Cpu.Pin D4, Cpu.Pin D5,Cpu.Pin D6,Cpu.Pin D7,Cpu.Pin CE,Cpu.Pin RS, int cols, int rows) { _lcd = new Hd44780Lcd( Data4: D4, Data5: D5, Data6: D6, Data7: D7, ClockEnablePin: CE, RegisterSelectPin: RS, Columns : cols, Rows : rows ); _rows = _lcd.Rows; _cols = _lcd.Columns; _posc = 0; _posr = 0; _ShowCursor = false; _BlinkPosition = false; } public void write(string str, byte row, byte col,bool retpos) { if (row >= _rows || col >= _cols) return; lock (_lcd) { byte cr = _posr; byte cc = _posc; bool bp = _lcd.BlinkPosition; _lcd.BlinkPosition = false; cp(row, col); _lcd.Write(str); _lcd.ChangePosition(cr, cc); _lcd.BlinkPosition = bp; } } public void write(string str,byte row,byte col) { if (row >= _rows || col >= _cols) return; lock (_lcd) { cp(row, col); _lcd.Write(str); _posc += (byte)str.Length; _posr = row; } } public void write(string str) { lock (_lcd) { _lcd.Write(str); _posc += (byte)str.Length; } } public void cp(byte row, byte col) { lock (_lcd) { _lcd.ChangePosition(row, col); _posr = row; _posc = col; } } public void cleardisplay() { lock (_lcd) { _lcd.ClearDisplay(); } } public bool ShowCursor { get { return _ShowCursor; } set { _ShowCursor = value; lock (_lcd) { _lcd.ShowCursor = _ShowCursor; } } } public bool BlinkPosition { get { return _BlinkPosition; } set { _BlinkPosition=value; lock(_lcd) { _lcd.BlinkPosition = _BlinkPosition; } } } }}
- hanzibal likes this
#11
Posted 22 April 2013 - 08:34 AM
That's great!
#12
Posted 23 June 2013 - 03:35 PM
[font="arial, sans-serif;"][color=rgb(51,51,51);]I'm using[/color][/font][font="arial, sans-serif;"][color=rgb(51,51,51);] toolbox[/color] NETMF[/font] Hd44780Lcd Class with 4x20 character LCD
I have trouble when I write on the LCD within an interrupt, which is triggered by the onboard switch.
The display shows strange characters and you lose control, [font="arial, sans-serif;"][color=rgb(51,51,51);]also[/color][/font][font="arial, sans-serif;"][color=rgb(51,51,51);] the[/color] Thread.Sleep[/font] not working properly within the interruption
[font="arial, sans-serif;"][color=rgb(51,51,51);]As[/color][/font][font="arial, sans-serif;"][color=rgb(51,51,51);] I can[/color] include your[/font] class in my program, I have not much experience in NETMF, thank you .
Followed show my program.
using System;using System.Net;using System.Net.Sockets;using System.Threading;using Microsoft.SPOT;using Microsoft.SPOT.Hardware;using SecretLabs.NETMF.Hardware;using SecretLabs.NETMF.Hardware.Netduino;using Toolbox.NETMF.Hardware;namespace LCDprueba2{ public class Program {// initialize the onboard LED private static OutputPort ledPort = new OutputPort(Pins.ONBOARD_LED, false); // initializa LCD public static Hd44780Lcd Display = new Hd44780Lcd( Data4: Pins.GPIO_PIN_D0, Data5: Pins.GPIO_PIN_D1, Data6: Pins.GPIO_PIN_D2, Data7: Pins.GPIO_PIN_D3, ClockEnablePin: Pins.GPIO_PIN_A1, RegisterSelectPin: Pins.GPIO_PIN_A2,ReadWritePin:Pins.GPIO_NONE,Columns:20,Rows:4 ); public static void Main() { // initialize the onboard switch InterruptPort switchPort = new InterruptPort(Pins.ONBOARD_SW1, true,Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth); // add an event-handler for the switch switchPort.OnInterrupt += new NativeEventHandler(switchPort_OnInterrupt); while(true) { Display.ClearDisplay(); Display.ChangePosition(0, 0); Thread.Sleep(1000); Display.Write("Hello World!"); Thread.Sleep(1500); } }// cierre main private static void switchPort_OnInterrupt(uint port, uint data, DateTime time) { // turn the LED on, //if the button is pressed (== 0, because switch is inverted) ledPort.Write(data == 0); Display.ChangePosition(0, 0); Thread.Sleep(1000); Display.Write("I am in interruption"); Thread.Sleep(3000); } // cierre interrupcion }}
#13
Posted 23 June 2013 - 09:52 PM
It's probably coming from two or more threads accessing the LCD driver simultaneously, try adding lock statements around things that need be executed exclusively. There was a case recently with the same problem - and the same solution. I'll see if I can dig it out...
EDIT: Turned out the mentioned case was in fact this very thread :-)
Have a look at some code earlier in this thread on how to use the lock statement. You see, the LCD driver is not "thread safe" meaning it cannot deal with multiple threads. What happens is that your main thread gets interrupted in the middle of transferring data to the LCD by the interrupt service routine which then starts sending its own data to the LCD in the middle of the ongoing operation. The LCD will get very confused by this and put in an out-of-sync state effectively garbling every operation from there on.
EDIT: Oh, and you should never have a thread sleep in an interrupt service routine! It should act like a hit squad - get in, do the job and get the h-ll out of there
#14
Posted 24 June 2013 - 05:46 PM
hanzibal thank you very much for your comments, I will work on this, and then comment my progress
Best regards
Marcelo Roberto Panizzi
0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users