Programmers' Pain
19Sep/1214

Finally! A working streaming firmware for my Rainbowduino V3 controllers

Two Rainbowduino V3 controllers running the 'rainbowduino-v3-streaming-firmware'

Two Rainbowduino V3 controllers running the ‘rainbowduino-v3-streaming-firmware’

It took a while but I’ve finally managed to get the firmware of my new Rainbowduino V3 controllers to a state that I can use them as part of my 512 RGB LED coffee table project. I’ve learnt a lot of new things about interrupt handling of AVR micro controllers that I didn’t want to learn at all and I went trough quite some frustrating weeks where I was very close to just throw those controllers into the trash. But luckily I’ve managed to get the firmware flying at the end. If you want to find out what obstacles I had to fight with, how it all works at the end and where you can find the Rainbowduino V3 firmware including the matching Java API than feel free to continue reading this blog post 🙂

The first firmware I’ve tried for my new Rainbowduino V3 controllers was the reference firmware offered by the manufacturer (seeedstudio.com) of the controller. The firmware works quite nice but it targets for standalone usage of the controller without any functionality to stream 8×8 RGB frames to the controller via an I2C link or the build-in USB connector. Since I’ve already used the neorainbowduino firmware for my Rainbowduino V2 controllers that were used for the first test assembly of my coffee table I was also familiar with sending those frames with the help of an Arduino Uno or Teensy controller via an I2C-link to the Rainbowduino controllers. Sadly the neorainbowduino firmware can’t be used for V3 controllers since seeedstudio.com has change the controllers hardware quite a lot. Also I did know from my initial tests that the I2C-link approach is limited to max. four Rainbowduino controllers per Teensy controller since otherwise those controllers will act as the bottleneck preventing the Java program from sending RGB frames at ~20fps. An Arduino Uno due to his even worse serial performance isn’t able to drive more than two Rainbowduino controllers at ~20fps. Therefore it was quite obvious for me to focus on the build-in USB connector of the Rainbowduino V3 controller since this would solve several problems for my use case:

The eight Rainbowduino V3 controller of my 512 RGB LED coffee table project

The eight Rainbowduino V3 controller of my 512 RGB LED coffee table project

  • Direct serial connection to every Rainbowduino V3 controller without having another controller like an Arduino Uno or Teensy in-line that will act as a bottleneck.
  • No need for an external power supply since each controller can be powered directly via the USB connection.
  • No additional wiring needed for the I2C-links or being able to upload the controllers firmware since both can be done via a single USB cable.

Actually there’s one drawback of using an USB connection compared to to an I2C-link: You won’t be able to directly daisy-chain those controllers any more since the USB plug will be in the way. Luckily this isn’t a problem for my project since I do use some self-build 34x34cm LED panels so that I have enough space for an USB plug attached to each of my controllers.

While searching a bit for Rainbowduino V3 firmwares that claim to be able to send RGB frames via an USB connection I only found the rainbowdash firmware which offers an operation mode called DirectMode that is able to send RGB frames via serial to the controllers. Sadly this only works up to a baudrate of 19200 until the firmware suffers from data corruption / data loss due to conflicting interrupts: the internal Arduino interrupt that is used to receive incoming serial data and the interrupt of the rewritten seeedstudio.com firmware used to drive the LEDs. Conclusion: I own eight new controllers but there wasn’t any firmware available to stream 24bit RGB frames with 8 bit per color channel to those Rainbowduino V3 controllers via the build-in USB connector. Therefore I’ve decided to start my own firmware trying to combine the features of the neorainbowduino and the original seeedstudio.com firmware. That was end of March – or in other words – five month ago.. I had no fucking clue in what kind of trouble I’ll put myself into..

So.. It’s mid-September in the meanwhile, I’ve learned things I didn’t want to learn, I’ve fought with issues I couldn’t imagine five month ago and I was quite frustrated sometimes.. but I’ve managed to get my Rainbowduino V3 firmware including the matching Java API up and running! I’ve called it rainbowduino-v3-streaming-firmware since it’s only feature is to receive RGB frames via a serial connection of the build-in USB connector. You can find it at https://code.google.com/p/rainbowduino-v3-streaming-firmware/ if you want to use it for your own projects.

A Rainbowduino V3 controller attached to one of my custom build LED panels

A Rainbowduino V3 controller attached to one of my custom build LED panels

How does it work?

The firmware expects four frame fragments to be send to the controller to be able to show one 8×8 24bit RGB frame. Splitting up the frame into four fragments is done to avoid running into data corruption / data loss as soon as the internal buffer of the Rainbowduino V3 controller runs full. It took a while to understand that the recent Arduino 1.0 update has reduced to buffer size from 128byte to 64byte although most of the blog and forum posts you’ll find in the net are talking about a 128byte serial buffer – but that’s a different story. Each frame fragment gets extended with a header and some checksums to be able to implement a reliable serial protocol including some proper error handling. Whenever a frame fragment was received an ACK reply message is send via the serial connection to the Java API. The firmware itself just holds two frames in memory: the one that is currently shown by the LEDs and the next one that is currently being received via serial. As soon as a full frame has been transferred the frame buffers do switch. Everything was held rather simple since the firmware should just accomplish a single job: Receiving 8×8 RGB frames and drive the LEDs with it.

The most painful problem I had to solve were those two conflicting interrupts I’ve mentioned earlier. In the beginning I could either decide to receive all frame fragments in a reliable way but suffering from ghosting / flickering effects at the same time since the timing while driving those RGB LEDs wasn’t reliable any more. This was caused by the serial interrupt stopping the LED update routine whenever serial data was received. The other option was to keep the timing of the LED update routine evenly but dealing with data corruption / data loss whenever the controller was busy with pushing color data to those LEDs. This problem kept me busy for several month and I’ve tried multiple things to get around it including some frustrating moments when you have to revert all of your code changes since your new idea on how to solve this problem didn’t turned out to work as expected.

At the end the solution to address this interrupt problem was to simply re-enable the global interrupts of the AVR micro controller inside of the just running LED update interrupt call. First this sounds like a stupid idea to allow a single threaded micro controller to again call interrupts although the currently running interrupt callback isn’t done yet – this kind of smells like an interrupt calling itself over and over again which will brick your controller. In my case there’s only the internal serial interrupt that is able to interrupt the LED update routine to be able to handle incoming serial data. This combined with the fact that the runtime behaviour of the LED update routine is very predictable since it only pushes one of the frame buffers to the driver ICs prevents the controller to run into interrupt loops. It took a while to figure out the best working timing and interrupt configuration but afterwards the LED update routine is only interrupted very shortly whenever the controller has to handle incoming serial data. The time between the next call of the update routine is still enough to parse the incoming serial data and store it in the frame buffer. Since the LED update routine is triggered every ~1250µs the controller also doesn’t have enough time to neither receive a full frame fragment nor parsing it completely so that there’s no risk to run into problems with the 64byte build-in serial buffer that would otherwise result in data corruption and data loss.

After fixing the interrupt problem the firmware is now able to run at up to 35 frames per second. Starting from ~38fps the timing between the Java API and the firmware gets wonky which results in lots of frame (fragments) being dropped by the firmware. Nevertheless 35fps should be more than enough for most usages. Also keep in mind that the internal refresh rate of the LEDs is close to ~100fps so that even if you stream frames with only 35fps to the controller the actual frame is pushed almost three times to the LEDs by the driver ICs. Therefore I’m currently not able to see any flickering at all while showing frames on the Rainbowduino V3 controllers. Another advantage is that this approach scales pretty good while using multiple Rainbowduino V3 controllers at the same time since even a single USB connection has more than enough speed to drive multiple controllers. I my case I even use all eight controllers directly attached to a single USB hub without any noticeable latencies of the USB connection. To not create any new bottlenecks in the Java API the RainbowduinoV3.java class was implemented in a thread-safe way so that more than one thread can drive multiple controllers at the same time.

Also I’ve tried to keep the Java third-party library dependencies down to a minimum so that you’re not forced to use bigger frameworks like Processing just to be able to send RGB frames to a Rainbowduino V3 controller. It only depends on the RXTX, Apache Commons Lang 3, and the Simple Logging Facade libraries. If you need more technical information on how to use my rainbowduino-v3-streaming-firmware than please consult the technical documentation available on the project homepage. I’ve also provided two simple examples on how to use the Java API of the firmware so that you should be able to get your controller running without writing a single line of code. Those examples are also able to drive more than one Rainbowduino V3 controller at the same time.

For my 512 RGB LED coffee table project this means that I can focus again on finishing the remaining hardware tasks of the table itself so that I finally will able to use it as a coffee table in the near future! I’ll keep you informed as soon as this happens 🙂

Comments (14) Trackbacks (0)
  1. This is awesome. I tried and failed at getting my own reliable streaming working with my rainbowduino so you’ve done better than me!
    I don’t suppose you have any documentation that states how your serial packets are constructed? I’d like to interface some PC-side streaming code I have from another non-rainbowduino RGB project with your firmware and am trying to work out how to construct the packets.

    • I don’t dare to call it a documentation but the main RainbowduinoV3.java class contains at the beginning some hints how the serial data is structured: http://code.google.com/p/rainbowduino-v3-streaming-firmware/source/browse/rv3sf_api/src/main/java/de/programmerspain/rv3sf/api/RainbowduinoV3.java

      Each 8×8 frame gets separated into four frame fragments where each fragment is 51bytes long: 2 header, 1 fragment index and 48 bytes for the RGB color values of 16 LEDs. For each received frame fragment the controller replies with a 4 byte long ACK message: 1 header, 2 CRC and an return code byte. The header and frame fragment bytes are declared als static variables inside the class. The return codes are defined in the http://code.google.com/p/rainbowduino-v3-streaming-firmware/source/browse/rv3sf_api/src/main/java/de/programmerspain/rv3sf/api/RainbowduinoV3StateEnum.java enum. Only after all four frame fragments have been received the Rainbowduinos firmware starts to switch the internal framebuffer to display the new frame. In case the order of the frame fragment indexes is wrong the whole received data is ignored until another frame fragment with the first index gets send.

      So it should not be to hard to drive the Rainbowduino code from other projects since there’s no RGB value conversion happening. It just int’s from 0-255 being send as a single byte to the controller alternating between the red, green and blue colors for the first LED, the second one, etc.

      I hope that makes it easier for you to get a starting point on how to drive the Rainbowduino code from your project. If not: Feel free to ask further questions 🙂

      • Hi Markus,

        Firstly thanks for the awesome firmware. I am trying to interface through C++ on a unix system. I am finding that sometimes when I get an error ack, or no ack at all the system falls down. Is there any recommend procedure for when this happens? Can the firmware be pushed in to a state of no recovery or can I encourage some kind of refresh?

        • Some more info: I have a little more success (although still encountering the rainbowduino crashing) playing around with the delays between sending fragments, and frames. I cannot infer from the firmware a minimum delay between fragments.

  2. Thanks Markus, very quick response! That seems to have fixed the issue. I will post my c-code up on my site when I am finished and link to you!

  3. Hi how are you? Thank you for your amazing work…
    I try to use your streaming firmware, but I’m facing some difficulties. Nothing too serious I think but I can’t find the solution on my own.
    I’m kinda a newbie on rainbowduino, I bought my first two rainbowduino V3 one month ago with rainbowcube that I soldered myself and I’m waiting for my two led matrix to arrive… I’ve tried RainbowDashboard and original firmware from seeedstudio it’s great but I want to test your firmware…

    No troubles at all to upload the firmware to rainbowduino via Arduino IDE but I’m not sure if I have installed the needed library, I download them and put them in /System/Library/Java/Extensions/ (I’m on OSX 10.8.4). When I try to launch rv3sf_api-0.2.jar or rv3sf_examples-0.2.jar nothing happen only a error message after 30s telling me that the App couldn’t be launch…

    I know I look like an idiot but I’m a newbie…

    • To be honest I don’t have any experience concerning Java development on a Mac. What I do know is that the rv3sf_api.jar is meant to be be used as part of a Java application that sends frames to the Rainbowdunio V3 controllers. The rv3sf_examples.jar file is such an ‘application’.

      To launch e.g. the de.programmerspain.rv3sf.examples.ColorChangerExample class of the rv3sf_examples.jar file you need to have both jars and the needed dependencies described on the project page (https://code.google.com/p/rainbowduino-v3-streaming-firmware/#Compile_/_Runtime_Dependencies) in your classpath. Than the example class should launch an feed the controller with a changing color every second.

      In general is the firmware and the matching Java API meant to be used as part of a bigger software that’ll feed the Java API and therefore also the controller with external produced frames. So that’s the reason why there is no sample standalone-usage example that you can launch with a single click. But the description on the project page should help you getting the needed external dependencies to be able to call a JVM to run the provided simple examples.

  4. Sorry for my late answer and thank you for your quick answer 🙂

    I think you’re not using windows so the only last option is linux… It’s not a problem, I can emulate Ubuntu when I want…

    Actually I understand how it’s works, but I just don’t know how to install the needed dependencies on OsX or Linux. My knowledge of Java is equal to 0…

    I forgot to tell you, I’m French and there is no translate for classpath in French ;-(

    • If I got you right you actually try to ‘install’ the classpath dependencies somehow into your system. This will not work. The classpath (http://en.wikipedia.org/wiki/Classpath_%28Java%29) is the parameter of the Java VM that tells the VM where to find it’s classes to launch which includes in this case also the needed dependencies documented on the projects homepage. So it’s basically a directory where you’ll point your Java VM to to load the clases from the JAR files in that directory – but this is nothing you have to install somehow in your system.

      So to get the examples of my firmware running create an empty directory, put the JARs of the API and the examples into it including the external dependencies listed on the project homepage. Than start a Java VM using the ‘java’ binary of your Java installation and us the -cp parameter to specify your new directory as the to be used classpath. After that you only have to add the to be launched class to the ‘java’ binary call which could be the ‘de.programmerspain.rv3sf.examples.ColorChangerExample’ class of my examples JAR file.

  5. Markus – with the rainbowduino using multiplexing, does that mean that each LED in the 8×8 grid is limited to 1/64th of its iMax?

    Ideally, I’d like to build something using RGB LEDs and be able to set the PWM duty cycle to 100% and have the current equal the iMax of the LED. This is do-able with the TLC5490, but as you said, it becomes difficult to daisy chain large numbers of TLC5940’s.

    I’m curious if the tradeoff with the rainbowduinos is much-reduced max current.

    Thanks,
    -Cameron

    • A Rainbowduino controller drives an LED array line by line meaning that all eight LEDs of a row are powered whereas the LEDs of the other seven rows aren’t powered. So ignoring all the time needed to cycle through the rows a Rainbowduino controller should be able to get 1/8th out of each LED. Quite a while ago I’ve read some posts about how to explicitly drive an LED array with more than the specified maximum current due to the fact they aren’t operated at 100%. Of cause this is some kind of a gamble between driving LEDs outside their specs and a possible risk to destroy them – especially if the controller drives a LED row longer than it should. I’ve never tried this with a Rainbowduino controller nor do I know if it’s even possible to change to current output at all.

  6. now ive make some progress with your help of documentation on google.but i still have some problems that my system is not stable.
    ive downloaded your java file and transformed them into processing lib file.
    in processing i setup like this
    GammaTable gammaTable = new GammaTable();
    rainbowduinoV3 = new RainbowduinoV3(“COM5”, gammaTable);
    and it run very well.
    but when i use
    void draw(){
    rainbowduinoV3.sendFrame(frame);
    }
    it sometimes with no response.and if i disconnect the usb and then connect again,it will work a few more times.
    any ideas?
    the list of my jar file
    commons-lang3-3.1.jar
    RXTXcomm-2.2pre5.jar
    slf4j-api-1.6.3.jar
    log4j-1.2.16.jar


Leave a comment

Connect with Facebook

No trackbacks yet.