Hd44780Lcd busy flag - Netduino Plus 2 (and Netduino Plus 1) - Netduino Forums
   
Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Hd44780Lcd busy flag


  • Please log in to reply
13 replies to this topic

#1 ahmedfme

ahmedfme

    Member

  • Members
  • PipPip
  • 14 posts
  • LocationEgypt

Posted 17 April 2013 - 09:18 PM

I am using the netmf toolbox Hd44780Lcd class with 4x20 character lcd and it works fine. But I faced a problem when start to use it in multithreaded project. I implement a timer which display the current time every second and at the same time monitor user inputs on keypad and at the same time monitor web service received posts and display some info on arrival and monitor lm35 temp and update each minute.and a lot of other tasks distributed in different threads. I found that when more than one thread tries to write to lcd it start to display strange characters and after a while display nothing. I have implemented a busy semaphore to prevent concurrent accessing to LCD. But I am wondering if Hd44780Lcd class checks Busy Flag of the module or not. And if it checks , why this happen. Reg. Ahmed

#2 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

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 ahmedfme

ahmedfme

    Member

  • Members
  • PipPip
  • 14 posts
  • LocationEgypt

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 Giuliano

Giuliano

    Advanced Member

  • Members
  • PipPipPip
  • 361 posts
  • LocationSimi Valley, CA

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 ahmedfme

ahmedfme

    Member

  • Members
  • PipPip
  • 14 posts
  • LocationEgypt

Posted 19 April 2013 - 07:48 AM

I am using it in normat 4 bit mode no spi nor i2c

#6 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 19 April 2013 - 08:25 AM

Are you using Stefan's Toolbox? Any progress?

#7 ahmedfme

ahmedfme

    Member

  • Members
  • PipPip
  • 14 posts
  • LocationEgypt

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 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 21 April 2013 - 01:34 PM

Very nice, writing a wrapper class is a good solution but you can actually omit the while(_busyflag) construct too since each thread will block on the lock statements until the thread currently inside the locked region exits the locked region. The latter functionality is what makes lock statements so versatile and simple to use compared to using the underlaying mutex construct directly. In general, you should avoid the kind of busy waits induced by the while(_busyflag) and similar schemes since such constructs will typically yield low performance and poor reponsiveness. EDIT: I now discovered that you have already marked your functions as "synchronized" which would omit the need for lock statements. However, I'm not sure the "synchronized" attribute really works in .NET MF. If you decide to go with lock statements (which I know to work for sure), you can certainly remove both the while(_busyflag) and the "synchronized" attributes. Also, it's good practice not to issue locks on objects residing outside your class because if another thread locks on that object outside your class, you could get a deadlock situation and your application locks up. Rather, you should create a private object _sync = new object() and lock on that instead instead. Why not let the wrapper class create the LCD object and keep it to itself as a private member, then you can safely look on it?

#9 ahmedfme

ahmedfme

    Member

  • Members
  • PipPip
  • 14 posts
  • LocationEgypt

Posted 22 April 2013 - 07:02 AM

great notes,

i'll start to deploy and i'll inform you about the results

thanks ... :)



#10 ahmedfme

ahmedfme

    Member

  • Members
  • PipPip
  • 14 posts
  • LocationEgypt

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;                }            }        }            }} 


#11 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

Posted 22 April 2013 - 08:34 AM

That's great!



#12 marcelo_bahia

marcelo_bahia

    New Member

  • Members
  • Pip
  • 3 posts

Posted 23 June 2013 - 03:35 PM

ahmedfme

[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    }}

Posted Image



#13 hanzibal

hanzibal

    Advanced Member

  • Members
  • PipPipPip
  • 1287 posts
  • LocationSweden

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  :ph34r:



#14 marcelo_bahia

marcelo_bahia

    New Member

  • Members
  • Pip
  • 3 posts

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

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.