Cosa: An Object-Oriented Platform for Arduino programming

Hi,
have you planed to make a power "vcc" class, with by example
int vcc = readVcc(); // with code below
setlowbat(VccMin, &functiontocall); // function to call when vcc down to VccMin

example code :

long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);  //ATTINY85
//  ADMUX = _BV(MUX5) | _BV(MUX0);                                          //ATTINY84
//  ADMUX = ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);  //ATMEGA328 168
// ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);  // ATMEGA1280 2560
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1126400L / result; // Back-calculate AVcc in mV
  return result;
}

guillaume.

guiguid, that is a nice idea! Below is a snippet of an example sketch how to do the monitoring

class VCC : public Periodic {
private:
  uint16_t m_threshold;
  uint16_t m_vcc;
  virtual void run()
  {
    m_vcc = AnalogPin::bandgap();
    if (m_vcc > m_threshold) return;
    on_low_voltage();
  }
public:
  VCC(uint16_t mv, uint16_t ms = 1024) :
    Periodic(ms),
    m_threshold(mv),
    m_vcc(0)
  {}
  virtual void on_low_voltage()
  {
    trace << Watchdog::get_millis() / 1000 << ':' << m_vcc << PSTR(" mV\n");
  }
};

VCC lowPower(4900);

The callback, the virtual function on_low_voltage(), is called when the threshold is exceeded. The default implementation will print the measurement. Sub-class VCC and override the virtual function to implement your own action.

Please see the full the sketch Cosa/CosaVCC.ino at master · mikaelpatel/Cosa · GitHub

In a later update of Cosa I might bring the VCC class into the library.

Cheers!

Graynomad:
Amazing amount of work here kowalski. I haven't looked too deep yet but it seems well documented as well.

Rob, thanks for the encouragement!

Yes, Cosa is a lot of work but also a lot of fun. I did some changes to the documentation so hopefully you can get an overview easier. There are many components, drivers, etc, in Cosa, so some extra help navigating is needed. Please see the "Related Pages" tab http://dl.dropboxusercontent.com/u/993383/Cosa/doc/html/pages.html

Cheers!

A new Cosa blog posting is now available. It presents some of the Cosa support for 1-Wire devices (with/without parasite powering), the DS18B20 driver, battery monitoring and sending sensor data using the Cosa Virtual Wire Interface (VWI).

Cheers!

Big THANKS to guiguid for great suggestions and testing a lot of this code.

More good work.

I assume the 1-wire is handled with bit-banging the signal(s), any idea how much CPU time that takes?


Rob

Graynomad:
More good work.
I assume the 1-wire is handled with bit-banging the signal(s), any idea how much CPU time that takes?


Rob

Thanks!

Yes, the Cosa 1-Wire driver does bit-bang the protocol as most micro-controller implementations. I think Wiki explains the protocol very well 1-Wire - Wikipedia. There are all the numbers.

The reset or presence signal is the big waste in CPU-cycles if using a simple delay loop. Each bit in the protocol is short (shortest a 5 us pulse, 75 us per bit) so an alternative solution such as timer interrupt sampler is not really possible. UART would be possible.

Reading the temperature from DS18B20 is in the order of 2 ms (reset plus 1 byte command, 8 byte address, 1 byte command followed by read of 7 byte, 960 + 17*75 = 2235 us). Most of this time is delay loops. Typically interrupt handling is allowed between bit read/writes. The actual conversion takes 750 ms at full resolution. During this period the processor can do something else or take a nap.

To answer your question; typically less than 1% at 1 second sample rate (per device).

Cheers!

OK, thanks for that. I'm trying to decide if it's worth putting an I2C to 1-wire bridge chip on a new design, I think I will as that also gives active pullup.


Rob

Graynomad:
OK, thanks for that. I'm trying to decide if it's worth putting an I2C to 1-wire bridge chip on a new design, I think I will as that also gives active pullup.


Rob

I had a look at the DS2482-100 Single-Channel 1-Wire Master, I²C to 1-Wire Bridge Device. Interesting challenge to get the OWI device driver to run over the Cosa TWI, i.e. make the Cosa OWI driver hide the fact that a bridge was used and allow code written as an OWI::Driver to run unchanged.

Actually reading the sensor data from a DS18B20 will take a large number of TWI commands (1-Wire search is even worse). The sequencing is a challenge if to avoid polling the status register in a busy-loop over the TWI driver. This could actually increase the CPU load instead of decreasing it. Though there are a number of advantages with this chip I should add.

Cheers!

Interesting observations, I know naff-all about 1-wire and am flying by data sheet here. I'll add the chip and figure it out later :slight_smile:


Rob

Hey kowalski,
First, I echo others' recent kudos for your continued great work on this platform!

Now for a hopefully simple question that I'm almost embarrassed to ask:
How do I use the additional hardware serial ports on the Arduino Mega2560?
I perused through the UART.hh and UART.cpp files, and I see code for what looks like uart1,2,3 inside of: #elif defined(ARDUINO_MEGA)
But simply calling uart1.begin(9600); didn't compile.

I did get this blip of code to compile at least (not sure if it really works or not):

static char ibuffer1[UART::BUFFER_MAX];
static IOBuffer ibuf1(sizeof(ibuffer1), ibuffer1);
static char obuffer1[UART::BUFFER_MAX];
static IOBuffer obuf1(sizeof(obuffer1), obuffer1);
UART uart11(1, &ibuf1, &obuf1);
...
uart11.begin(9600);

...but I wasn't sure if all of that was necessary if there is built-in support for simply calling: uart1.begin(9600);, etc.
Also, I had to use "uart11" as "uart1" complains about: "multiple definition of `uart1'"
Am I missing something simple?

Also, I'm curious as to the status of SoftwareSerial-like support... :slight_smile:

Thanks in advance for any help!

Thanks for the response, kowalski!

Please forgive my ignorance, but may I ask why the design principle is that the additional UART instances/buffers are not pre-allocated? Is it to save memory? If so, I would "think" that the MEGA certainly has enough memory to handle them being pre-allocated in the #elif defined(ARDUINO_MEGA) block so they can simply be used like the default uart. After all, multiple hardware UARTs was my primary reason for purchasing a MEGA :slight_smile:

Just curious... Thanks!

sirhax:
Please forgive my ignorance, but may I ask why the design principle is that the additional UART instances/buffers are not pre-allocated? Is it to save memory?

Great questions! I want to leave as much memory as possible to applications. Preallocation of buffers is actually difficult as it depends on the amount of "speed adjustment" needed. The buffer should be as large as possible to allow the application to continue processing. But small enough to leave as much memory as possible. The UART can be viewed as an extra processor. The goal is to get as many of the AVR hardware resources to run in parallel with the processor core.

An example: for a given output stream (bytes per second, in burst) the buffer size depends on the speed of the transmission (baud-rate). The faster the baud-rate the shorter the buffer for a fixed output rate but at least the size of a burst. If the buffer is too small the application will stall due to waiting on the UART.

Nearly all memory allocation in Cosa is configurable and/or input parameters as the IOBuffer's.

Cheers!

Edit: Updated with the new IOBuffer template class for better performance and improved memory allocation. There is also a new example sketch in the Cosa/Sandbox: https://github.com/mikaelpatel/Cosa/blob/master/examples/Sandbox/CosaMegaUARTs/CosaMegaUARTs.ino


Hi sirhax!

I have added some support for multiple UARTs. It's a quick fix with a support macro for the setup. The usage is as below.

static IOBuffer<UART::BUFFER_MAX> ibuf1;
static IOBuffer<UART::BUFFER_MAX> obuf1;
UART uart1(1, &ibuf1, &obuf1);
...
void setup()
{
   ...
   UART_SETUP(1, uart1);
   uart1.begin(9600);
   ...
}

The support macro UART_SETUP() is used for binding the UART instance to the ISR handler. The extern variables are now refactored (static class members) and defined in the UART.hh file. The macro does the job. I also took the opportunity to change the strange constructor parameter order of IOBuffer. Had missed that :slight_smile:

Please use the issue handling on github. It allows me and others follow these types of great improvement ideas.

Cheers!

Some news on the latest improvements:

  1. Extended Virtual Wire Interface
    The Cosa Virtual Wire Interface (VWI) has been updated with support for node addresses, address match and message types. In extended mode a header is added to the payload. The header contains the Transmitter node address, message sequence number and message type. The receiver(s) will match the address by masking and comparing with its own node address. The full message with header and message is returned to the receiver for further dispatch. The interface change is backward compatible. Please see the example sketches CosaVWItempsensor.ino, https://github.com/mikaelpatel/Cosa/blob/master/examples/VWI/CosaVWItempsensor/CosaVWItempsensor.ino, and CosaVWItempmonitor.ino, https://github.com/mikaelpatel/Cosa/blob/master/examples/VWI/CosaVWItempmonitor/CosaVWItempmonitor.ino.

  2. NEXA/Homeeasy Wireless Remote command receiver.
    Support for interrupt driven or polled wireless remote command receiving. See NEXA.hh, https://github.com/mikaelpatel/Cosa/blob/master/Cosa/Driver/NEXA.hh, and the example sketch CosaNEXAreceiver.ino, https://github.com/mikaelpatel/Cosa/blob/master/examples/Sandbox/CosaNEXAreceiver/CosaNEXAreceiver.ino.

  3. IO-vector support
    The type iovec_t (see Cosa/Types.h) is a struct with buffer/size pair. A null terminated vector of iovect_t is a convenient method of allowing scattered buffer elements that are gathered for instance on send.
    a. New VWI::send(vec) member function to allow additional buffers on send. Allows additional headers without code change.
    b. New IOStream::Device::writev(vec) member function.

  4. Template classes
    The Cosa Queue and IOBuffer classes have been refactored to template classes. This allows additional performance and improved memory allocation. An example of ripple effect; The Cosa FSM benchmark measurement of sending messages between finite-state machines was improved by 50% (20 us per message dropped to 10 us).

Cheers!

A new Cosa blog post is available. It presents the Cosa Enhanced Virtual Wire Interface; reliable wireless RF433 module communication with message acknowledgement and auto-retransmission. The VWI classes may be used with ATtinyX5.

Cheers!

Mikael,
This is really interesting what you are doing.
I have peeked into your Cosa OOP documentation over the past weeks and can see you have put a tremendous amount of work into this.
It looks looks to be a highly organised, well thought out and useable framework.

I look forward to learning more and hopefully trying it out.


Paul

Paul, thanks for your comments and encouragement.

Cosa as a project is great fun and I have lots on the agenda. It is very much a bottom-up process to build a framework and I want/need to get feedback early on to move in the right direction. Obviously more support for Wireless, Ethernet, USB, and many more sensor drivers are needed. Also the host part of Ciao/Cosa Fai is also needed before becoming really useful.

If you get the time to test Cosa I would very much appreciate feedback.

Cheers!

A new Cosa blog post is available. It presents the basic working procedure for getting Arduino Cosa sketches working on ATtiny. Special focus is on how to use the Cosa Soft UART and PCD8544 LCD driver for trace output from ATtiny.

Cheers!

Just stumbled onto this. Nice lib!

I am writing a modest lib myself that is only for advanced users and targets to minimize ram usage (at the expense of using more prog-mem) and allow total control. I got frustrated with the stupid Arduino lib implementations that seem to be the standard -they are great for demo's and simple prototypes, but will fight you when you want to do some real work. I also use mainly template classes and no virtual functions to accomplish my goals. I intentionally leave out/do not use certain OO/C++ features in order to keep it small.

What do you think of this (to me, this looks very logical):
ViewPort<TextLcd<LcdDriver<..pin io..>, ..physical size..>, ..virtual size..>

This demonstrates:

  • separation of concerns: the actual hardware driver can be swapped out for different types of LCDs, or any one of the template classes
  • extensablility: if you don't like the impl. of some part, replace with your own.
  • No ram: all parameters are compiled into the code and the template classes do not use virtuals. This assumes you will not add/change LCD displays dynamically.

To avoid using virtuals, I use this a lot:

template<BaseT>
class SomeService : BaseT
{
public:
  void SomeMethod()
  {
     BaseT::MethodOnBaseT();
  }
};

Currently I still depend on the Arduino lib, but I'm planning to replace that.

Anyway, all the best with your library.

The library looks nice, but I don't get how I can subscribe to an event (for example of an ExternalInterruptPin) when subclassing is not an option? The class pushes an event but I do not see how I it can be handled from outside.