Convert Arduino code to XOD

Hi All,
I have just started playing with XOD and it seems very powerful. But I am having a problem relating how it works to old fashioned C (Arduino style).
In particular I have a code fragment that generates a PPM stream from an array of inputs. There is no coding required in the “loop()” section of the program to implement this. It just sets some registers (BTW this only works on Arduino Nano and Mega2560 to my knowledge) for timer1, and an ISR to increment the array counter. It works really well, but I don’t know if it can be implemented in XOD. I know zero about C++, and not much more about XOD.
I saw another post where you suggested copying the bespoke code into the code generated by XOD. This would certainly work but it would mean doing it every time the XOD patch is updated. Not a huge problem for me as there is lots of other stuff to implement that doesn’t require the PPM output generated (I could probably stick that in last, after everything else is working) but I still have the problem of populating the array and making it available to the ISR. Is that possible? Would I need to define it in the state{} section of the “not defined in xod” node? How do I reference it from another node (that does analog reads and generates the pulse width)? From what I understand of XOD so far this would not be possible.
For your perusal I’ve pasted the full code below.
Thanks, Ian

volatile unsigned int channel[9] = {2000, 2400, 2600, 2800, 3000, 3200, 3600, 4000, 21400};
volatile unsigned int ch = 0;
void setup() {
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;

TIFR1 |= (1 << OCF1A); // clear any pending interrupts;

TCCR1A |= (1 << COM1B1); // Toggle on B compare
TCCR1A |= (1 << WGM10) | (1 << WGM11); // Fast PWM mode, TOP = OCR1A
TCCR1B |= (1 << WGM12) | (1 << WGM13); // Fast PWM mode, TOP = OCR1A
TCCR1B |= (1 << CS11); // 8 prescaler gives 500us tick size, i.e. 2 ticks per ms.
TIMSK1 |= (1 << TOIE1); // enable overflow vector
DDRB |= (1 << DDB2); // for Nano - turn on output pin 10 = OC1B (PB2).
//DDRB |= (1 << DDB6); // for Mega - turn on output pin 13 = OC1B (PB6)
OCR1B = 600; // for separator pulse of 300us - double for 8 prescaler
interrupts(); // enable all interrupts
}
ISR(TIMER1_OVF_vect) {
OCR1A = channel[ch] ;
ch = ( ch++ > 8) ? 0 : ch;
}
void loop() {
// put code to do analog reads, switch polling and whatever else is
// required to generate the pulse widths required, and store them in
// the “channel[]” array. The example will transmit 8 channels. The
// ninth element is the sync pulse (22500 - sum of all pulses and
// separator pulses) and must be recalculated for every frame.
}

Hello and welcome!

A quick dirty hack which came into my mind first is to make a new C++ node with roughly the following code:

struct State {}; // not used

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
  if (isSettingUp()) { // this will evaluate once on boot
    noInterrupts(); // disable all interrupts
    TCCR1A = 0;
    TCCR1B = 0;
    TIFR1 |= (1 << OCF1A); // clear any pending interrupts;
    //
    // ... all the register magic...
    //
    interrupts(); // enable all interrupts
  }
}

{{#global}}
// Escape to the global scope because ISR’s should be there

volatile unsigned int channel[9] = {
  2000, 2400, 2600, 2800, 3000, 3200, 3600, 4000, 21400
};

volatile unsigned int ch = 0;

ISR(TIMER1_OVF_vect) {
  OCR1A = channel[ch] ;
  ch = ( ch++ > 8) ? 0 : ch;
}
{{/global}}

Then place the node onto your entry point patch (main).

It will have no pins and so is not customizable anyhow, but it’s a first try. Another set of hacks can make it adjustable if the first step succeeds :wink:

P.S> Please, use triple backticks around code blocks so that forum can format them as code snippets.

Hi Victor,
Thanks for the quick response!
I eventually found the isSettingUp switch and wrapped it around the register setup in a separate node as you suggested. Tried creating another node with the channel array in the state block and some code to update it in the evaluate block, with two numeric inputs, channel number and pulse width. My idea was to use the node in main, do an analog read of a port then pass the port number and result of the read to the node. Eventually got this to compile but my knowledge of C++ is such that I couldn’t figure out from the generated code if it would work as expected. I’m guessing not as the state is local to the node, so the channel array would not be accessible to the ISR? I had no joy at all trying to squeeze the ISR in anywhere…
My update-pulse node now looks like this:

struct State {
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {

    int chanValue = getValue<input_CHAN>(ctx);
    int pulsValue = getValue<input_PULS>(ctx);
    // Write
    channel[chanValue] = (pulsValue * 2) + 1000;
    //emitValue<output_OUT>(ctx, inValue);
}

and my initialisation node looks like this:

struct State {
};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
    if (isSettingUp) {
      noInterrupts();           // disable all interrupts
      TCCR1A = 0;
      TCCR1B = 0;
      TIFR1  |= (1 << OCF1A);  // clear any pending interrupts;
      TCCR1A |= (1 << COM1B1); // Toggle on B compare
      TCCR1A |= (1 << WGM10) | (1 << WGM11);   // Fast PWM mode, TOP = OCR1A
      TCCR1B |= (1 << WGM12) | (1 << WGM13);   // Fast PWM mode, TOP = OCR1A
      TCCR1B |= (1 << CS11);  // 8 prescaler gives 500us tick size, i.e. 2 ticks per ms.
      TIMSK1 |= (1 << TOIE1);    // enable overflow vector
      DDRB   |= (1 << DDB2); // for Nano - turn on output pin 10 = OC1B (PB2).
      //DDRB   |= (1 << DDB6); // for Mega - turn on output pin 13 = OC1B (PB6)
      OCR1B = 600; // for separator pulse of 300us - double for 8 prescaler
      interrupts(); // enable all interrupts
    }
    //auto inValue = getValue<input_IN>(ctx);
    //emitValue<output_OUT>(ctx, inValue);
}
{{#global}}
// Escape to the global scope because ISR’s should be there

volatile unsigned int channel[9] = {
  2000, 2400, 2600, 2800, 3000, 3200, 3600, 4000, 21400
};

volatile unsigned int ch = 0;

ISR(TIMER1_OVF_vect) {
  OCR1A = channel[ch] ;
  ch = ( ch++ > 8) ? 0 : ch;
}
{{/global}}

It all compiles, but will it work? I’ll let you know if it does…
:wink: Ian

From what I see in your latest code, I see no reason why it should not work. I guess it will. Try it.

If I made this node, I would put everything in a single node with nine inputs. Arguably, it would make the node more self-contained and easier to understand:

{{#global}}
// Escape to the global scope because ISR’s should be there

volatile unsigned int channel[9] = {
  // these are initial valued=s
  2000, 2400, 2600, 2800, 3000, 3200, 3600, 4000, 21400
};

volatile unsigned int ch = 0;

ISR(TIMER1_OVF_vect) {
  OCR1A = channel[ch] ;
  ch = ( ch++ > 8) ? 0 : ch;
}
{{/global}}

struct State {};

{{ GENERATED_CODE }}

void evaluate(Context ctx) {
    if (isSettingUp) {
      noInterrupts();           // disable all interrupts
      TCCR1A = 0;
      TCCR1B = 0;
      TIFR1  |= (1 << OCF1A);  // clear any pending interrupts;
      TCCR1A |= (1 << COM1B1); // Toggle on B compare
      TCCR1A |= (1 << WGM10) | (1 << WGM11);   // Fast PWM mode, TOP = OCR1A
      TCCR1B |= (1 << WGM12) | (1 << WGM13);   // Fast PWM mode, TOP = OCR1A
      TCCR1B |= (1 << CS11);  // 8 prescaler gives 500us tick size, i.e. 2 ticks per ms.
      TIMSK1 |= (1 << TOIE1);    // enable overflow vector
      DDRB   |= (1 << DDB2); // for Nano - turn on output pin 10 = OC1B (PB2).
      //DDRB   |= (1 << DDB6); // for Mega - turn on output pin 13 = OC1B (PB6)
      OCR1B = 600; // for separator pulse of 300us - double for 8 prescaler
      interrupts(); // enable all interrupts
    }

    // setting up or update on an input pin
    // we refer the global array `channel`, so the ISR will have access to it
    channel[0] = getValue<input_CH1>(ctx) * 2 + 1000;
    channel[1] = getValue<input_CH2>(ctx) * 2 + 1000;
    // ...
    channel[8] = getValue<input_CH9>(ctx) * 2 + 1000;
}

It works!!

Now I just have to figure out the rest of the code. It’s turning out to be more difficult than I thought using the builtin Xod primitives. I think I may have to rethink my approach. I’m thinking I need to define more patches that do less, and then connect them all together in main. Or build up a sort of tree structure of patches, with the “leaves” doing the actual work, and the nodes in the higher level patches doing all the linking and conditional processing, or something. Dunno. Having a lot of fun working it all out though!
:wink: Ian

1 Like