Arduino Mega PWM on all outputs – or – Excel code generation

The problem:
Generating serial-port-controlled PWM signals on all 54 outputs of the Arduino Mega

The solution:
Generating a serial protocol, using timer interrupts & code generation by excel.

ArduinoMega2560_R3_Front_450px

In this post I will describe the process through which I managed to solve all the above mentioned problems.

The serial protocol

The first step is to think of a simple protocol that uses the least possible bytes for controlling any of the 54 digital output (the address). To send a number between 0 and 54 we will need 6 bits. (the highest binary number with 6 bits is 111111 = decimal 63).

If we were to use 1 byte, we would have 2 bits left for the pulse width (the data), which is clearly too little. Using 2 bytes gives us 10 remaining bits for the pulse width, which is a range of 0..1023. A two-byte message would look like this:

byte0    byte1
dddddddd ddaaaaaa
|---------||----|
    data   output

The problem with this approach is that the Arduino will misinterpret messages that arrive in the wrong order. A message with reversed bytes:

byte0    byte1
ddaaaaaa dddddddd
|---------||----|
    data   output

will now be completely misinterpreted. To avoid this problem we will have to reserve two extra bits to tell the Arduino which byte to be interpreted first and which second. This still gives us 8 bits for the data, which I believe is good enough. The resulting protocol looks like this:

           byte0    byte1
          xxxxxxxx xxxxxxxx
bit nr:   76543210 76543210
byte0 id: 0
byte1 id:          1
address:   aaaaaa
data:            d  ddddddd

To encode the address(0..53) and the data(0..255) into the two bytes we need the following formula:

byte0 = 0<<7 | (address&0x3f) << 1 | (data>>7&0x01);
byte1 = 1<<7 | (data&0x7f);

To decode the bytes back into the original data, we will have to use byte0 and byte1.

address = inByte0>>1 & 0x3f;
data = (inByte0&0x01)<<7 | (inByte1&0x7f);

To decipher which is the first and which is the second byte, we will need a few extra lines of code:

// these variables are defined globally:
byte inByte0;
byte inByte1;

// inside void loop():
// the inByte comes from the Serial.read(), here left out.

byte address;
byte data;
// check if bit7 = 0. -> this is byte0, otherwise this is byte1
boolean isAddress = (inByte>>7 & 0x01) == 0; 

if (isAddress) {
  inByte0 = inByte;
} else { // is data
  inByte1 = inByte;
  // decompile message:
  address = inByte0>>1 & 0x3f;
  data = (inByte0&0x01)<<7 | (inByte1&0x7f);
  //todo: now we can do some stuff.. (PWM)
}

Generating PWM on all outputs

To generate PWM on all outputs, we will have to code that will always run in the background, ignoring the main loop() function. On the Arduino, we call these background routines interrupts.

This routine shall use a variable named cycle, that continuously increases from 0 to 255. We shall then compare this value with any of our pulseWidths and set our output HIGH if the cycle is 255 or cycle is smaller than pulseWidth and LOW if not.

To set the digital output10, we would usually write:

if (cycle==255 || cycle < pulseWidth[10]) digitalWrite(10,HIGH);
else digitalWrite(10,LOW);

The problem with this that we are using an array for the pulseWidths, which is slower than normal variables, and that we are using the digitalWrite command, which is actually a routine with more than 20 lines of code. This will surely take up too much of our precious processor time and result in very slow pulse width modulation.

Just take a look at the source code for digitalWrite() command:

void digitalWrite(uint8_t pin, uint8_t val)
{
        uint8_t timer = digitalPinToTimer(pin);
        uint8_t bit = digitalPinToBitMask(pin);
        uint8_t port = digitalPinToPort(pin);
        volatile uint8_t *out;

        if (port == NOT_A_PIN) return;

        // If the pin that support PWM output, we need to turn it off
        // before doing a digital write.
        if (timer != NOT_ON_TIMER) turnOffPWM(timer);

        out = portOutputRegister(port);

        if (val == LOW) {
                uint8_t oldSREG = SREG;
                cli();
                *out &= ~bit;
                SREG = oldSREG;
        } else {
                uint8_t oldSREG = SREG;
                cli();
                *out |= bit;
                SREG = oldSREG;
        }
}

Avoiding arrays – writing code in excel

Now instead of using an array for pulseWidths, I decided to use seperate variables. This of course will be a pain in the arse, since we have to use width0, width1, width2,.. width53. To avoid having to write loads of code, I created a formula in excel (OpenOffice calc) that would do the job for me. I can now use excel for generating initialisations, comparisons etc..

Avoiding digialWrite(): Port mapping

In the Arduino language we have the ability to manipulate digital outputs directly. This is called port manipulation. Here is a table for all Arduino Mega channels, derived from the chip image.

PORT	BIT							
	7	6	5	4	3	2	1	0
A	29	28	27	26	25	24	23	22
B	13	12	11	10	50	51	52	53
C	30	31	32	33	34	35	36	37
D	38	-	-	-	18	19	20	21
E	-	-	3	2	-	5	1	0
G	-	-	4	-	-	39	40	41
H	-	9	8	7	6	-	16	17
J	-	-	-	-	-	-	14	15
L	42	43	44	45	46	47	48	49

PinMap2560sma_

For example, to set output 27 to HIGH we just need to set bit 5 of port a to 1, to set output 23 to LOW, we just need to set bit 1 of port a to 0.

// set output 27 to HIGH (bit5 to 1):
PORTA |= B00100000;
// set output 23 to LOW (bit1 to 0):
PORTA &= B11111101;

The pwm code for channel 23 and 27 will now look like this:

if (cycle==255 || cycle < pulseWidth23) PORTA |= B00000010; else PORTA &= B11111101;
if (cycle==255 || cycle < pulseWidth27) PORTA |= B00100000; else PORTA &= B11011111;

Attached you will find the Arduino code, a Max/MSP test patch and the excel file that contains the entire Arduino Mega port table and the code generating list:

ArduinoMegaPWMArduinoMaxMspExcel

Posted in Arduino, Code, Research | Tagged | Comments Off

Creating neurons – desynchronized activity

Toying with neural networks can be quite a painstaking process, especially when trying to use these within an artistic context. Usually you end up frying your brains with the overload of mathematics. To counter this, I am trying a totally new approach:

I will look at the brain from a more physical point of view: Neurons, axons, synapses, etc.. What I would like to achieve is the possibility to simulate for instance drug intake into a virtual brain.

What has always bothered me about neural networks, is the way in which electric impulses are synchronized. To counter this, I will aim to simulate each neuron by using physical properties. In this first test, electrical impulses are travelling down the axon, thus arriving at different times at different neurons. Another side-effect is that I can create some nice visualizations.

Firing axons:

And here some dendrites receiving impulses that are travelling towards the nucleus.

Posted in Uncategorized | Tagged , , , | Comments Off

Drawing pixels with javascript: An animated voronoi

For about 20 years I have managed to avoid javascript for interactive and animated content. So far I have used flash, director and java. But now with the coming of HTML5, I am starting to like this (old) option. Desktops are fast enough to render javascripts directly to screen.

The example uses Canvas and the getContext() method. Here we see 350 x 350 = 122500 pixels being calculated on every frame. The pixels are coloured depending on their distance to the moving points. The result is an animated Voronoi.

Feel free to play with the settings below the animation. The source javascript is also available for download.


Voronoi2Preview
Your browser does not support the HTML5 canvas tag.


Posted in Research, Uncategorized | Tagged , , | Comments Off