Cosa: An Object-Oriented Platform for Arduino programming

A new Cosa blog post is available. It presents the Cosa LCD device drivers and abstraction.

Cheers!

Nice progress again mr Kowalski :stuck_out_tongue:

kowalski:

  1. Reducing the need to send rom address when only a single device is connected or issue DS18B20 convert request to multiple devices at the same time (broadcast).
  // Broadcast convert request to connected devices; 12-bit conversion delay and parasite power

DS18B20::convert_request(&owi, 12, true);

// Read back results
 indoors.read_scratchpad();
 outdoors.read_scratchpad();
 basement.read_scratchpad();

I haven't used DS18B20's before, but if you are not using rom addresses, how can you tell which sensor is which (ie indoors, outdoors, basement) ??

And then for something else.
I discovered that what I would like to 'invent' for addressing I/O pins was already build by someone else, YOU ]:smiley:

So now I'm exploring your Pin design and have some questions:

  • The base class is the Pin
  • Then there is an InputPin and an OutputPin, but also an AnalogPin. Why is this AnalogPin not an InputPin?
  • The AnalogPin does have an on_change() method, but the digital InputPin doesn't, why?

And then some for the interrupt handling & use of those interrupts:

  • The External and PinChange Interrupts are modelled as an InputPin. No problem with that, but why the difference between External and PinChange interrupts?
  • The reason for the above one is this: I have boards that sometimes have the INT pin wired to a hardware int, and sometimes to another pin (ie pinchange). I would like my classes just to respond to an interrupt, regardless of the fact if it is hardware or pinchange...

And in line with the above:
You seem to make a difference between SPI/SoftSPI, TWI/SoftTWI. That is logical, but some of the devices seem to be hardwired to the SPI driver if I'm not mistaken, ie you can't just have the same sensor/device either (or both) talk over SoftSPI and SPI?? Or is it possible to pass the actual SPI device to the sensor/device?

Tons of questions! See if I can answer them.

MarsWarrior:
I haven't used DS18B20's before, but if you are not using rom addresses, how can you tell which sensor is which (ie indoors, outdoors, basement) ??

The Cosa OWI interface allows several ways to handle the rom address but I guess that you are concerned with the rom address not being a parameter. The Cosa OWI has two parts; the OWI bus and the OWI device driver. The OWI bus knows about communication while the OWI device driver is a device on the bus. It holds its rom address. It can obtain the address as a parameter to the instance (typically from EEMEM) or by connecting to device using the search command. In this case an index is used. To use this you need to order the devices according to their rom addresses on the wire.

MarsWarrior:
So now I'm exploring your Pin design and have some questions:

  • The base class is the Pin
  • Then there is an InputPin and an OutputPin, but also an AnalogPin. Why is this AnalogPin not an InputPin?
  • The AnalogPin does have an on_change() method, but the digital InputPin doesn't, why?

Hum, Pin is actually an input pin to avoid multiple inheritance. So AnalogPin can be used for digital input. And the Board pin definitions for analog pins is accepted for both InputPin and OutputPin.

The on_change() method has to do with the ISR-Event Handler and is not an observer pattern. If that is what you are asking for? There is an analog conversion completed interrupt. All pins cannot generate pin change interrupts (as I understand the hardware). And there are only a very limited number of pins for external interrupts.

The most important aspect of the Pin class hierarchy is actually performance and abstraction. The Wiring function library is a very slow design and implementation. And not very object-oriented. It is also very difficult to scale to larger designs. There is a lot of calculations and lookups that are done for every digitalRead/Write that are unnecessary. This can be cached on initialization or even better at compile time. There are a few attempts to use templates instead of instances for modeling the hardware resources. Basically code generating each pin instance. This give even higher performance.

I have used some of these techniques for the Cosa Queue, IOBuffer and Offscreen Canvas. Great performance improvements :wink:

MarsWarrior:
And then some for the interrupt handling & use of those interrupts:

  • The External and PinChange Interrupts are modelled as an InputPin. No problem with that, but why the difference between External and PinChange interrupts?
  • The reason for the above one is this: I have boards that sometimes have the INT pin wired to a hardware int, and sometimes to another pin (ie pinchange). I would like my classes just to respond to an interrupt, regardless of the fact if it is hardware or pinchange...

The difference is in the hardware and how pin changes are detected in for instance power down. The next item I regard to be a configuration problem and in Cosa I see that as how you instantiate objects and inherit from classes. Actually from the application perspective it is an Interrupt Handler which is the common super class for both interrupt types (external/pin change). I see that as a modeling aspect. There are several approaches to this.

MarsWarrior:
And in line with the above:
You seem to make a difference between SPI/SoftSPI, TWI/SoftTWI. That is logical, but some of the devices seem to be hardwired to the SPI driver if I'm not mistaken, ie you can't just have the same sensor/device either (or both) talk over SoftSPI and SPI?? Or is it possible to pass the actual SPI device to the sensor/device?

SPI and TWI is work in progress as I would like to allow multiple SPI/TWI bus managers and both software and hardware at the same time. Right now these are singletons (global variable) and may be redefined depending on the application. Drivers only know about the "symbol". This is up to debate as there are other ways to model this relationship. Also allowing both software and hardware version would be nice given a common interface. SPI and TWI do not follow the delegation pattern that I have used in much of the design. They might evolve in this direction :wink: it would give a more flexible design.
BW, Cosa does not include a Soft TWI right now and the Soft SPI is MOSI only. Plenty of work to do in that area. But still the SPI and TWI handling with iovec is a quantum leap forward compare to what is in the Arduino IDE box. Writing drivers becomes so much easier :wink:

Cheers!

kowalski:
The Cosa OWI interface allows several ways to handle the rom address but I guess that you are concerned with the rom address not being a parameter. The Cosa OWI has two parts; the OWI bus and the OWI device driver. The OWI bus knows about communication while the OWI device driver is a device on the bus. It holds its rom address. It can obtain the address as a parameter to the instance (typically from EEMEM) or by connecting to device using the search command. In this case an index is used. To use this you need to order the devices according to their rom addresses on the wire.

Ok, clear! If I check the address on forehand, and connect them in that order everything will be allright...

The on_change() method has to do with the ISR-Event Handler and is not an observer pattern. If that is what you are asking for? There is an analog conversion completed interrupt. All pins cannot generate pin change interrupts (as I understand the hardware). And there are only a very limited number of pins for external interrupts.

Aha, now I understand. I was just looking at similarities and dissimilarities in the classes while trying to understand how they are setup.

The difference is in the hardware and how pin changes are detected in for instance power down. The next item I regard to be a configuration problem and in Cosa I see that as how you instantiate objects and inherit from classes. Actually from the application perspective it is an Interrupt Handler which is the common super class for both interrupt types (external/pin change). I see that as a modeling aspect. There are several approaches to this.

I understand the difference now in hardware and pin change interrupts. I have got cases though where the power down behaviour is not important: I just want to register on an interrupt and it is not important if it is hardware or pin change. But you are right about the interrupt handler: class is called by on_interrupt().

SPI and TWI is work in progress as I would like to allow multiple SPI/TWI bus managers and both software and hardware at the same time. Right now these are singletons (global variable) and may be redefined depending on the application. Drivers only know about the "symbol". This is up to debate as there are other ways to model this relationship. Also allowing both software and hardware version would be nice given a common interface. SPI and TWI do not follow the delegation pattern that I have used in much of the design. They might evolve in this direction :wink: it would give a more flexible design.
BW, Cosa does not include a Soft TWI right now and the Soft SPI is MOSI only. Plenty of work to do in that area. But still the SPI and TWI handling with iovec is a quantum leap forward compare to what is in the Arduino IDE box. Writing drivers becomes so much easier :wink:

Didn't realize that it was still a work in progress, but it explains why I couldn't find some of the Soft parts.
I just thought I didn't understand your code (I'm not a C/C++ expert!).
As I'm using some RTOS, the separation between driver & device is very important. More even if they share the same bus: in that case I need synchronization to allow only one of the devices to be active on the bus. And a separate 'driver' (or device, or bus, depending on how you name things) does make this very, very easy.

Is iovec btw also possible for the 'soft' versions of SPI/TWI, as it relies on interrupts??

And as a side effect of your answers I looked into design patterns and found out that I'm using them without knowing :astonished:

I tried the blink program on 1.0.5. Compiles and works great. I tried the same in ECLIPSE but that did not go quite right yet.

I get these errors:

D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:59: error: expected identifier before '(' token
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:102: error: expected identifier before '(' token
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:175: error: expected identifier before '(' token
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:236: error: expected identifier before '(' token
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh: In member function 'virtual int IOStream::Filter::fputc(char, int*)':
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:177: error: invalid conversion from 'int' to 'int*'
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:177: error:   initializing argument 2 of 'virtual int IOStream::Device::fputc(char, int*)'
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh: In member function 'virtual int IOStream::Filter::fgetc(int*)':
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:238: error: invalid conversion from 'int' to 'int*'
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:238: error:   initializing argument 1 of 'virtual int IOStream::Device::fgetc(int*)'
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh: In member function 'void IOStream::print(char)':
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:380: error: no matching function for call to 'IOStream::Device::fputc(char&, __file*&)'
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:59: note: candidates are: virtual int IOStream::Device::fputc(char, int*)
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh: In member function 'void IOStream::println()':
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:408: error: no matching function for call to 'IOStream::Device::fputc(char, __file*&)'
D:\Arduino\hardware\arduino\cores\arduino/Cosa/IOStream.hh:59: note: candidates are: virtual int IOStream::Device::fputc(char, int*)

Any ideas?

Hi nicoverduin. My guess is that the macro putchar/getchar from stdio.h is included in the ECLIPSE/AVR environment. I have added two undef in IOStream.hh:

#undef putchar
#undef getchar

This has to be repeated in sketches that include IOStream as the Arduino preprocessor is adding some code.

I have not yet used the Arduino ECLIPSE environment. Would be great to have that working. Thanks for trying it out.

Cheers!

BW: After grep-ing through the Arduino core stdio.h is included there in several files. It must be the Arduino pre-processor that includes it:

HardwareSerial.cpp:#include <stdio.h>
Print.cpp:#include <stdio.h>
Print.h:#include <stdio.h> // for size_t
WInterrupts.c:#include <stdio.h>
wiring_private.h:#include <stdio.h>

Just put the 2 undefs in and it compiles like charm. Lot warnings though in the Arduino compile
about uninitialized variables in program code etc.
But the program works :slight_smile:
I'll try some more complicated programs later this week. Not now. Too nice weather het in Holland :slight_smile:

A new Cosa blog post is available. It describes how to use the event-driven keypad handler for the LCD Keypad Shield.

Cheers!

See my latest post on weird problems while trying to compile Cosa with Arduino 1.05 and 1.52...

Hi MarsWarrior.

Something weird is happening.
I'm trying out Code::Blocks, which gives me alot of troubles (compiler errors, not finding header files etc.).

So I tried the Cosa examples: don't build either.
Then I tried the Arduino IDE 1.05 with Cosa examples: Don't build either (!!!!)

If I read this correctly, you are asking for support with an alternative IDE, Code::Blocks? I haven't used that IDE so it is difficult for me to give any specific advice more than google and read the installation guide. Seems an interesting IDE though.

http://forum.arduino.cc/index.php?topic=145397.0

The problems you are having with Arduino-1.0.5 I guess are related to that you have not installed Cosa for that version? The compiler error messages indicate that the compiler could not file the include files for Cosa in the include path.

Cheers!

Just read the PM, and see that I mixed up my question/problem.

Just forget me mentioning Code::Blocks :*, not asking you to support any other IDE than the mighty Arduino IDE XD

This is what I did to reproduce the problem:

  • I re-installed Arduino 1.05 and 1.52, just to be save.
  • Then I downloaded the latest Cosa library.
  • I tried to add the Cosa library using the Arduino IDE (Add Library), no luck (java.io.FileNotFoundException: C:\Users\Marco\AppData\Local\Temp\arduino_962622\Cosa10898\Cosa\Cosa\BCD.h (Het systeem kan het opgegeven pad niet vinden)
    )
    I have absolutely no idea what the problem is. Never had this with other libraries...
  • Then I copied the Cosa library manually to my home folder/Arduino/libraries and tried to compile one of the examples: no luck, hh files not found
  • Then I copied the Cosa library manually to the Arduino libraries folder (C:/Program files (x86)/...), same problem, won't compile

Note that the Cosa examples do show up in the Arduino Examples menu and in the sketches / libraries menu! So the Arduino IDE does see Cosa!!

But while trying to compile the CosaBenchMarkPins.ino (or any other example for that matter):

CosaBenchmarkPins.ino:33:24: error: Cosa/Pins.hh: No such file or directory
CosaBenchmarkPins.ino:34:23: error: Cosa/RTC.hh: No such file or directory
CosaBenchmarkPins.ino:35:25: error: Cosa/Memory.h: No such file or directory
CosaBenchmarkPins.ino:36:28: error: Cosa/Watchdog.hh: No such file or directory
CosaBenchmarkPins.ino:37:25: error: Cosa/Trace.hh: No such file or directory
CosaBenchmarkPins.ino:38:40: error: Cosa/IOStream/Driver/UART.hh: No such file or directory
CosaBenchmarkPins:40: error: 'InputPin' does not name a type
CosaBenchmarkPins:41: error: 'OutputPin' does not name a type
CosaBenchmarkPins:42: error: 'OutputPin' does not name a type
CosaBenchmarkPins:43: error: 'OutputPin' does not name a type
CosaBenchmarkPins:44: error: 'AnalogPin' does not name a type
CosaBenchmarkPins.ino: In function 'void setup()':
CosaBenchmarkPins:53: error: 'uart' was not declared in this scope
CosaBenchmarkPins:54: error: 'trace' was not declared in this scope

When I however use #include <> instead of #include "", the No Such file or directory errors disappear, but still the rest of the errors keep coming...

I'm out of ideas on what is wrong...

Hope you now understand what I did, and what my problem is!

Hi MarsWarrior.

You really don't like reading documentation ;-). I was under the impression that you had already installed Cosa previously and was now attempting to use it with Code::Blocks and a new version of Arduino. I understand now that this assumption was wrong. Sorry about that.

Cosa is not an Arduino library. The Arduino preprocessor cannot handle sub-directories within a library. I like to structure things so the include is "Cosa/XXX.hh" for header file and then there is even more structure like "Cosa/LCD.hh" and "Cosa/LCD/Driver/HD44780.hh".

Now how can we get the Arduino preprocessor (compiler include path) to recognize this? We put the Cosa directory into the arduino header/source directory! So the installation procedure is:

  1. Download Cosa as a zip file.
  2. Unzip in your libraries folder in your sketches folder.
  3. Move the Cosa (source/header) folder to the Arduino source/header folder. For 1.0.5 that is the folder "arduino-1.0.5/hardware/arduino/cores/arduino".

You havn't done step 3 yet. That's all.

Cheers!

Links to the installation procedure:

  1. Cosa: An Object-Oriented Platform for Arduino programming - Libraries - Arduino Forum
  2. Cosa: Installing Cosa
  3. GitHub - mikaelpatel/Cosa: An Object-Oriented Platform for Arduino/AVR (See section Install)

A small remark to that setup - when not working with Cosa the build of a sketch takes ages as it builds all the Cosa stuff as well. How to switch it off ? (without removing the Cosa folder) :slight_smile:

pito:
A small remark to that setup - when not working with Cosa the build of a sketch takes ages as it builds all the Cosa stuff as well. How to switch it off ? (without removing the Cosa folder) :slight_smile:

I would suggest using a separate Arduino installation for the Cosa stuff until the Arduino IDE learns how to use library files (archives). I believe this is the root cause to the build problem. It would be even better if Arduino could have library files with directory structure as Java jar-files as this would avoid an old C/C++ archive problem. This would require some new AVR GNU binutil stuff.

Cheers!

kowalski:
Hi MarsWarrior.

You really don't like reading documentation ;-). I was under the impression that you had already installed Cosa previously and was now attempting to use it with Code::Blocks and a new version of Arduino. I understand now that this assumption was wrong. Sorry about that.

Well, yes I don't like reading documentation as I am a visual thinker. Still I did read your blog. Started with the first application, but managed to skip the whole installation blog :smiley: I did however compile Cosa a few months back on another PC, but didn't know the special install anymore as you have noticed...

Cosa is not an Arduino library. The Arduino preprocessor cannot handle sub-directories within a library. I like to structure things so the include is "Cosa/XXX.hh" for header file and then there is even more structure like "Cosa/LCD.hh" and "Cosa/LCD/Driver/HD44780.hh".

Now how can we get the Arduino preprocessor (compiler include path) to recognize this? We put the Cosa directory into the arduino header/source directory! So the installation procedure is:

  1. Download Cosa as a zip file.
  2. Unzip in your libraries folder in your sketches folder.
  3. Move the Cosa (source/header) folder to the Arduino source/header folder. For 1.0.5 that is the folder "arduino-1.0.5/hardware/arduino/cores/arduino".

You havn't done step 3 yet. That's all.

Thanx for the explanation. During my search I came accross some problems about subdirectories & libraries and the fact that this was filed as a bug, accepted, but then again rejected and considered as an Arduino feature! On the other side I use multiple libraries for my own projects (I was told to do so), and guess not able to use subdirectories is a reason, but I never realized this...

I wonder if Code::Blocks suffers from the same problem, as I'm using the Arduino compatible version, but haven't had time to check this.
Code::Blocks btw caches already compiled files, so should be a lot faster, certainly if Cosa is compiled for each sketch, as pito mentioned.

Update: Result from compiling CosaPins.ino in Code::Blocks with the Cosa library in the Arduino folder:

-------------- Build: Arduino Uno in CosaPins (compiler: GNU AVR GCC Compiler)---------------

Compiling: CosaPins.ino
Linking console executable: build\CosaPins_uno.elf
CosaPins.ino: In function 'void setup()':
CosaPins.ino:83: warning: only initialized variables can be placed into program memory area
CosaPins.ino:86: warning: only initialized variables can be placed into program memory area
CosaPins.ino:89: warning: only initialized variables can be placed into program memory area
CosaPins.ino:90: warning: only initialized variables can be placed into program memory area
CosaPins.ino:91: warning: only initialized variables can be placed into program memory area
CosaPins.ino:92: warning: only initialized variables can be placed into program memory area
CosaPins.ino:93: warning: only initialized variables can be placed into program memory area
CosaPins.ino:94: warning: only initialized variables can be placed into program memory area
CosaPins.ino:95: warning: only initialized variables can be placed into program memory area
CosaPins.ino:96: warning: only initialized variables can be placed into program memory area
CosaPins.ino:97: warning: only initialized variables can be placed into program memory area
CosaPins.ino:98: warning: only initialized variables can be placed into program memory area
CosaPins.ino:99: warning: only initialized variables can be placed into program memory area
CosaPins.ino:100: warning: only initialized variables can be placed into program memory area
CosaPins.ino:113: warning: only initialized variables can be placed into program memory area
CosaPins.ino:115: warning: only initialized variables can be placed into program memory area
CosaPins.ino:117: warning: only initialized variables can be placed into program memory area
CosaPins.ino:119: warning: only initialized variables can be placed into program memory area
CosaPins.ino: In function 'void loop()':
CosaPins.ino:131: warning: only initialized variables can be placed into program memory area
CosaPins.ino:134: warning: only initialized variables can be placed into program memory area
CosaPins.ino:138: warning: only initialized variables can be placed into program memory area
CosaPins.ino:143: warning: only initialized variables can be placed into program memory area
CosaPins.ino:146: warning: only initialized variables can be placed into program memory area
CosaPins.ino:147: warning: only initialized variables can be placed into program memory area
CosaPins.ino:148: warning: only initialized variables can be placed into program memory area
CosaPins.ino:149: warning: only initialized variables can be placed into program memory area
build\CosaPins.o: In function `global constructors keyed to _Z11free_memoryv':
CosaPins.ino:(.text._GLOBAL__I__Z11free_memoryv+0x8): undefined reference to `ExternalInterrupt::ExternalInterrupt(Board::ExternalInterruptPin, ExternalInterrupt::Mode)'
CosaPins.ino:(.text._GLOBAL__I__Z11free_memoryv+0xec): undefined reference to `PWMPin::set(unsigned char)'
CosaPins.ino:(.text._GLOBAL__I__Z11free_memoryv+0x120): undefined reference to `vtable for AnalogPin'
CosaPins.ino:(.text._GLOBAL__I__Z11free_memoryv+0x122): undefined reference to `vtable for AnalogPin'
C:\Users\xyz\My Documents\CosaPins\build\/core_uno_16.a(main.cpp.o): In function `main':
main.cpp:(.text.main+0x8): undefined reference to `setup'
main.cpp:(.text.main+0x10): undefined reference to `loop'
Process terminated with status 1 (0 minutes, 4 seconds)
6 errors, 28 warnings (0 minutes, 4 seconds)

Hmmm. Almost there, but not yet :slight_smile: Never seen such errors, but I already discovered that Code::Blocks seems to be more strict than the Arduino IDE.
I don't have an Arduino IDE installed here, but assume that Cosa will compile if installed right!

MarsWarrior, I see that you are back trying to get Cosa up and running on Code::Blocks. Below are a few hints on how to interpret the warning and error messages from the compiler.

  1. The warnings have to do with the PSTR()/PROGMEM macro from AVR. It is not correctly defined in AVR. The same in Arduino. Requires a fix in AVR so for now just ignore "warning: only initialized variables can be placed into program memory area".
  2. The errors are interesting as they reference free_memory() which is very strange. This might have to do with the preprocessing.
  3. The link also seems to miss the object file for the preprocessed .ino file as setup() and loop() are missing.

You need to provide your compiler and link options to make sense of this. Also as I mentioned before this post/topic on this forum is mainly for Cosa updates and not support. Please use the github issue handling instead. I don't really provide support for stuff that is not on the project plan. Sorry about that.

When porting I start with something a bit simpler than CosaPins.ino and work my way upwards. This example sketch does use a lot of Cosa advanced stuff. It is not my first choice when going for a new IDE.

Last, the issue that pito mentioned. It isn't as bad as that. Yes, Cosa is compiled with the Arduino core when a sketch is built for the first time in a session (start of the IDE). A recompile of both the Arduino core and Cosa is forced when a new board is selected. Compiling another sketch in the same session with the same board setting will not force a new build of Cosa (or the Arduino core). All the object files are reused.

Cheers!

I will follow your suggestion by using simpler examples, but a collegue of mine, who has more knowledge of C++ than I have said that this error is normally related to:

  • A common reason of the "vtable" message is not declaring a virtual function equal to zero, for example virtual foo(); instead of virtual foo() = 0;
  • Methods are not implemented in the subclass, while they should be as they are defined in the header file
  • Ordering problem with the linker if the included header files are in the wrong order

If I find something related to Cosa I will either PM you, or add an issue in Github.

The Cosa I2C slave LCD driver is now completed. The initial design has been refactored to a new Virtual LCD class (VLCD) which allows any Cosa LCD device driver to be connected (not just the HD44780 driver). The VLCD class contains two parts; 1) the client part acts as a LCD proxy, translating LCD API calls to I2C messages, 2) the server part acts as an adapter that decodes the I2C messages and calls the LCD implementation.

Below is the CosaLCDslave sketch. It uses the new Virtual LCD class and binding to the HD44780 driver with the 4-bit parallel port IO. This sketch is compiled for an ATtiny84 in the example above but may be compiled for any Cosa supported Arduino.

#include "Cosa/Watchdog.hh"
#include "Cosa/LCD/Driver/HD44780.hh"
#include "Cosa/VLCD.hh"

// Use a 4-bit parallel port for the HD44780 LCD (16X2 default)
HD44780::Port port;
HD44780 lcd(&port);

// And use the LCD for the implementation of the Virtual LCD slave
VLCD::Slave vlcd(&lcd);

void setup()
{
  Watchdog::begin();
  lcd.begin();
  vlcd.begin();
}

void loop()
{
  Event event;
  Event::queue.await(&event);
  event.dispatch();
}

The benchmark CosaLCDspeed.ino binds to the Virtual LCD and runs the measurements. It is the Arduino Nano in the picture above that runs this sketch. See the code on github.

https://github.com/mikaelpatel/Cosa/blob/master/examples/TWI/CosaLCDslave/CosaLCDslave.ino

By implementing the IOStream::Device methods puts(), puts_P() and write() the performance can be boosted to 50-98% of the performance of the I2C IO expander at 400kHz. Below are some results from the benchmarking. The first table shows the performance (operations per second/frames per second), and compares the 4-bit and I2C IO expander implementations (at 100khz and 400 khz).

The above results are used as the baseline for the comparison with the second table below which is the ATtiny84 (internal clock 8Mhz) compiled version and the VLCD version. The comparison is between the 4-bit implementation and then the VLCD implementation (with optimizations).

VLCD may be viewed as a "template" for how to construct I2C slave devices.
http://dl.dropboxusercontent.com/u/993383/Cosa/doc/html/d1/d1f/classVLCD.html

Cheers!

For more details on the development of VLCD and the LCD optimizations see Cosa/Boosting LCD 1602 performance (7X SR4W, 6.5X 4-bit parallel, 1.7-2.3X I2C) - Displays - Arduino Forum

The next step; a USI based TWI master for ATtiny and the ported LCD support. Below is the LCD benchmark running on a LCD with I2C IO expander and an ATtiny85 (internal clock 8 MHz, internal pull-up). The benchmark result is 39 operations per second (32 characters plus 2 set cursor per op). The result for the Cosa LCD driver with I2C IO on a standard Arduino (Uno, Nano, etc) is 53 fps.

The latest I2C optimizations include packaging larger I2C block (32 IO expander commands for 8 characters) on puts() and write().

Cheers!

Here are the numbers from the latest improvements of the Cosa LCD device driver. The table also contains the ratio compared to the New LiquidCrystal Library benchmark.
https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home#!performance-and-benchmakrs
Please note that the ATtiny84/85 benchmarking uses the internal 8Mhz clock.

Read more on "Arduino Forum :: Using Arduino :: Displays :: Cosa/Boosting LCD 1602 I2C performance beyond 130 fps" Cosa/Boosting LCD 1602 performance (7X SR4W, 6.5X 4-bit parallel, 1.7-2.3X I2C) - #27 by kowalski - Displays - Arduino Forum and the blog Cosa: Object-Oriented LCD management

Cheers!