|Fig.1: IOStream class hierarchy|
|Fig.2: IOStream::Device interface|
Number conversion (binary to textual representation) is performed by the IOStream class which delegates the actual output to the attached IOStream::Device. The IOStream and the null device code is reused by all devices.
The LCD::Device class extends the IOStream::Device class with additional methods typical for LCD. Most of these are pure abstract and must be defined by the device driver.
|Fig.3: LCD::Device Interface|
There are basically two major types of LCD devices; pixel and character based. Some pixel based devices restrict drawing of pixels to a vertical byte, 8 pixels at a time, but allow horizontal cursor handling on pixel level. Examples of this type of LCD devices are PCD8544 and ST7565. HD44780 aka 1602/1604/2004 are typical character based devices where the characters codes are written to the device and not pixels.
|Fig. 4: HD44780 Device Driver collaboration diagram|
|Fig. 5: HD44780::IO class hierarchy|
The HD44780 device driver requires 2.5 Kbyte program memory for parallel port, 3.5 Kbyte with I2C expander. The PCD8544 device driver with font (System7X5) requires 3.5 Kbyte. And last, ST7565, 4 Kbyte including font. All devices drivers include IOStream::Device, LCD::Device and default virtual methods.
|Fig. 6: Benchmarking the LCD device drivers|
- Arduino Mega, 20x4 character, HD44780 with MJKDZ I2C IO expander.
- Arduino Nano, 128x64 pixel, ST7565, software bit serial, OutputPin::write().
- Arduino Nano, 84x48 pixel, PCD8544, software bit serial.
- Arduino Uno, 16x2 character, HD44780, 4-bit direct port access, D4..D7.
- Clear the display, lcd.display_clear().
- Fill the display with characters, lcd.putchar(), WIDTH * HEIGHT number of characters per iteration and lcd.set_cursor() per line.
- Write a string, lcd.puts(), 2x16 characters per iteration, and lcd.set_cursor() per iteration.
- Write a string from program memory, lcd.puts_P(), as previous.
- Write an integer in decimal format, lcd.set_cursor() and number print per iteration (trace << num).
- Write an integer in binary format, as previous (trace << bin << num).
|Tab. 1: Benchmark operations per second|
The Cosa I2C IO expander handler is further optimized to achieve higher performance by reducing the transmission overhead. Writing a command or data byte to the I2C IO expander is transmitted as a sequence of five bytes instead of four X two byte transmissions (address and port data, total eight bytes). This reduces the transmission time with nearly 40%. This method can be applied further to reduce string output (see puts() and compare with puts_P() in tab. 1). The I2C@100khz improvement is over 1.7X faster compared to that reported by New LiquidCrystal Library benchmarks (31 fps). With I2C@400khz the improvement is over 4.6X faster.
|Fig.7: ATtiny84 acting as an I2C LCD slave device. Running 4-bit parallel LCD device driver|
With the new USI based TWI master device driver support even an ATtiny85 can be used with an LCD.
|Fig.8: ATtiny85 connected to LCD with I2C IO expander|
For further details see the Cosa on-line documentation and the LCD example sketches.