piface / libpifacecad

A simple C library for accessing PiFace Control and Display.
GNU General Public License v3.0
10 stars 8 forks source link

Using libpifacecad sometimes corrupts LCD display #1

Closed flyn-org closed 10 years ago

flyn-org commented 10 years ago

I am working a program that makes use of libpifacecad to manipulate my PiFace CAD. I am using the library's pifacecad_open, pifacecad_lcd_backlight_on, pifacecad_lcd_clear, piface_lcd_write, and piface_lcd_close functions. Rather often, the display of the PiFace CAD shows a corrupt string of characters.

I wrote a simple test program containing:

int main(void) { pifacecad_open(); pifacecad_lcd_backlight_on(); pifacecad_lcd_clear(); pifacecad_lcd_write("Hello, World!"); pifacecad_close(); }

I have found that even this program corrupts the screen, although much more rarely than my larger program. For example, once I saw a corrupt screen after the 43rd run. Other times, I see the corrupt screen every 20 or so runs. I run these tests with the following, where a.out is the program above:

c=0; while true; do ./a.out; c=$((c + 1)); echo $c; read; done

tompreston commented 10 years ago

My first thoughts were that this could be a timing issue. However I managed to get up to 400+ runs without any screen corruption.

Perhaps you have less tolerant hardware? Have you tried increasing the delays in pifacecad.h? Just increasing DELAY_SETTLE_NS should do.

flyn-org commented 10 years ago

Increasing DELAY_SETTLE_NS does seem to fix the problem. Multiplying your value by 10 was not enough, but after multiplying by 100, I could no longer get the screen to corrupt.

tompreston commented 10 years ago

Does it impact the speed of your program, greatly? I want to change DELAY_SETTLE_NS to the value you have used. However, this will slow down the operation of other PiFace Control and Display's that work with the current value.

I'm going to leave the header file as is for now but leave this issue open to see if any more people have similar issues within the week.

xpeace commented 10 years ago

I have the same issue here furthermore I experience display brightness flickering during write access. This is Independent from the power supply. Tested with 2A5V as well as 1A5V, behaviour seems a bit unstable when accessing the CAD Modul using libpifacecad code. By the way example Code for the button read using an event driven mechanism in c++ would be nice. Some further insight would be nice

tompreston commented 10 years ago

@xpeace Does increasing the settle delay not fix your issue? What about the Python modules? Can you upload an video of the problem to YouTube or something? This is difficult to test since libpifacecad works on all of our boards.

Event driven mechanisms will require using epoll to monitor events on GPIO pin 25 which is where the interrupt pin is connected to. I'm completely snowed under with work at the moment so I can't implement this myself (at the moment) but it should be possible to do with a bit of reading.

xpeace commented 10 years ago

Things that seem to have increased stability (I can't reproduce it any more):

xpeace commented 10 years ago

Looks like a race condition, I had two threads trying to access the unit, resulting in a messed up display, currently its working again, also reset to default 40µs timing delay,

OS: Raspbian Wheezy Compiler: Codeguru Chain for Windows (http://www.gurucoding.com/en/rpi_cross_compiler/index.php)

dch26 commented 10 years ago

I am having exactly the same issue. I am getting corrupt text on the lcd after a seemingly random amount of time. I have tried changing the 40,000 to 400,000 and 4,000,000 in pifacecad.h but makes no difference. Also on raspbian. Once corrupt, software recovery not possible. Have to restart program. Any thoughts?

tompreston commented 10 years ago

@xpeace I don't have a joystick so I can't test your program. Glad to hear things are working again though!

@dch26 Have you overclocked your Pi? Most of the problems seem to be timing issues (overclocking/concurrent bus access)

TheBurrito commented 10 years ago

I was likewise seeing corruption that would scroll from right to left after a seemingly random amount of time (though always within 30s of running my app).

I have since reset the OC setting with raspi-config and it is now stable. My sequence of calls was:

open, blink off, cursor off

and once per second in a loop:

clear, write (6-8 chars), set cursor, write (6-8 chars), and either backlight on or off.

ANYTIME I tried to set position to the first row (0) with my system overclocked the entire display would instantly go blank. If I just let the text lay out or used a newline in the first write to move the second write to the second line without setting position the display would work for quite some time before garbage characters would scroll in from the right and move one position every loop.

In all cases the backlight control still worked as expected based off of calculated values that I was supposed to be displaying.

TheBurrito commented 10 years ago

And right as I posted, the screen went all wonky. As soon as I get my pi shutdown and get code copied over I'll post a pastebin of my app source.

Edit: linky: http://pastebin.com/9MLt26TP

sshivaji commented 10 years ago

I referenced this issue on the pifacecad python page. Looking over the code pastebin, the problem is exactly the same as I had. This problem now seems clear at a high level to me.

When there are 2 concurrent lcd writes (with no barrier between the instructions), the display will become garbled. In the code sample above, when the loop is executing quickly, 2 writes can happen at the same time. The reason can be that fscanf and fopen will soon be read quickly from a page cache.

I first noted this when I was updating the display every second. The solution for my app was make all writes to the display from one method. I added a lock to that method so that only one write can occur at a time (in C, you can likely use a posix semaphore). The garbled text issue then subsided.

However, I also wonder why the piface should have garbled text in the first place when concurrent writes are performed. Can that be better handled at a lower level?

sshivaji commented 10 years ago

In the above loop, I now wonder if the compiler is optimizing the instructions so that the sleep call is not executed as often. Curious to see the assembly :)

dch26 commented 10 years ago

@tompreston - no, my pi is not overclocked.

@sshivaji - i am not doing concurrent writes. my application is single threaded and i write to the screen once a second from a single subroutine. i am not using python, so we can rule that out being at fault.

xpeace commented 10 years ago

All other implementations on the web of the hd44780 I`ve seen use an additional LCDBusy check before writing, not just rely on timings. Maybe this would contribute to overclocking stability issues as well. By the way what happens when writing to LCD and reading the Buttons concurrently, may this cause problems as well ? If so, this should probably be solved on "Driver" level as well, ... I am currently using booleans when accessing the LCD bReadButtonAllowed = false, and when accessing the button, bWriteLCDAllowed=false, ... so far this seems to kinda work, (tho it seems more like a workaround) . While making some propositions here - what about boxfill, would that be theoretically possible on the LCD ?

sshivaji commented 10 years ago

@dch26 python or not, the issue is the same. Can you confirm via assembly or the low level trace that it indeed happens once a second, the compiler could be optimizing away your code. Try putting a lock on every write and a small sleep to ensure that nothing else is happening during a write and see if that solves your problem.

@xpeace reading and writing at the same time could be the problem as well. I will test for that. If the hd44780 uses an LCD busy check, there is definitely an issue at the driver level.

tachijuan commented 10 years ago

For what it's worth I had this issue with python as well. Ended up writing a class than would enqueue writes and issue them serially.

Sent from my mobile device. All spelling errors are it's fault.

On Jan 26, 2014, at 12:12 PM, sshivaji notifications@github.com wrote:

@dch26 python or not, the issue is the same. Can you confirm via assembly or the low level trace that it indeed happens once a second, the compiler could be optimizing away your code. Try putting a lock on every write and a small sleep to ensure that nothing else is happening during a write and see if that solves your problem.

@xpeace reading and writing at the same time could be the problem as well. I will test for that. If the hd44780 uses an LCD busy check, there is definitely an issue at the driver level.

— Reply to this email directly or view it on GitHub.

sshivaji commented 10 years ago

@xpeace Briefly read over the writing to the LCD implementation for both the C and the python versions of pifacecad. A sleep is used instead of checking for the busy bit. The reference guide for hd44780 suggests that the busy bit (bit number 7) can/should be checked before performing a write. Did you attempt a patch already?

Changing the sleep to a busy bit check and wait for ack will probably solve the issue at a lower level.

@tompreston I probably want to patch this soon. Would you agree that this is the right approach?

tompreston commented 10 years ago

Checking for the busy bit looks like the correct approach. Are you able to patch it since I have a few other projects to handle? I can squeeze it in sometime this week, if you can't.

tompreston commented 10 years ago

Scratch that, I've patched it. Can someone test the version in the dev_tp branch and see if that fixes your problem. You'll still have to lock when accessing from concurrent processes/threads but this should fix the single thread screen corruption. I can't test it since my CAD works!

sshivaji commented 10 years ago

Thanks for the quick patch! I personally can't extensively test the C version. I can do that on the python version (pifacecad tree) after applying your logic changes, and will report if it works.

TheBurrito commented 10 years ago

I'll be able to test the patch in 2 days. Will keep in touch.

xpeace commented 10 years ago

In function

void pifacecad_lcd_init(void)  of the forked busy code called from ->  pifacecad_open 

the following function call of the init sequence does not return on my Pi ... 

cur_function_set |= LCD_4BITMODE | LCD_2LINE | LCD_5X8DOTS;
pifacecad_lcd_send_command(LCD_FUNCTIONSET | cur_function_set); // Point of No Return, ...

reverted to previous version ... works "normal"

tompreston commented 10 years ago

@xpeace I'm no longer calling pifacecad_lcd_send_command in the pifacecad_lcd_init function. Are you using the most up to date version? See https://github.com/piface/libpifacecad/blob/dev_tp/src/pifacecad.c#L99+L127

xpeace commented 10 years ago

I dont`t know what happened I got inconsistent code, before. Did retry again now, unsuccessfull.

I am getting deadlocked in the busy loop frequently (if i reset cursor and write a second time to line 0).

I disabled all threads - just plain serial calls- but I already get stuck during my app start (only serial calls here)

pifacecad_lcd_cursor_off(); pifacecad_lcd_set_cursor(0,1);

pifacecad_lcd_send_command // removed busybit wait -> App did not lockup any more but text has been completely messed up again, ... ... This is so annoying.

TheBurrito commented 10 years ago

Branch dev_tp is working great for me so far; this is the longest it has remained stable. I'm going to leave it running overnight and will report back if there end up being any issues.

Thanks for the fix! (I was really worried I might have to cross over to the python world to get some basic stuff set up right off the bat!)

tompreston commented 10 years ago

@xpeace Do you have an example program I can try running on my CAD that will break it? All my tests seem to work for me.

sshivaji commented 10 years ago

The tp_dev branch is working quite well for me too. I tried http://pastebin.com/9MLt26TP with master and every second run or so lead to a garbled display. 20+ runs under tp_dev were not able to garble the display!

Will try to port this fix over to the python this week. More complex than it appears at first with the clock pulse, and register setting especially if you don't do embedded programming.

xpeace commented 10 years ago

It is really hard to manage different threads that write to the LCD, Clear the LCD and Polling the Button states every x milliseconds.at the same time, ...

For thread access control I use one global mutex object ...

    pthread_mutex_t mutexrw; // Global Mutex     
    // init Mutex once at begin of Main() using mutex default attributes 
    pthread_mutex_init(&mutexrw, NULL);
    // 
    pthread_mutex_lock (&mutexrw);
    // writeToLCD || readButtons here
    pthread_mutex_unlock (&mutexrw);
    //
    //  You can reuse the above scheme and 
    //  mutex for all other button read  or 
    //  LCD write operations even from different 
    //  threads 
    // 
    // before App ends destroy Mutex
    pthread_mutex_destroy(&mutexrw);

This seems to work nicely. By the way can I read access the Buttons while writing to the LCD ?

I managed to get the PI completely locked up by calling the CAD functions, even no more remote access via ssh was possible (but I think this was before i was shure of having all Mutexes in place)

For the latest branch - I needed to comment out one of the busy bit checks - then the busycode worked reliable for me as well.

    // I got stuck here way too frequent (everytime first line used 16+ digits)
    void pifacecad_lcd_send_command(uint8_t command)
    {
        // while(is_busy());  // wait until not busy
        pifacecad_lcd_set_rs(0);
        pifacecad_lcd_send_byte(command);
        sleep_ns(DELAY_SETTLE_NS);
    }

setCursor to new line fails when I do not remove that check (will loop in busy check eternally)

-> Also See the other Issue: https://github.com/piface/libpifacecad/issues/2

16 Digits and Linebreak with Pifacecad cmd program and tp_branch and I get stuck on busy loop at the newline (setcursor code) position (tho I thought internal memory size is valid for 40 chars per line, one could decrease the 80 bytes in the Header to 40 for testing , ...)

Is it normal that the backlight does flicker when executing eg. an LCD clear command or closing the connection with backlight still on ? I`m not sure if this is a kind of feature or Network / Audio related, ...

xpeace commented 10 years ago

Multiplying settle_ns by 100 seem to make it relatively stable for me so far.

My Configuration: latest debian wheezy for Pi, all updates, Pi Firmware 02.02.2014 Toolchain: Codeguru Windows Cross Compiler

without multiplying the settle_ns I still get corrupt ascii displayed

dch26 commented 10 years ago

i took the dev_tp code and compiled it. it ran successfully for just a couple of cycles before getting stuck forever in a loop while the new "is_busy" ALWAYS returned a 1. then realised that xpeace had same issue. modified C code in a similar way. also, the 40000 didnt work well so i had to move to 4000000 for the settle value. i too saw other looping issues until i ensured that text being sent to LCD was 16 chars or less per line. i have removed all artifical pauses from my code and am now hammering the LCD for read and write as fast as i can. hasnt skipped a beat, crashed or given me a garbled screen as yet. looking good! thx to all for code changes and sharing comments & experiences. fyi - i am using perl wrappers around the library and raspbian

tompreston commented 10 years ago

Sorry about the long delay! I've added support for interrupts and hopefully fixed the bug in is_busy. Can someone pull dev_tp and test it, please?

JohnWulff commented 10 years ago

I am using the libpifacecad library in my project on a Raspberry Pi with a PiFaceCAD mounted on a PiRack with 3 other PiFace boards using the latest Raspbian OS. All digital I/O is running perfectly and not interfering with the PiFaceCAD display.

I am using the following calls from pifacecad.c to display new text on the LCD display: pifacecad_lcd_clear(); // clear display first pifacecad_lcd_write(texts[val & 0x07]); // write one of 8 texts Doing this resulted in the display text being garbled occasionally, as reported in several submissions. cadclean cadgarbled I found conclusively that the problem is in pifacecad_lcd_clear(). Putting a sleep_ns(1520000); between these two calls fixed the problem. I am guessing that the "Clear display" command of the HITACHI HD44780U takes a lot longer to execute than the 37 us of the other commands (no execution time is actually specified), because this command clears the whole display internally. The next command in the HITACHI HD44780U spec (page 24) is "Return home", whose execution time is specified at 1.52 ms. I did not see any misbehavior with this command and no extra delay. I suspect that the 1.52 ms is a misprint in the HITACHI spec and should have been in the "Clear display" line.

I found another error, which proves to me that the "Clear display" command is busy for a considerable time:

pifacecad_lcd_clear();       // clear display first
pifacecad_lcd_display_off(); //or display_on (you would not normally do this)

The display_off or display_on never executed unless there was a delay above 100 us (above 750 us for reliable operation) between the two calls.

I wrote the test program showTimingError.c (will upload this if I can), which compiles and links with libpifacecad.a like test.c. This reproduces the errors I found more consistently. showTimingError is called with a delay parameter in microseconds.

showTimingError 0          # very occasional corruption; display_off does not work
showTimingError 500        # nearly all displays are corrupted
showTimingError 750        # very occasional corruption; display_off mostly works
showTimingError 1520       # no errors found with this setting ever 
JohnWulff commented 10 years ago

I have just pulled dev_tp and tested it. The "while(is_busy()); // wait until not busy" works - no more corruptions with "showTimingError" with any delay setting between 0 us and 1520 us (see previous post today). Also "pifacecad_lcd_display_off();" works with 0 delay after "pifacecad_lcd_clear();" which never worked before.

I measured the execution time of the new routine "is_busy()" with getimeofday(). This showed that "is_busy()" actually takes 860 us +- 30 us to execute. This slows down the transfer of data in "pifacecad_lcd_send_data()" significantly. The only instance where "while(is_busy());" looped twice was after the "pifacecad_lcd_clear()" command, which confirms that this command actually executes in somewhere between 1720 us and 2580 us, which is slightly more than I measured with "showTimingError" above.

Because of the slow execution time of "is_busy()" i feel it would be better to patch "pifacecad_lcd_clear(): as follows

void pifacecad_lcd_clear(void)
{
    pifacecad_lcd_send_command(LCD_CLEARDISPLAY);
    sleep_ns(2600000L); // additional delay to bridge execution time of LCD_CLEARDISPLAY
    cur_address = 0;
 }

"pifacecad_lcd_home() could be patched the same way to satisfy the HITACHI spec for this command. All other commands only take 37 us according to the HITACHI spec, which is taken care of by the 40 us delay after every "pifacecad_lcd_send_byte()" call in pifacecad.c in the original and new implementation. Therefore no other busy waits are necessary.

More tests will confirm whether this is safe.

JohnWulff commented 10 years ago

I have now managed to create a "gist" https://gist.github.com/JohnWulff/29f216a7d79d09807712 containing the two files mentioned in the previous 2 posts.

showTimingError.c is the 2nd file in the gist (although I entered it first) It shows consistent corruptions if called with delays between 100 and 750 us when linked with the master branch of libpifacecad.

When linked with the dev_tp branch of libpifacecad it shows no corruptions. The 1st file in the gist is pifacecad_dev_tp_measure_busy.c, which is a patched version of src/pifacecad.c and should replace that file temporarily to build libpifacecad.a. When exercised with showTimingError linked with this version of libpifacecad.a (and -lm the math library) it shows execution times of is_busy() and how many times it repeats in the while loop (which it does only after libpiface_lcd_clear() calls like so:

texts[5] "texts[5]"; clear + 0 ns # 0x01 is the 'Clear display command' 0.001,671: before pifacecad_lcd_send_command(0x01) 0.000,864: before pifacecad_lcd_send_command(0x80) 883 864 0.000,952: before pifacecad_lcd_send_data(0x74) 0.000,885: before pifacecad_lcd_send_data(0x65) 0.000,907: before pifacecad_lcd_send_data(0x78) 0.000,853: before pifacecad_lcd_send_data(0x74) 0.000,842: before pifacecad_lcd_send_data(0x73) 0.000,885: before pifacecad_lcd_send_data(0x5b) 0.000,852: before pifacecad_lcd_send_data(0x35) 0.000,842: before pifacecad_lcd_send_data(0x5d) texts[5] "texts[5]"; clear + 0 ns 0.001,145: before pifacecad_lcd_send_command(0x01) 0.000,846: before pifacecad_lcd_send_command(0x80) 881 849 0.000,855: before pifacecad_lcd_send_data(0x74) 0.000,835: before pifacecad_lcd_send_data(0x65)

This also shows that there is a 870 us busy wait after every character transferred to the display, which should be avoided.

tompreston commented 10 years ago

I managed to run your tests last week and I can confirm that the problem exists as you describe. Unfortunately, with constant deadlines and being between houses at the moment I just don't have the time to spare to patch in the fix (which also has to be included into the LCDproc patch) and get in touch with SparkFun about the error in the datasheet.

Since the delay's are constant, I think you're right in suggesting that we can just program them in rather than waiting for the busy line.

I'd be more than happy to merge a pull-request into my dev branch, if you/anyone feels like making the changes yourself. If not, the changes will have to wait until I get a spare moment.

I've not forgotten about this, I just can't prioritise it at the moment!

JohnWulff commented 10 years ago

pull-request from https://github.com/JohnWulff/libpifacecad/ to implement the above suggestions

add 2.6 ms delay to piface_lcd_clear() and piface_lcd_home()

change SEQOP_ON to SEQOP_OFF in piface_open_noinit()

These values set bit 5 of the IOCON register in the MCP23S17 I/O Expander. Setting this bit to 0 (SEQOP_ON) enables address pointer increments in the MCP23S17. I do not think this is ever used (especially with BANK_OFF). Every command to the MCP23S17 sets a new address. The auto-incrementing of text byte transfers in the HD44780U is handled somewhere else.

JohnWulff commented 10 years ago

I wrote the following for the "man page" of my application program iCpiFace, which handles direct input/output for the "immediate C" system from up to 8 PiFace/PiFaceCAD units connected to a Raspberry Pi either plugged in directly or via one or more PiRacks. This helped me to clarify the action of the software on the many different components, which have to be considered.

TECHNICAL BACKGROUND The I/O connections on the PiFace board are controlled from the Raspberry Pi via four different paths:

    1) the kernel SPI system can write and read to and from the MCP23S17
       16-Bit I/O Expander chip on the Piface. There are two SPI channels
       on the Raspberry Pi:
           /dev/spidev0.0 - which enables CS CE0 when SPI writes or reads.
           /dev/spidev0.1 - which enables CS CE1 when SPI writes or reads.
       The MCP23S17 is a slave SPI device. The slave address contains four
       fixed bits and three user-defined hardware address bits pins A2, A1
       and A0 (if enabled via IOCON.HAEN - A2 is not used in the PiFace).
       The Read/Write bit fills out the control byte. Jumpers JP1 and
       JP2 select A0 and A1 on each PiFace. Jumpers JP1 - JP8 select
       CE0 or CE1 for every PiFace on a PiRack. Together this makes for
       8 possible PiFace addresses 0 - 7. The PiFaceCAD board has fixed
       wiring with CE1 and address 0, making it combined address 4 (unless
       CE0 is swapped on the PiRack - which you wouldn't do - would you!).

    2) The MCP23S17 has a number of 8 bit registers which can be written
       and read via the above SPI channels. The most important of these
       for the PiFace driver are:
           IOCON   - which sets the configuration of the MCP23S17.
           IODIRA  - set to 0x00, which makes all 8 port A pins outputs.
           IODIRB  - set to 0xff, which makes all 8 port B pins inputs.
           GPIOA   - which sets the 8 output pins when written to.
           GPIOB   - which returns the 8 input pins when read.
           GPINTENB- set to 0xff, a change on any port B pin activates INTB.
           INTFB   - set for any pin which changed and caused an interrupt.
           INTCAPB - which returns the 8 input pins at interrupt time.
       The INTB output, which signals a change on any of the input bits,
       is set to active-low in an open-drain configuration to allow for more
       than one PiFace. INTB is connected to pin 22 (GPIO25) going to
       the Raspberry Pi.

       Reading either GPIOB or INTCAPB reset the source of the input
       interrupt.  INTCAPB only supplies the state at interrupt time,
       which does not necessarily reflect the state of the input when
       executing the interrupt handler. Using INTCAPB sometimes led to
       lost input changes. Therefore I do not use it.

       NOTE: only one instance of iCpiFace may be run and all PiFaces and
       an optional PiFaceCAD must be controlled by this one instance. If
       two instances were running, the common interrupts would clash.

    3) The Raspberry Pi brings out 17 GPIO signals, 5 of which double up to
       do the SPI interface, 2 for a UART, leaving 10 for general purpose
       input/output (there are 4 more on a 2nd connector, which is not fitted
       normally). The Linux "sysfs" can access the value of these GPIO pins
       from user space and more importantly can generate interrupts from them.
       For details see:
       http://www.auctoris.co.uk/2012/07/19/gpio-with-sysfs-on-a-raspberry-pi/

       GPIO25 (the interrupt from the PiFace inputs) is exported with
       "sysfs" in the PiFace driver and set to interrupt on its falling
       edge. The interrupt is out-of-band, so if select(2) is used,
       the third exception file descriptor set must be used. select is
       generally used in the iC system, because it handles timeouts
       correctly when interrupted.  Alternatively if poll(2) is used
       by defining POLL, it must be polled with POLLPRI rather than
       with POLLIN.

       If GPIO25 has already been exported by another program or by
       another instance of iCpiFace the program exits with an error
       message, since GPIO25 cannot be used by more than one program
       simultaneously.  Some programs (PiFace Digital Emulator) do not
       unexport GPIO25 when they close. The -f command line option can
       be used to force use of GPIO25 if you are sure there is no running
       program actually using GPIO25.

    4) To allow several PiFace units and possibly a PiFaceCAD to run
       simultaneously on a PiRack, the INTB/GPIO25 line requires a pullup
       resistor, so the individual INTB outputs from each MCP23S17 can
       signal their interrupts via open-drain outputs. There is no pullup
       resistor on the PiFace, PiFaceCAD or the PiRack. But each GPIO
       pin on the Raspberry Pi can be configured to have a 60 Kohm pull-up
       or pull-down resistor. Unfortunately there is no way to control
       this with the "sysfs". To do this the BCM2835 direct memory access
       interface is used. For details see:
           http://www.airspayce.com/mikem/bcm2835/index.html
       This package does not support interrupts, so only the setting of
       the pullup resistor on INTB/GPIO25 is done with this package.

For the PiFaceCad there are two additional paths from the Raspberry Pi to consider:

    5) The PiFaceCAD uses GPIOA for 8 bits of input with INTA connected
       to pin 22 (GPIO25) for interrupts and GPIOB for output to a
       HD44780U Dot Matrix Liquid Crystal Display Controller. The C
       software provided by Thomas Preston was used for the display.
           https://github.com/piface/pifacecad

       The commands pifacecad_lcd_clear() and pifacecad_lcd_home() require
       a delay of 2.6 ms to bridge the execution time used internally for
       clearing the display buffer.  For the first command no execution
       time is specified in the HITACHI specification - the second one
       is specified at 1.52 ms. Actual measurement using the Busy Flag
       determined that the execution time if pifacecad_lcd_clear()
       is between 1.75 and 2.6 ms. Without a delay of 2.6 ms after
       this command a following pifacecad_lcd_write() would frequently
       garble the text. A pifacecad_lcd_display_off() or _on() does not
       execute at all unless there is a delay of 2.6 ms after a prior
       piface_lcd_clear(). All the other commands are followed by a
       delay of 40 us, which is in line with the HITACHI spec.

    6) The PiFaceCad also has a LIRC output on pin 16 (GPIO23). This
       output is high if a PiFaceCad is present - low otherwise.  It is
       only used in iCpiFace to distinguish between a PiFaceCAD or
       a plain PiFace at address 4 during the initialisation scan.
       The LIRC signal is best handled by independent LIRC software
       available in the Linux Kernel.
           http://piface.github.io/pifacecad/lirc.html
           #setting-up-the-infrared-receiver%3E%60_%20yourself
tompreston commented 10 years ago

I've merged your pull request. This bug should now be closed! Thank you John and everyone else for all your input.