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
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.
}
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:
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;
}
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!
Ian