Pages: 1 ... 5 6 [7] 8 9 ... 30   Go Down
Author Topic: Cosa: An Object-Oriented Platform for Arduino programming  (Read 78525 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 1
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the fast answer. Handing the event in the dispatch loop would become a bit messy on the long run.

Just to depict my problem: I'm planning to use a rotary encoder which uses two pins. Therefore subclassing the ExternalInterruptPin as in the IR::Receiver example is not possible. So probably I would have to subclass the pin in order to be able to delegate the event handling to some other class/function.

But I'm in the moment just looking into different lib to see which would fit my needs best. Yours looked quite interesting.

The short answer to your question is that you can always handle the event directly instead of calling dispatch(). Below is snippet from CosaFSMBlink which uses the dispatch-method.
Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 443
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the fast answer. Handing the event in the dispatch loop would become a bit messy on the long run.

Just to depict my problem: I'm planning to use a rotary encoder which uses two pins. Therefore subclassing the ExternalInterruptPin as in the IR::Receiver example is not possible. So probably I would have to subclass the pin in order to be able to delegate the event handling to some other class/function.
You are welcome! This is an interesting design problem.

The solution you are sketching is similar to the pattern used in the NRF24L01P driver where a sub-class of ExternalInterruptPin is defined within the class itself and posts events back to the "parent", i.e. container.
Below is a snippet from the driver.
Code:
class NRF24L01P : private SPI::Driver {
private:
  ...
  class IRQPin : public ExternalInterruptPin {
    friend class NRF24L01P;
  private:
    NRF24L01P* m_nrf;
  public:
    IRQPin(Board::ExternalInterruptPin pin, Mode mode, NRF24L01P* nrf) :
      ExternalInterruptPin(pin, mode),
      m_nrf(nrf)
    {}
    virtual void on_interrupt(uint16_t arg = 0);
  };
  IRQPin m_irq;
  ...
};

void
NRF24L01P::IRQPin::on_interrupt(uint16_t arg)
{
   ...
   Event::push(Event::RECEIVE_COMPLETED_TYPE, m_nrf, status);
   ...
}
You could have several InterruptPins defined within a container class which post events to the same target object (i.e. the container).

Cheers!
Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 443
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the link, didn't know that lib. I will look into it.
...
I am currently testing a way for lightweight cooperative mutlitasking. Once I figured out how to do async time delays I can go to town on supporting other typical devices (I2C, LCD etc).
You are welcome. Here are a few links to Proto-threads which is a style of implementing coroutines. These are actually from the comment block in Cosa/Thread.hh, http://dl.dropboxusercontent.com/u/993383/Cosa/doc/html/d0/d51/classThread.html and https://github.com/mikaelpatel/Cosa/blob/master/Cosa/Thread.hh.

[1] Adam Dunkels et al, Protothreads: Simplifying Event-Driven Programming of Memory-Constrained Embedded Systems, SenSys'06, November 1-3, 2006, Boulder, Colorado, USA.
[2] Larry Ruane, protothread: An extremely lightweight thread library for GCC, http://code.google.com/p/protothread/
[3] http://en.wikipedia.org/wiki/Protothreads

It is possible to avoid the "switch" problem by using gcc local labels and label address. The Cosa implementation is object-oriented and fully integrated with the Cosa periodic timer queue.

Cheers!
Logged

Netherlands
Offline Offline
Jr. Member
**
Karma: 1
Posts: 93
Profile before you Optimize.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice docs!

That does look like a good implementation. Most threading impl's I've seen are over the top for the small MCU they're supposed to work on (IMHO).

I will stick with my macro's and switch statement (two bytes) for a while and see if I can get it to work. My aim is to allow the tasks to run with and without a scheduler. The scheduler only handles waiting tasks, at least that's the idea.

Thanx!
Logged


Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 443
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

A new Cosa blog post is available. It presents the Cosa NEXA driver; RF433 transmitter and receiver for Home Automation with NEXA/HomeEasy remote and receivers. Driver and example sketches may be run on ATtiny.

http://cosa-arduino.blogspot.se/2013/05/more-rf433-wireless-home-automation.html

Cheers!
Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 443
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Some news on the latest updates to Cosa.

1. ATtiny X5 and X4 is now supported. In reality only 8K devices, ATtiny84 and ATtiny85, are practical to work with. The others have too small memory size (SRAM). Most drivers have been ported to the ATtiny's; DHT11/22, OneWire DS18B20, LCD (PCD8544/ST7565), Virtual Wire, Ultra-sonic range module and more. More details: http://cosa-arduino.blogspot.com/2013/04/programming-attinyx5.html
2. Enhanced Virtual Wire Interface (VWI), VWI::Transceiver, with message acknowledgement, auto-retransmission and support for message type encoding/decoding. http://cosa-arduino.blogspot.com/2013/04/enhanced-virtual-wire-interface.html
3. Support for Home Automation NEXA/HomeEasy transmitter, receiver and "listener" objects. http://cosa-arduino.blogspot.com/2013/05/more-rf433-wireless-home-automation.html
4. Soft UART with IOStream integration. Mainly for debug trace output from ATtiny as this only requires a single pin for the TX.
5. Improved driver support for DHT11/22.
6. Cosa RTC includes three levels of "clocks"; micro-, milli- and second base. The millisecond timer base (Timer0/B) interrupt handling may be extended with a periodic callback for more accurate event timing.
7. BCD print support. May be used to avoid BCD-binary conversion when BCD data is not processed (such as when using the I2C Realtime Clock, DS1307, see DS1307::timekeeper_t::print(IOStream& stream, const char* format), https://github.com/mikaelpatel/Cosa/blob/master/Cosa/TWI/Driver/DS1307.cpp)
8. LCD ST7565 support. As PCD8544 the LCD driver is integrated with IOStream. Graphics is performed using the OffScreen Canvas. This driver also supports text scroll without using a memory buffer. Please see the example sketch; https://github.com/mikaelpatel/Cosa/blob/master/examples/LCD/CosaST7565P/CosaST7565P.ino  
9. New methods in the IOStream::Device interface; room(), number of bytes before output buffer is full, and peekchar(), access the next character in the input buffer without removing it. Updates to the implementations of the interface; UART, IOBuffer, etc.
10. Updated support for io vector buffers (iovec) and improved handling in communication drivers (TWI, SPI and VWI).
11. Major refactoring of Cosa TWI (I2C driver). Totally rewritten I2C/Two-Wire driver with higher level of application support. Reduced to less than 300 commented LOC.
12. Updated OffScreen Canvas to a template class. Improved robustness and performance.

Cheers!
« Last Edit: May 16, 2013, 01:56:08 pm by kowalski » Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 443
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Some news on the latest updates to Cosa.

1. TWI (I2C) slave mode on Arduino and ATtiny. Allows easy design of TWI slave devices using a simple event callback design. The Cosa TWI ATtiny driver uses USI and implements variable write blocks with STOP detection.  See CosaTWImaster/slave for an example of usage pattern; https://github.com/mikaelpatel/Cosa/blob/master/examples/TWI and the example sketches CosaTWImaster/slave and CosaTWIremotePinMaster/Slave.

2. New Cosa driver class for Rotary Encoders. Support for direction detection and dials with min, max and initial value. Uses the Cosa support for Interrupt Pins and the Event manager. See example sketch; https://github.com/mikaelpatel/Cosa/blob/master/examples/Sandbox/CosaRotaryEncoder/CosaRotaryEncoder.ino

3. GCC weak attribute introduced on Cosa objects; UART, SPI, TWI, etc. Makes it easy for applications to override. See UART for an example; https://github.com/mikaelpatel/Cosa/blob/master/Cosa/IOStream/Driver/UART.cpp and redefinition in CosaTWIslave example sketch; https://github.com/mikaelpatel/Cosa/blob/master/examples/TWI/CosaTWIslave/CosaTWIslave.ino

Cheers!
« Last Edit: May 27, 2013, 10:05:40 am by kowalski » Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2066
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
New Cosa driver class for Rotary Encoders.
I've got two quadrature output kinds of encoders (ie. see http://www.bourns.com/data/global/pdfs/ECW1J.pdf ):
a) with full cycle per detent
b) 1/4 cycle per detent
Would it be possible to configure it for that modi?



« Last Edit: May 27, 2013, 10:05:10 am by pito » Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 443
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
New Cosa driver class for Rotary Encoders.
I've got two quadrature output kinds of encoders (ie. see http://www.bourns.com/data/global/pdfs/ECW1J.pdf ):
a) with full cycle per detent
b) 1/4 cycle per detent
Would it be possible to configure it for that modi?
Hi Pito. The Cosa Rotary Encoder driver is a repackaging of Ben Buxton's excellent implementation into the object-oriented style of Cosa and integrated with Interrupt Pins and the Event Manager. http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html

It is possible to configure in two modes; half and full step. The default is full step. Define HALF_STEP to change mode (in Rotary.cpp). I think this covers at least one of the cases.

Cheers!
« Last Edit: May 27, 2013, 04:35:43 pm by kowalski » Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2066
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yea, it seems the half step is the "1/4 cycle" and the full step means "full cycle". I can test it when an example is available.. Thanks
Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 443
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yea, it seems the half step is the "1/4 cycle" and the full step means "full cycle". I can test it when an example is available.. Thanks
I have updated the Rotary Encoder/Dial driver so that the stepping mode may be selected at run-time instead of build-time. It may also be updated. Below is a snippet from the updated version of the example sketch https://github.com/mikaelpatel/Cosa/blob/master/examples/Sandbox/CosaRotaryEncoder/CosaRotaryEncoder.ino

Code:
// Construct Dial connected to interrupt pins D6 and D7, start in full step mode,
// with initial value -100, min -100, and max 10.
Rotary::Dial dial(Board::PCI6, Board::PCI7, Rotary::Encoder::FULL_STEP, -100, -100, 10);

void loop()
{
  // Rotary Encoder interrupt pin handler will push an event when a change occurs
  Event event;
  Event::queue.await(&event);

  // Dispatch the event so that the dial value is updated
  event.dispatch();

  // Change step mode at min and max values
  static int old_value = -100;
  int new_value = dial.get_value();
  if (old_value == -100 && new_value == -99)
    dial.set_step(Rotary::Encoder::FULL_STEP);
  else if (old_value == 10 && new_value == 9)
    dial.set_step(Rotary::Encoder::HALF_STEP);
  old_value = new_value;

  // Print the new value
  trace << new_value << endl;
}

Cheers and thanks for the feedback!
« Last Edit: May 27, 2013, 04:46:50 pm by kowalski » Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2066
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmm, I am coping with the stuff, indeed smiley
I am using 1284p mighty, IDE 1.5.2, and an encoder with pullups on A6/A7, and in "Cosa/Board/mighty.hh" I did following changes (mighty uses a reversed numbering in Ax):
Code:
...
  /**
   * Return Pin Change Mask Register for given Arduino pin number.
   * @param[in] pin number.
   * @return pin change mask register pointer.
   */
  static volatile uint8_t* PCIMR(uint8_t pin)
  {
    return (pin < 8  ? &PCMSK0 :
   pin < 14 ? &PCMSK1 :
   pin < 24 ? &PCMSK2 :
   &PCMSK3);
  }
...
 /**
   * Analog pin symbols; mapping from name to port<5>:bit<3>.
   */
  enum AnalogPin {
    A0 = 31,
    A1 = 30,
    A2 = 29,
    A3 = 28,
    A4 = 27,
    A5 = 26,
    A6 = 25,
    A7 = 24
  } __attribute__((packed));
...
  /**
   * Pin change interrupt. Number of port registers.
   */
  enum InterruptPin {
    /*PCI0 = A0,
    PCI1 = A1,
    PCI2 = A2,
    PCI3 = A3,
    PCI4 = A4,
    PCI5 = A5,
    PCI6 = A6,
    PCI7 = A7*/
    PCI0 = D0,
    PCI1 = D1,
    PCI2 = D2,
    PCI3 = D3,
    PCI4 = D4,
    PCI5 = D5,
    PCI6 = D6,
    PCI7 = D7,
    PCI8 = D8,
    PCI9 = D9,
    PCI10 = D10,
    PCI11 = D11,
    PCI12 = D12,
    PCI13 = D13,
    PCI14 = D14,
    PCI15 = D15,
    PCI16 = D16,
    PCI17 = D17,
    PCI18 = D18,
    PCI19 = D19,
    PCI20 = D20,
    PCI21 = D21,
    PCI22 = D22,
    PCI23 = D23,
    PCI24 = A0,
    PCI25 = A1,
    PCI26 = A2,
    PCI27 = A3,
    PCI28 = A4,
    PCI29 = A5,
    PCI30 = A6,
    PCI31 = A7
  } __attribute__((packed));
...
  /**
   * Auxiliary
   */
  enum {
    VBG = (_BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)),
    EXT_MAX = 3,
    PCINT_MAX = 4,
    PIN_MAX = A0
  } __attribute__((packed));
};
Not sure whether I do understand the Auxiliary well - it seems to me pcint_max = 4(??) and pin_max = A0 (??) (pin code 31).
So the pin change interrupt is set to A6, A7 with the code:

Code:
// MIGHTY ATMEL ATMEGA1284P
//
//                       +---\/---+
//           (D 0) PB0  1|        |40  PA0 (AI 0 / PCI24 / D24)
//           (D 1) PB1  2|        |39  PA1 (AI 1 / PCI25 / D25)
//      INT2 (D 2) PB2  3|        |38  PA2 (AI 2 / PCI26 / D26)
//       PWM (D 3) PB3  4|        |37  PA3 (AI 3 / PCI27 / D27)
//    PWM/SS (D 4) PB4  5|        |36  PA4 (AI 4 / PCI28 / D28)
//      MOSI (D 5) PB5  6|        |35  PA5 (AI 5 / PCI29 / D29)
//  PWM/MISO (D 6) PB6  7|        |34  PA6 (AI 6 / PCI30 / D30)
//   PWM/SCK (D 7) PB7  8|        |33  PA7 (AI 7 / PCI31 / D31)
//                 RST  9|        |32  AREF
//                 VCC 10|        |31  GND
//                 GND 11|        |30  AVCC
//               XTAL2 12|        |29  PC7 (D 23)
//               XTAL1 13|        |28  PC6 (D 22)
//      RX0 (D 8)  PD0 14|        |27  PC5 (D 21) TDI
//      TX0 (D 9)  PD1 15|        |26  PC4 (D 20) TDO
// RX1/INT0 (D 10) PD2 16|        |25  PC3 (D 19) TMS
// TX1/INT1 (D 11) PD3 17|        |24  PC2 (D 18) TCK
//      PWM (D 12) PD4 18|        |23  PC1 (D 17) SDA
//      PWM (D 13) PD5 19|        |22  PC0 (D 16) SCL
//      PWM (D 14) PD6 20|        |21  PD7 (D 15) PWM
//                       +--------+
//

#include "Cosa/Rotary.hh"
#include "Cosa/Trace.hh"
#include "Cosa/IOStream/Driver/UART.hh"

void setup()
{
  // Use the UART as output stream
  uart.begin(115200);
  trace.begin(&uart, PSTR("CosaRotaryEncoder: started"));

  // Start the interrupt pin handler
  InterruptPin::begin();
  
}


// Construct Dial connected to interrupt pins (A6 and A7 on mighty), start in full step mode,
// with initial value -100, min -100, and max 10.
Rotary::Dial dial(Board::PCI30, Board::PCI31, Rotary::Encoder::FULL_STEP, -100, -100, 10);

void loop()
{
  // Rotary Encoder interrupt pin handler will push an event when a change occurs
  Event event;
  Event::queue.await(&event);

  // Dispatch the event so that the dial value is updated
  event.dispatch();

  // Change step mode at min and max values
  static int old_value = -100;
  trace << old_value << endl;
  int new_value = dial.get_value();
 //if (old_value == -100 && new_value == -99)
 //  dial.set_step(Rotary::Encoder::FULL_STEP);
 //else if (old_value == 10 && new_value == 9)
 //  dial.set_step(Rotary::Encoder::HALF_STEP);
 // old_value = new_value;

  // Print the new value
  trace << new_value << endl;
}

However it prints only:
Code:
CosaRotaryEncoder: started
with whatever I've done above.. It does not even print the old_value..

PS1: it waits/stops/crashes(?) on " Event::queue.await(&event);"
PS2: tried with other pins, no luck yet..

PS3: reading interruptpin.hh I've set PCINT_MAX = 4 in above mighty.hh

PS4: I think we have to have in l.50 interruptpin.hh (as the mighty has got all 4 PCMSKs):
Code:
#if !defined(__ARDUINO_MEGA__)
  friend void PCINT3_vect(void);

PS5: yea, the interrupt handler has to be fine-tuned for above mighty.hh.. Thanks smiley
« Last Edit: May 28, 2013, 09:15:30 am by pito » Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 443
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The Interrupt Pin handler is not yet implemented for Arduino Mighty. Seems like time to look into that.

Cheers!
« Last Edit: May 28, 2013, 08:47:31 am by kowalski » Logged

Sweden
Offline Offline
Sr. Member
****
Karma: 11
Posts: 443
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The Pin Change Interrupt (Cosa/InterruptPin) is now implemented and the board definition updated for the Mighty. Please pull the update from github; https://github.com/mikaelpatel/Cosa/commit/74647585803af3df16673a9849e7d80dfb955659

Cheers.
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 60
Posts: 2066
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Now it has started to work, however the "full" step and "half" step needs to be investigated smiley.

PS1: My first encoder does a click every Gray code step (so called "1/4 cycle per detent").
With FULL_STEP it incr/decr every fourth click, with HALF_STEP it incr/decr every second click.

PS2: My second encoder (called "full cycle no detents) incr/decr based on the FULL/HALF_STEP slower or faster.

PS3: My third encoder (called "full cycle per detent") incr/decr twice a click when HALF, and once a click when FULL..
smiley

PS4: How does fit your mighty.hh the Mighty's pin assignment (see above)? My current understanding is the changes I proposed above does fit the mighty's pinout, you does it differently - why?

PS5: I've changed the types in rotary.hh (to long int) so now I can dial a frequency on my DDS VFO:
Code:
CosaRotaryEncoder: started
29999999
29999998
29999997
29999996
smiley

Some new ideas (this is NOT a change request):
1. to make the dial parameters types flexible (signed/unsigned long long, long, int, char)
2. to measure the time between the increments ("accelerated dialing") - when fast angular speed then double the increment each encoder's cycle (so a fast rotational pulse will create a huge increment). I have it with an very old pic16 DDS design and it works great..
3. to add a "step" parameter (the increment)
4. to rename FULL_STEP and HALF_STEP to FULL_CYCLE and HALF_CYCLE (as it is related to the encoder)
5. the "1/4 cycle per detent" that is an unsupported encoder.


* rotenc.jpg (17.76 KB, 638x157 - viewed 23 times.)
« Last Edit: May 28, 2013, 11:23:45 am by pito » Logged

Pages: 1 ... 5 6 [7] 8 9 ... 30   Go Up
Jump to: