I'm finally finished with the lightboard! <insert fanfare here>
And guess what?
ALL ports are fully functional! <insert epic rock music here>
Let me repeat that -
All ports work, each and every one of them.
That's nothing short of a miracle!
After a couple of months I've finally recreated the "blink" tutorial (...)
Now I'll just have to finish writing the lighting routine so I can hook this guy up to the motherboard!
Awesome!
Showing posts with label Arduino. Show all posts
Showing posts with label Arduino. Show all posts
Tuesday, April 16, 2013
Thursday, May 31, 2012
More pressing and blinking
I've decided to redesign the electronics inside the machine.
Basically, it's more trouble than it's worth having two different systems trying to handle the same thing - I'm talking about the serial communication between Arduino and Chipkit. It does work, but it's only a matter of time until it becomes unbearable sending information back and forth, not to mention the very limited RAM in the Arduino.
I'll most probably only use the Chipkit since it's got plenty of I/O, lots of RAM and overall a beefier MCU. After the converging of the boards I'll have to see how many inputs/outputs there are left, but most definitely I'll have a couple to spare. There will be some pretty nasty refactoring of the code thou...
I've also decided that I need to build a switchboard and a light board -
The switchboard will give me 64 switches instead of the old one with 32 inputs.
The new one will also feature cable connectors so that there's only two flat-cables to unplug instead of 32 independent ones. Much simpler and much less to keep track of. They will still be 64 independent switches and not a matrix, so each switch gets it's own connection. In theory I could matrix these switches to create 4096 (64*64) switches...
The lightboard gives me 96 independent digital outputs for lights.
The old MUX-shield I planned to use only gave me 48 outputs and for some reason I cannot explain - it does no longer work. I'm actually not sure if I've ever tested it in with the Chipkit (+3.3VDC vs +5VDC). Since it's an output board, each of these outputs could in turn trigger a MOSFET to turn on/off a series of lights, instead of just a single light. This board will also use two 50-port flat-cables for quick and easy disconnections. The two extra ports in each cable will be additional ground lines.
On top of that I will have a couple of PWM light-chains for the GI. PWM, pulse-width modulation, is basically a digital analog output that allows me to dim digital outputs by flickering them fast enough. Since I'll be using LED's for the GI I believe this is the only choice. With regular bulbs I figure I could use the analog outputs instead.
The best thing about these boards I'll be making (parts are ordered) is that I'll only trade 3 control pins for "any" number of inputs/outputs required. This means I could hook up another identical board to gain an additional 64/96 inputs/outputs. Sweet!
Basically, it's more trouble than it's worth having two different systems trying to handle the same thing - I'm talking about the serial communication between Arduino and Chipkit. It does work, but it's only a matter of time until it becomes unbearable sending information back and forth, not to mention the very limited RAM in the Arduino.
I'll most probably only use the Chipkit since it's got plenty of I/O, lots of RAM and overall a beefier MCU. After the converging of the boards I'll have to see how many inputs/outputs there are left, but most definitely I'll have a couple to spare. There will be some pretty nasty refactoring of the code thou...
I've also decided that I need to build a switchboard and a light board -
The switchboard will give me 64 switches instead of the old one with 32 inputs.
The new one will also feature cable connectors so that there's only two flat-cables to unplug instead of 32 independent ones. Much simpler and much less to keep track of. They will still be 64 independent switches and not a matrix, so each switch gets it's own connection. In theory I could matrix these switches to create 4096 (64*64) switches...
The lightboard gives me 96 independent digital outputs for lights.
The old MUX-shield I planned to use only gave me 48 outputs and for some reason I cannot explain - it does no longer work. I'm actually not sure if I've ever tested it in with the Chipkit (+3.3VDC vs +5VDC). Since it's an output board, each of these outputs could in turn trigger a MOSFET to turn on/off a series of lights, instead of just a single light. This board will also use two 50-port flat-cables for quick and easy disconnections. The two extra ports in each cable will be additional ground lines.
The main power output of the lightboard will be controlled via a relay, so no power is sent to the outputs unless it's told to by the MCU. Purely for safety, and not sure if needed - but I had a relay to spare. The increased number of outputs allows for much more lights, and that's a good thing!
The best thing about these boards I'll be making (parts are ordered) is that I'll only trade 3 control pins for "any" number of inputs/outputs required. This means I could hook up another identical board to gain an additional 64/96 inputs/outputs. Sweet!
Sunday, September 11, 2011
Motherboard revised
I did a little work on the motherboard, including adding the third soundboard, 3.3->5V converter and SD-card reader. Behold!
It has a certain "scrapyard challenge"-feel to it, but it will be hidden from view anyway. And - should it come to the point where it bothers me a whole lot, the schematics for all the boards I've used are open source and available online so I could easily order a circuitboard with all the components integrated.
Adding a second sound effects card really made a difference. I'd thought it would be more subtle but being able to have multiple effects playing alongside music really adds to the experience. This also means I can have longer spoken phrases during the game without losing music or effects while doing so.
![]() |
1) From left, going clockwise: Soundboards (2 sfx, 1 music), Arduino Mega2560, "display adapter" (3.3V to 5V converter), Chipkit Max32 + MUX shield, SD/MMC card reader. |
Adding a second sound effects card really made a difference. I'd thought it would be more subtle but being able to have multiple effects playing alongside music really adds to the experience. This also means I can have longer spoken phrases during the game without losing music or effects while doing so.
Monday, August 22, 2011
As David would have said - Ch-ch-ch-changes!
I've changed my mind... I will be using a SD card for animations.
It will also be used to store the highscore etc. The built in EEPROM has a "very" limited write/erase cycle so I figure I'd keep the internal memorycards intact and store everything on external cards to minimize the risk of my pinball machine breaking down during a tournament or whatnot.
The Chipkit 512 KB flash storage means around 120 frames of animation. That data is probably best used as common animation that needs to be readily available and the SD-card ones will be mode-specific graphics. With SPI the datarate is fast enough, and I figure I could use the natural pauses in the game to load new animations into RAM. The current game logic was actually already prepared for this so it would mean minimal changes and/or interruptions in gameplay.
I've also got basic serial communication between master (Arduino) and slave (Chipkit) going on, so the host can send "playMusic", "playAnimation" etc commands to the slave which will then perform them. I will probably do at least one rewrite of that library as time progress to further streamline the communication, but at the moment it works fine. It is prepared for (and is currently) sending batch jobs of commands, but it's uncertain if the final version will send single commands right away or batch them together for sending at the end of the frame. There are different benefits for both versions.
I've also refactored the code to work with two different boards:
Arduino - Switches, Solenoids, Game logic and SoundFX.
Chipkit - Display, Lights, SD card and Music
With the transition to the Chipkit, it unfortunately turned out that (most likely) the voltage difference from 5V to 3.3V does not allow the display to properly function. I've been in touch with the manufacturers of both the display and the Chipkit and we've come up with the same conclusion. So, I've ordered a 3.3->5V logic translator chip now which will hopefully solve the problem. Kind of a bummer, but it will be worth the extra effort for all the sweet improvements it offers.
The game logic ... Ah, the fun part!
The ruleset is shaping up quite nicely and as it seems to me - a nice adaptation of the original concept. When reading the rules I'm quite satisfied that the gameplay will be fun as well. I guess the hardest part will be actually finding sound and graphics for the game, but if all else fails, I will do them myself.
It will also be used to store the highscore etc. The built in EEPROM has a "very" limited write/erase cycle so I figure I'd keep the internal memorycards intact and store everything on external cards to minimize the risk of my pinball machine breaking down during a tournament or whatnot.
The Chipkit 512 KB flash storage means around 120 frames of animation. That data is probably best used as common animation that needs to be readily available and the SD-card ones will be mode-specific graphics. With SPI the datarate is fast enough, and I figure I could use the natural pauses in the game to load new animations into RAM. The current game logic was actually already prepared for this so it would mean minimal changes and/or interruptions in gameplay.
I've also got basic serial communication between master (Arduino) and slave (Chipkit) going on, so the host can send "playMusic", "playAnimation" etc commands to the slave which will then perform them. I will probably do at least one rewrite of that library as time progress to further streamline the communication, but at the moment it works fine. It is prepared for (and is currently) sending batch jobs of commands, but it's uncertain if the final version will send single commands right away or batch them together for sending at the end of the frame. There are different benefits for both versions.
I've also refactored the code to work with two different boards:
Arduino - Switches, Solenoids, Game logic and SoundFX.
Chipkit - Display, Lights, SD card and Music
With the transition to the Chipkit, it unfortunately turned out that (most likely) the voltage difference from 5V to 3.3V does not allow the display to properly function. I've been in touch with the manufacturers of both the display and the Chipkit and we've come up with the same conclusion. So, I've ordered a 3.3->5V logic translator chip now which will hopefully solve the problem. Kind of a bummer, but it will be worth the extra effort for all the sweet improvements it offers.
The game logic ... Ah, the fun part!
The ruleset is shaping up quite nicely and as it seems to me - a nice adaptation of the original concept. When reading the rules I'm quite satisfied that the gameplay will be fun as well. I guess the hardest part will be actually finding sound and graphics for the game, but if all else fails, I will do them myself.
Wednesday, August 17, 2011
Max32 + Mega2560 = Superpin!
The main bottleneck at this moment is the RAM, as I said earlier. With the Mega2560 I got 8KB of RAM, which gives me around 1 display buffer with 8 colors (´a 4096 bytes). Sure, I could do some voodoo magic to get it working, but it will be very slow to perform any writing to the buffer. With all this extra overhead the 16MHz will running at 100% just to keep up. In order to fully support doublebuffering I would like to have three buffers. One buffer that is sent with SPI to the display straight away, and two that are alternated and built "behind the scenes".
But...
I will be using BOTH boards, actually.
The Max32 will take care of the visuals (lights and display) and the Mega2560 will do solenoids, switches and game logic. Using all the available memory, this would give me around 800 KB to store data (ruleset and logic excluded) for animation - I could easily fit all the game animations there to eliminate the need for an external SD card.
The Max32 is also of more than 4x the MHz, 2x the flash and 16x the RAM!
With this extra card I've more than doubled the performance and the number of I/O pins, which will really come in handy!

1) Poor Man's Motherboard!
Sunday, August 14, 2011
Those buffers...
I found out that I can improve the speed of the display rendering with about 50%.
It's quite simple really.
Currently I'm checking every frame, after every color, after pixel on/off...
But my machine will not feature 60 fps full motion video. Heck, even cinemas don't have that. You can easily see that this is a large overhead with largely redundant information.
By extracting the draw buffer (front) from the videolayer (back) I can keep drawing the frontbuffer "no questions asked" at about 1 ms per color. All the screen updates, such as text and images, happens in the backbuffer and when say a certain interval has passed the buffers are swapped. Rinse and repeat.
The beauty about this is that I remove all the heavy checks from the draw routine and can spread out the work of building a frame over a "lot" of time. Every clock cycle is crucial in this build since the Arduino is a single core, single process type of MCU.
A quick example (numbers are guesstimates, since I have not coded the backbuffer part yet):
Before:
Single frame: 18 ms (drawing) + 20 ms (building) = 38 ms, gives around 26 fps if the frame would be recreated every frame, such as during a video scene. This is very low and flickering is noticeable. Normal case is around 52 fps if the frame is created only once and drawn many times.
Single frame: 8 ms (drawing) + 2 ms (building) = 10 ms, gives around 100 fps if video was created at about 15 frames/sec. I could easily limit the drawing to 70 Hz to further free up resources without being noticeable for the player. Time that they however will feel with the game being more responsive.
I can't believe I've missed this -
I've done this a million times before in regular graphics programming...
It's quite simple really.
Currently I'm checking every frame, after every color, after pixel on/off...
But my machine will not feature 60 fps full motion video. Heck, even cinemas don't have that. You can easily see that this is a large overhead with largely redundant information.
By extracting the draw buffer (front) from the videolayer (back) I can keep drawing the frontbuffer "no questions asked" at about 1 ms per color. All the screen updates, such as text and images, happens in the backbuffer and when say a certain interval has passed the buffers are swapped. Rinse and repeat.
The beauty about this is that I remove all the heavy checks from the draw routine and can spread out the work of building a frame over a "lot" of time. Every clock cycle is crucial in this build since the Arduino is a single core, single process type of MCU.
A quick example (numbers are guesstimates, since I have not coded the backbuffer part yet):
Before:
Single frame: 18 ms (drawing) + 20 ms (building) = 38 ms, gives around 26 fps if the frame would be recreated every frame, such as during a video scene. This is very low and flickering is noticeable. Normal case is around 52 fps if the frame is created only once and drawn many times.
Single frame: 8 ms (drawing) + 2 ms (building) = 10 ms, gives around 100 fps if video was created at about 15 frames/sec. I could easily limit the drawing to 70 Hz to further free up resources without being noticeable for the player. Time that they however will feel with the game being more responsive.
I can't believe I've missed this -
I've done this a million times before in regular graphics programming...
Saturday, August 13, 2011
Shades of Sanity
Heureka!
SPI is a godsend. Everything's forgiven!
The new code is approximately 2.5 x faster, which may not sound a lot - but that's what separates a boring or flickering display from a nice, crisp multicolor display. The main time thief is the "if ( *f++ >= lx)" part - the code runs at about 128 frames/sec with a fixed value instead of "b", so I figure it will be possible to further improve the code. For reference, old Williams games used 4+1 shades, newer Stern games use 16 shades. Considering the hardware used, I'm quite satisfied with the current performance.
SPI is a godsend. Everything's forgiven!
![]() |
1) 8 + 1 colors at 18.868 ms, about 52 frames/sec. |
Feel free to look upon and possible improve the code:
void writeDisplay()
{
/*
Write all shades in one go. (i.e around 2.3 ms per color)
*/
register byte x,y,lx,b;
register byte *f;
cli(); //Disable interrupts
for (lx=1; lx < DISPLAY_MAX_BRIGHTNESS+1;lx++) //repeat for each color/shade
{
f = &frame[0][0];
//row 1 -------------
bitClear(PORTF, 2); //set 4th bit of PORTF to LOW
for (x=0; x < 16; x++) //send full 128 bit row using SPI
{
if ( *f++ >= lx) b = B10000000; else b=0;
if ( *f++ >= lx) b |= B01000000;
if ( *f++ >= lx) b |= B00100000;
if ( *f++ >= lx) b |= B00010000;
if ( *f++ >= lx) b |= B00001000;
if ( *f++ >= lx) b |= B00000100;
if ( *f++ >= lx) b |= B00000010;
if ( *f++ >= lx) b |= B00000001;
SPI.transfer(b);
}
bitSet(PORTF, 2); //set 4th bit of PORTF to HIGH //Column latch
bitSet(PORTF, 4); //set 5th bit of PORTF to HIGH (mark first row)
bitClear(PORTF, 5); //set 6th bit of PORTF to LOW
bitClear(PORTF, 3); //set 4th bit of PORTF to LOW
bitSet(PORTF, 3); //set 4th bit of PORTF to HIGH
bitSet(PORTF, 5); //set 6th bit of PORTF to HIGH
//row 2-31 ------------
for (y=0; y < DISPLAY_MAX_ROWS-2; y++)
{
bitClear(PORTF, 2); //set 4th bit of PORTF to LOW
for (x=0; x < 16; x++) //send full 128 bit row using SPI
{
if ( *f++ >= lx) b = B10000000; else b=0;
if ( *f++ >= lx) b |= B01000000;
if ( *f++ >= lx) b |= B00100000;
if ( *f++ >= lx) b |= B00010000;
if ( *f++ >= lx) b |= B00001000;
if ( *f++ >= lx) b |= B00000100;
if ( *f++ >= lx) b |= B00000010;
if ( *f++ >= lx) b |= B00000001;
SPI.transfer(b);
}
bitSet(PORTF, 2); //set 4th bit of PORTF to HIGH //Column latch
bitClear(PORTF, 4); //set 5th bit of PORTF to LOW (the rest of the rows are not leading)
bitClear(PORTF, 5); //set 6th bit of PORTF to LOW
bitClear(PORTF, 3); //set 4th bit of PORTF to LOW
bitSet(PORTF, 3); //set 4th bit of PORTF to HIGH
bitSet(PORTF, 5); //set 6th bit of PORTF to HIGH
}
//row 32 ---------------
bitClear(PORTF, 2); //set 4th bit of PORTF to LOW
for (x=0; x < 15; x++) //send full 128 bit row using SPI
{
if ( *f++ >= lx) b = B10000000; else b=0;
if ( *f++ >= lx) b |= B01000000;
if ( *f++ >= lx) b |= B00100000;
if ( *f++ >= lx) b |= B00010000;
if ( *f++ >= lx) b |= B00001000;
if ( *f++ >= lx) b |= B00000100;
if ( *f++ >= lx) b |= B00000010;
if ( *f++ >= lx) b |= B00000001;
SPI.transfer(b);
}
if ( *f++ >= lx) b = B10000000; else b=0;
if ( *f++ >= lx) b |= B01000000;
if ( *f++ >= lx) b |= B00100000;
if ( *f++ >= lx) b |= B00010000;
if ( *f++ >= lx) b |= B00001000;
if ( *f++ >= lx) b |= B00000100;
if ( *f++ >= lx) b |= B00000010;
if ( *f >= lx) b |= B00000001;
SPI.transfer(b);
bitSet(PORTF, 2); //set 4th bit of PORTF to HIGH //Column latch
bitClear(PORTF, 4); //set 5th bit of PORTF to LOW (the rest of the rows are not leading)
bitClear(PORTF, 5); //set 6th bit of PORTF to LOW
bitClear(PORTF, 3); //set 4th bit of PORTF to LOW
bitSet(PORTF, 3); //set 4th bit of PORTF to HIGH
bitSet(PORTF, 5); //set 6th bit of PORTF to HIGH
} //End of color/shade
sei(); //enable interrupts.
bitClear(PORTF, 5); //set 6th bit of PORTF to LOW
}
void writeDisplay()
{
/*
Write all shades in one go. (i.e around 2.3 ms per color)
*/
register byte x,y,lx,b;
register byte *f;
cli(); //Disable interrupts
for (lx=1; lx < DISPLAY_MAX_BRIGHTNESS+1;lx++) //repeat for each color/shade
{
f = &frame[0][0];
//row 1 -------------
bitClear(PORTF, 2); //set 4th bit of PORTF to LOW
for (x=0; x < 16; x++) //send full 128 bit row using SPI
{
if ( *f++ >= lx) b = B10000000; else b=0;
if ( *f++ >= lx) b |= B01000000;
if ( *f++ >= lx) b |= B00100000;
if ( *f++ >= lx) b |= B00010000;
if ( *f++ >= lx) b |= B00001000;
if ( *f++ >= lx) b |= B00000100;
if ( *f++ >= lx) b |= B00000010;
if ( *f++ >= lx) b |= B00000001;
SPI.transfer(b);
}
bitSet(PORTF, 2); //set 4th bit of PORTF to HIGH //Column latch
bitSet(PORTF, 4); //set 5th bit of PORTF to HIGH (mark first row)
bitClear(PORTF, 5); //set 6th bit of PORTF to LOW
bitClear(PORTF, 3); //set 4th bit of PORTF to LOW
bitSet(PORTF, 3); //set 4th bit of PORTF to HIGH
bitSet(PORTF, 5); //set 6th bit of PORTF to HIGH
//row 2-31 ------------
for (y=0; y < DISPLAY_MAX_ROWS-2; y++)
{
bitClear(PORTF, 2); //set 4th bit of PORTF to LOW
for (x=0; x < 16; x++) //send full 128 bit row using SPI
{
if ( *f++ >= lx) b = B10000000; else b=0;
if ( *f++ >= lx) b |= B01000000;
if ( *f++ >= lx) b |= B00100000;
if ( *f++ >= lx) b |= B00010000;
if ( *f++ >= lx) b |= B00001000;
if ( *f++ >= lx) b |= B00000100;
if ( *f++ >= lx) b |= B00000010;
if ( *f++ >= lx) b |= B00000001;
SPI.transfer(b);
}
bitSet(PORTF, 2); //set 4th bit of PORTF to HIGH //Column latch
bitClear(PORTF, 4); //set 5th bit of PORTF to LOW (the rest of the rows are not leading)
bitClear(PORTF, 5); //set 6th bit of PORTF to LOW
bitClear(PORTF, 3); //set 4th bit of PORTF to LOW
bitSet(PORTF, 3); //set 4th bit of PORTF to HIGH
bitSet(PORTF, 5); //set 6th bit of PORTF to HIGH
}
//row 32 ---------------
bitClear(PORTF, 2); //set 4th bit of PORTF to LOW
for (x=0; x < 15; x++) //send full 128 bit row using SPI
{
if ( *f++ >= lx) b = B10000000; else b=0;
if ( *f++ >= lx) b |= B01000000;
if ( *f++ >= lx) b |= B00100000;
if ( *f++ >= lx) b |= B00010000;
if ( *f++ >= lx) b |= B00001000;
if ( *f++ >= lx) b |= B00000100;
if ( *f++ >= lx) b |= B00000010;
if ( *f++ >= lx) b |= B00000001;
SPI.transfer(b);
}
if ( *f++ >= lx) b = B10000000; else b=0;
if ( *f++ >= lx) b |= B01000000;
if ( *f++ >= lx) b |= B00100000;
if ( *f++ >= lx) b |= B00010000;
if ( *f++ >= lx) b |= B00001000;
if ( *f++ >= lx) b |= B00000100;
if ( *f++ >= lx) b |= B00000010;
if ( *f >= lx) b |= B00000001;
SPI.transfer(b);
bitSet(PORTF, 2); //set 4th bit of PORTF to HIGH //Column latch
bitClear(PORTF, 4); //set 5th bit of PORTF to LOW (the rest of the rows are not leading)
bitClear(PORTF, 5); //set 6th bit of PORTF to LOW
bitClear(PORTF, 3); //set 4th bit of PORTF to LOW
bitSet(PORTF, 3); //set 4th bit of PORTF to HIGH
bitSet(PORTF, 5); //set 6th bit of PORTF to HIGH
} //End of color/shade
sei(); //enable interrupts.
bitClear(PORTF, 5); //set 6th bit of PORTF to LOW
}
Friday, August 12, 2011
The new code...
My code is now full of commands similar to this:
*b = ((*b << 1) | (*p++ | layer)?1:0);
My head hurts...
*b = ((*b << 1) | (*p++ | layer)?1:0);
My head hurts...
Wednesday, August 10, 2011
Something shady's going on...
Sat down a couple of hours and got started on a multicolor display-routine - only to find out it didn't work. At all...
After extensive troubleshooting of what I believed to be was faulty cables, I've redone all the cables except the powercables in the machine. Now everything is nice and pluggable/unpluggable in a easy manner.
The problem wasn't in the cables however, but the cabling still needed some work.
When I tried a different version of the digitalWriteFast it, for some peculiar reason, broke the pins I was using so I tried plugging the display into another set. The refresh rate of the screen was becoming rather slow and at that time I didn't connect that those pins were not "accelerated" by digitalWriteFast.
Also - the new library was approximately 1.5 x slower than the old. Doh.
So anyway - I reverted to the old library and the old pins and now my code could do its work properly.
At the moment it can display 5 different "colors" (4 red + 1 black). The code that enables different shades is quite slow since it needs to check for different values and also draw the screen multiple times, so with 4 colors I'm pushing 'the little MCU that could' beyond its comfort zone.
I will do further testing with SPI enabled since I need to get the time needed for each update to a lot less than it is currently taking. It is currently updating a full 4+1 color frame at 19 ms, which is "really slow". I hope to get this down to under 1 ms, if possible...
After extensive troubleshooting of what I believed to be was faulty cables, I've redone all the cables except the powercables in the machine. Now everything is nice and pluggable/unpluggable in a easy manner.
The problem wasn't in the cables however, but the cabling still needed some work.
When I tried a different version of the digitalWriteFast it, for some peculiar reason, broke the pins I was using so I tried plugging the display into another set. The refresh rate of the screen was becoming rather slow and at that time I didn't connect that those pins were not "accelerated" by digitalWriteFast.
Also - the new library was approximately 1.5 x slower than the old. Doh.
So anyway - I reverted to the old library and the old pins and now my code could do its work properly.
![]() |
1) Multicolor display. Four different reds and one black layer. Here it's simply displaying f(y)=red, but any pixel can be any shade. |
I will do further testing with SPI enabled since I need to get the time needed for each update to a lot less than it is currently taking. It is currently updating a full 4+1 color frame at 19 ms, which is "really slow". I hope to get this down to under 1 ms, if possible...
Monday, August 1, 2011
Code changes
I've experienced that the Arduino seem to be slow sometimes, especially when writing values. So I did a little research and tested stuff on my own - and the Arduino is not slow. But the code is.
For instance:
Using regular digitalWrites, 2500 on/off cycles: 35764 microseconds.
Using digitalWriteFast, 2500 on/off cycles: 2614 microseconds.
The old code is almost 14 (!) times slower than the new code! Damn...
Of course, there are caveats. It requires the pin number AND state to be static and known at compile time. Most of us do this all the time anyway (const, #define etc) so it's not a big deal.
The syntaxes are similar, if not identical, too.
Old: digitalWrite(PINNR, STATE);
New: digitalWriteFast(PINNR, STATE);
The static STATE can be avoided by simply doing something similar to:
if (someState)
digitalWriteFast(PINNR, HIGH);
else
digitalWriteFast(PINNR, LOW);
So - If your are developing on Arduino, download the digitalWriteFast library before doing any coding! It's A LOT faster and doesn't require that much planning ahead. I've already begun converting my code (and redesigning it along the way) to gain the juicy speedup.
Disclaimer:
The numbers where taken from the top of my head so I don't remember the two last digits of each value, but the magnitude of the values are correct. With a 14x speedup, the last two digits are indeed the least significant values.
For instance:
Using regular digitalWrites, 2500 on/off cycles: 35764 microseconds.
Using digitalWriteFast, 2500 on/off cycles: 2614 microseconds.
The old code is almost 14 (!) times slower than the new code! Damn...
Of course, there are caveats. It requires the pin number AND state to be static and known at compile time. Most of us do this all the time anyway (const, #define etc) so it's not a big deal.
The syntaxes are similar, if not identical, too.
Old: digitalWrite(PINNR, STATE);
New: digitalWriteFast(PINNR, STATE);
The static STATE can be avoided by simply doing something similar to:
if (someState)
digitalWriteFast(PINNR, HIGH);
else
digitalWriteFast(PINNR, LOW);
So - If your are developing on Arduino, download the digitalWriteFast library before doing any coding! It's A LOT faster and doesn't require that much planning ahead. I've already begun converting my code (and redesigning it along the way) to gain the juicy speedup.
Disclaimer:
The numbers where taken from the top of my head so I don't remember the two last digits of each value, but the magnitude of the values are correct. With a 14x speedup, the last two digits are indeed the least significant values.
Tuesday, June 21, 2011
Dot Matrix Display
This should come in handy when the time comes....
Interfacing a real pinball DMD with Arduino.
And another about making DMD friendly graphics...
DMD Graphics with Flash.
Interfacing a real pinball DMD with Arduino.
And another about making DMD friendly graphics...
DMD Graphics with Flash.
Wednesday, March 2, 2011
Babysteps!
This, my fellow readers, is Pinball Mainframe version 0.0.1.
It's not much, but it's a start!
At the moment eight lights are connected to the Arduino via a shift register. All of them individually switchable and in the picture they are running a little "ye old Knight Rider" lighting show. My wiring and soldering look like crap, but it's called a development board for a reason...Ps. Using superbright LED's while prototyping is rather annoying.
It's not much, but it's a start!
At the moment eight lights are connected to the Arduino via a shift register. All of them individually switchable and in the picture they are running a little "ye old Knight Rider" lighting show. My wiring and soldering look like crap, but it's called a development board for a reason...
Saturday, February 12, 2011
Stand Alone
Yepp, I've pretty much decided that I will be creating the pinball for standalone use. The old plans with a PC-centered machine is now gone. I will use the PC while developing to read logs etc, but the final version will run on it's own. You can't argue with 3 sec boot time.
Arduino - you handsome beast!
But there's a little speed bump....
I'm think about using shift registers to control the lights instead of directly using the pins on Adruino. Why, you say? Simple reason: I want to be able to use multiball features!
The original plan was to use bitwise operations to get more inputs, based on the fact that a ball rarely (i.e never) touches multiple switches at the same time - like this:
Input:
1.................. to 16 = 16 inputs total
1 + 2 ........... to 16 = 16 + 15 inputs total
1 + 2 + 3 ..... to 16 = 16 + 15 + 14 inputs total
You get the picture.
But when using multiple balls it may be possible to hit multiple different targets at once - thus registering faulty hits with said method above. Not good.
So I got more or less a couple of options:
A) Get more Arduino units and let them do different tasks - one for input, one for output etc. They would be communicating internally via serial ports to exchange data.
This may be a feasible solution as it also gives me "dual core" capabilites, like not relying on a single loop for game features, simultaneous updates etc. But it's not very cheap.
Pro's: Dual cores, load balancing, dedicated tasks. Free's up system resources since a lot of the code can be moved to the other cpu.
Con's: Somewhat expensive.
B) Use shift registers for lights.
This allows me to get more lights by sacrificing a couple of pins to gain 8-16 more (depending on chip). The chips retain their status so I can fire&forget the lighting states and the chip will continue to do its thing on its own. It is also possible to link multiple shift registers together for additional ports WITHOUT using more pins on the Arduino itself. And the chip itself costs 1$. Sweet!
Pro's: Cheap.
Con's: Slightly more challenging to control lights. Ok, I lied. A lot more challenging. No load-balancing or dual cores.
Currently I'm leaning towards a second Arduino (possibly a smaller version even).
I think the current input/output requirements was around 95 outputs and 50 inputs.
So I need at least 40 more I/O's - unless the playfield changes.
And once I start adding graphics and sound, I'm not so sure one single Arduino will do the trick...
Arduino - you handsome beast!
But there's a little speed bump....
I'm think about using shift registers to control the lights instead of directly using the pins on Adruino. Why, you say? Simple reason: I want to be able to use multiball features!
The original plan was to use bitwise operations to get more inputs, based on the fact that a ball rarely (i.e never) touches multiple switches at the same time - like this:
Input:
1.................. to 16 = 16 inputs total
1 + 2 ........... to 16 = 16 + 15 inputs total
1 + 2 + 3 ..... to 16 = 16 + 15 + 14 inputs total
You get the picture.
But when using multiple balls it may be possible to hit multiple different targets at once - thus registering faulty hits with said method above. Not good.
So I got more or less a couple of options:
A) Get more Arduino units and let them do different tasks - one for input, one for output etc. They would be communicating internally via serial ports to exchange data.
This may be a feasible solution as it also gives me "dual core" capabilites, like not relying on a single loop for game features, simultaneous updates etc. But it's not very cheap.
Pro's: Dual cores, load balancing, dedicated tasks. Free's up system resources since a lot of the code can be moved to the other cpu.
Con's: Somewhat expensive.
B) Use shift registers for lights.
This allows me to get more lights by sacrificing a couple of pins to gain 8-16 more (depending on chip). The chips retain their status so I can fire&forget the lighting states and the chip will continue to do its thing on its own. It is also possible to link multiple shift registers together for additional ports WITHOUT using more pins on the Arduino itself. And the chip itself costs 1$. Sweet!
Pro's: Cheap.
Con's: Slightly more challenging to control lights. Ok, I lied. A lot more challenging. No load-balancing or dual cores.
Currently I'm leaning towards a second Arduino (possibly a smaller version even).
I think the current input/output requirements was around 95 outputs and 50 inputs.
So I need at least 40 more I/O's - unless the playfield changes.
And once I start adding graphics and sound, I'm not so sure one single Arduino will do the trick...
Thursday, February 10, 2011
Microcontroller!
Found the perfect microcontroller for my machine.
Meet the Arduino Mega 2560!
* USB driven (via serial), up to 54 I/O pins.
* Can operate in standalone mode (if needed in the future)
* Extensible (can support SD cards, MP3 etc)
But of course... 54 I/O ports won't get me very far, so I've ditched 7 ports in exchange for 48 more (by multiplexing outputs). A total of 115 digital I/O ports + 16 analog inputs.
Sweet!
Meet the Arduino Mega 2560!
* USB driven (via serial), up to 54 I/O pins.
* Can operate in standalone mode (if needed in the future)
* Extensible (can support SD cards, MP3 etc)
But of course... 54 I/O ports won't get me very far, so I've ditched 7 ports in exchange for 48 more (by multiplexing outputs). A total of 115 digital I/O ports + 16 analog inputs.
Sweet!
Subscribe to:
Posts (Atom)