Code Monkey home page Code Monkey logo

Comments (7)

neophob avatar neophob commented on August 20, 2024

Hmm well PixelController already works with the Rainbowduino v3. However it looks like your Rainbowduino board is crashing.

Can you replace the board to make sure its not a HW issue?

While you was editing the wire and twi files, you Arduino IDE was closed?

What Arduino version do you use?

Try to replace the USB cable (maybe with a shorter one)

What happens if you don't power up your DIY LED Matrix (only the Rainbowduino board)?

from pixelcontroller.

devinejohnny avatar devinejohnny commented on August 20, 2024

Thanks for the response and suggestions.

I have another v3.0b board, so I swapped it out and tried again. The result was the same.

When I edited the .h files Arduino IDE was closed. I just checked both files to make sure the changes were in place, then relaunched the IDE, uploaded the firmware, and opened PixelController. The issue is still present.

I'm using Arduino 1.0.5 on both my Mac and PC.

I unplugged my matrix from the Rainbowduino and launched PixelController. The issue is still present (both the TX and RX lights on the Rainbowduino will flash for a couple seconds, then the TX turns off, but the RX continues to blink).

The last thing for me to try is the new cable. I'm using a 3 foot cable right now, but I'll go buy some other options and report back.

Thanks for the help so far!

from pixelcontroller.

devinejohnny avatar devinejohnny commented on August 20, 2024

I've tried two new cables (thicker 6 foot cable and a different 3 foot cable) on both Rainbowduinos with the same result.

I uninstalled my Arduino IDE and re-downloaded it. I made the changes to wire.h and twi.h files before launching it. I reloaded the firmware on my Rainbowduino, but am still getting the crash.

Am I using the correct firmware:

/*
Rainbowduino V3 firmware capable of streaming 24bit RGB frames with up
to 35fps via the USB connector of the Rainbowduino V3 controller.

Author: Markus Lang ([email protected])
Websites: http://programmers-pain.de/
https://code.google.com/p/rainbowduino-v3-streaming-firmware/

This firmware is based on several Rainbowduino related firmwares like:
neorainbowduino: http://code.google.com/p/neorainbowduino/
rainbowdash: http://code.google.com/p/rainbowdash/
seeedstudio.com: http://www.seeedstudio.com/wiki/Rainbowduino_v3.0

The Java part splits a full 8x8 RGB frame (3 colors * 64 LEDs = 192byte)
into four frame fragments (each 48byte) to get around the 64byte default
buffer size of the Arduino hardware serial implementation. Each fragment
will be extended with the HEADER bits and a frame fragment index to
be able to reconstruct the full frame in the correct order inside this
firmware.

Splitting up the frame into fragments avoids running into data corruption
/ data loss if the Java part sends more bytes than the Arduino controller
can buffer. For every frame fragment the controller will send an ACK REPLY
message to the Java code so that the next fragment will be send.

The firmware is able to handle incomplete frames as well as CRC checksum
errors of the transferred LED color data so that it's able to signal those
error conditions to the Java API.

The LED update routine of this firmware is just a rewrite of the original
seeedstudio.com firmware (http://www.seeedstudio.com/wiki/Rainbowduino_v3.0)
including some changes regarding the interrupt handling to allow the
controller to update the LEDs and receiving incoming serial data at the
same time.
*/

// ports and bit values needed by the LED update routine
#define DDR_DATA DDRB
#define DDR_CLK DDRB
#define DDR_LINES DDRD
#define PORT_DATA PORTB
#define PORT_CLK PORTB
#define PORT_LINES PORTD
#define BIT_DATA 0x01
#define BIT_CLK 0x02
#define BIT_LINES 0xF0

// general const variables
const unsigned char RAINBOWDUINO_LEDS = 64;
const unsigned char NUMBER_OF_COLORS = 3;
const unsigned char RED = 0;
const unsigned char GREEN = 1;
const unsigned char BLUE = 2;
const unsigned char NUMBER_OF_FRAME_FRAGMENTS = 4;
const int FRAME_FRAGMENT_LENGTH = ((RAINBOWDUINO_LEDS / NUMBER_OF_FRAME_FRAGMENTS) * NUMBER_OF_COLORS);

// serial protocol related const variables
const long BAUD_RATE = 115200;
const unsigned char HEADER_LENGTH = 3;
const unsigned char ACK_REPLY_LENGTH = 4;
const byte HEADER = 0x10;
const byte FRAME_FRAGMENTS[NUMBER_OF_FRAME_FRAGMENTS] = {0x20, 0x21, 0x22, 0x23};
// serial protocol state codes
const byte STATE_ACK = 0x30;
const byte STATE_FRAME_FRAGMENT_INDEX = 0x31;
const byte STATE_INCOMPLETE_FRAME = 0x32;

// byte array used to send back ack replies
// (HEAHDER, 2 bytes for returned value, ERROR CODE)
byte ackReply[ACK_REPLY_LENGTH] = {HEADER, 0, 0, 0};

// byte array used as frame buffers for the currently received and displayed frame
// (2 buffers, RGB colors, 8 rows, 8 columns)
unsigned char frameBuffers[2][NUMBER_OF_COLORS][8][8];
// the currently used frame buffer by the LED update routine
volatile unsigned char currentFrameBuffer;
// the current line the LED update routine will push color data for
volatile unsigned char currentLine;

// global variables used to parse the incoming serial data
byte serialData; // stores the currently parsed byte
unsigned char headerCounter; // counts the number of found HEADER bytes
int frameFragmentPos; // the relative position in the currently parsed frame fragment
int frameFragmentPosOffset; // the offset to the relative position of the currently parsed frame fragment
int frameFragmentIndex; // the index of the currently parsed frame fragment
int crc; // used to calculate the frame fragment crc value
unsigned char currentColor; // used to store the current color index
unsigned char currentRow; // used to store the current row index
unsigned char currentColumn; // used to store the current column index

void setup() {
// initialize global variables used to update the LEDs
currentFrameBuffer = 0;
currentLine = 0;
// initialize global variables used to parse the incoming serial data
headerCounter = 0;
frameFragmentPos = -1;
frameFragmentPosOffset = -1;
frameFragmentIndex = -1;
crc = 0;
currentColor = 0;
currentRow = 0;
currentColumn = 0;
// setup serial communication
Serial.begin(BAUD_RATE);
// initialize frame buffers array
for (unsigned char buffer = 0; buffer < 2; buffer++) {
for (unsigned char color = 0; color < NUMBER_OF_COLORS; color++) {
for (unsigned char row = 0; row < 8; row++) {
for (unsigned char column = 0; column < 8; column++) {
frameBuffers[buffer][color][row][column] = 0;
}
}
}
}
// disable all internal interrupts
cli();
// initialize LED update routine and MY9221 state
DDR_LINES |= BIT_LINES;
PORT_LINES &= ~BIT_LINES;
DDRD |= 0x04;
DDR_DATA |= BIT_DATA;
DDR_CLK |= BIT_CLK;
PORT_DATA &= ~BIT_DATA;
PORT_CLK &= ~BIT_CLK;
DDRB |= 0x20;
// clear the display to get a clean state
clearDisplay();
// init TIMER 1 (trigger every ~1250us)
TCCR1A = 0;
TCCR1B = _BV(WGM13);
ICR1 = 10000;
TIMSK1 = _BV(TOIE1);
TCNT1 = 0;
TCCR1B |= _BV(CS10);
// re-enable all internal interrupts
sei();
}

void loop() {
// check for available serial data and start parsing after the HEADER bytes have been found
while (Serial.available() > 0) {
serialData = Serial.read();
// count the number of header bytes if we're not parsing a frame fragment right now
if (frameFragmentPos == -1) {
if (serialData == HEADER) {
headerCounter++;
// check if we've counted two HEADER bytes
if (headerCounter == 2) {
// set the frame fragment position and start the parsing
frameFragmentPos = 0;
headerCounter = 0;
}
} else {
headerCounter = 0;
}
continue;
}

// check if we need to resolve the frame fragment index
if (frameFragmentPos == 0 && frameFragmentIndex == -1) {
  for (unsigned char i = 0; i < NUMBER_OF_FRAME_FRAGMENTS; i++) {
    if (serialData == FRAME_FRAGMENTS[i]) {
      frameFragmentIndex = i;
      frameFragmentPosOffset = frameFragmentIndex * FRAME_FRAGMENT_LENGTH;
      break;
    }
  }
  // throw an error in case we couldn't parse the frame fragment index
  if (frameFragmentIndex == -1) {
    sendAckReply(STATE_FRAME_FRAGMENT_INDEX, serialData);
  }
  // throw an error in case the frame fragment index doesn't match the 
  // currentRow counter which indicates that we haven't received the 
  // frame fragments in the correct order. that can happen if you reset
  // the controller manually or if a frame fragment was lost during
  // transfer. therefore we'll skip the just received frame index incl.
  //  it's frame data.
  if (frameFragmentIndex * 2 != currentRow) {
    sendAckReply(STATE_INCOMPLETE_FRAME, frameFragmentIndex);
  }
  continue;        
}

// store the received byte in the frame buffer and calculate the crc value
if (frameFragmentPos != -1 && frameFragmentPos < FRAME_FRAGMENT_LENGTH) {
  // store received color value in the currently used framebuffer
  int framePos = frameFragmentPosOffset + frameFragmentPos;
  int frameBufferPos = framePos / NUMBER_OF_COLORS;
  frameBuffers[currentFrameBuffer][currentColor][currentRow][currentColumn] = serialData;
  // reset currentColor pointer if a complete color cycle is done
  currentColor++;
  if (currentColor == NUMBER_OF_COLORS) {
    currentColor = 0;
    currentColumn++;
    // reset currentColumn pointer if a complete row is done
    if (currentColumn == 8) {
      currentColumn = 0;
      currentRow++;
      // reset currentRow pointer if a complete row cycle is done
      if (currentRow == 8) {
        currentRow = 0;
      }
    }
  }
  // calculate crc value for the currently parsed frame fragment
  crc = crc + serialData;
  // increment the frame fragment position
  frameFragmentPos++;
}

// check if we've parsed all bytes of the current frame fragment
if (frameFragmentPos == FRAME_FRAGMENT_LENGTH) {
  // switch the currently used frame buffer if we've received the last frame fragment
  if (frameFragmentIndex == NUMBER_OF_FRAME_FRAGMENTS) {
    currentFrameBuffer = !currentFrameBuffer;
    // reset global variables that have been in use to parse the whole frame
    currentRow = 0;
    currentColumn = 0;
  }
  // let the java code know that we've parse an entire frame fragment
  sendAckReply(STATE_ACK, crc);
}

}
}

// send the ack reply message to the serial interface and reset the global parsing variables
void sendAckReply(byte stateCode, int value) {
// update ack reply array
ackReply[1] = value >> 8;
ackReply[2] = value;
ackReply[3] = stateCode;
// send ack reply message
Serial.write(ackReply, ACK_REPLY_LENGTH);
Serial.flush();
// reset global variables that have been in use to parse the frame fragment
frameFragmentPos = -1;
frameFragmentPosOffset = -1;
frameFragmentIndex = -1;
currentColor = 0;
crc = 0;
}

void send16BitData(unsigned int data) {
for (unsigned char i = 0; i < 16; i++) {
if (data & 0x8000) {
PORT_DATA |= BIT_DATA;
} else {
PORT_DATA &= ~BIT_DATA;
}
PORT_CLK ^= BIT_CLK;
data <<= 1;
}
}

void latchData() {
PORT_DATA &= ~BIT_DATA;
delayMicroseconds(10);
PORT_LINES &= ~0x80;
for (unsigned char i = 0; i < 8; i++) {
PORT_DATA ^= BIT_DATA;
}
}

void switchOnDrive(unsigned char line) {
PORT_LINES &= ~BIT_LINES;
PORT_LINES |= (line << 4);
PORT_LINES |= 0x80;
}

void clearData() {
PORT_DATA &= ~BIT_DATA;
for (unsigned char i = 0; i < 192; i++) {
PORT_CLK ^= BIT_CLK;
}
}

void clearDisplay() {
send16BitData(0);
clearData();
send16BitData(0);
clearData();
latchData();
}

ISR(TIMER1_OVF_vect) {
// re-enable global interrupts, this needs some explanation:
// ---------------------------------------------------------
// to allow the internal interrupt of the Arduino framework to handle
// incoming serial data we need to re-enable the global interrupts
// inside this interrupt call of the LED update routine.
// usually that's an stupid idea since the LED update rountine interrupt
// could also be called a second time while this interrupt call is still
// running - this would result in a hanging controller.
// since we know that the interrupt is called in a 1250us interval and
// the code in this method takes around ~650us to finish we still have
// enough buffer to allow the internal interrupt to handle incoming serial
// data without risking to block the controller. the time between the next
// LED update rountine call is also sufficient to give the controller
// enough time to parse the incoming serial data.
// this setup was the easiest way out of the problem that the internal
// interrupt and the interrupt of the LED update routine do otherwise
// result in major data loss and data corruption if we wouldn't re-enable
// the global interrupts here.
sei();
// determine the frame buffer row to be used for this interrupt call
unsigned char row = 7 - currentLine;
// clear the data of the former interrupt call to avoid flickering
clearDisplay();
// push data to the MY9221 ICs
send16BitData(0);
// push the blue color value of the current row
for (char column = 0; column < 8; column++) {
send16BitData(frameBuffers[currentFrameBuffer][BLUE][row][column]);
}
// push the green color value of the current row
for (char column = 0; column < 4; column++) {
send16BitData(frameBuffers[currentFrameBuffer][GREEN][row][column]);
}
send16BitData(0);
for (char column = 4; column < 8; column++) {
send16BitData(frameBuffers[currentFrameBuffer][GREEN][row][column]);
}
// push the red color value of the current row
for (char column = 0; column < 8; column++) {
send16BitData(frameBuffers[currentFrameBuffer][RED][row][column]);
}
// since the following code is timing-sensitive we have to disable
// the global interrupts again to avoid ghosting / flickering of
// the other lines that shouldn't be active at all.
cli();
latchData();
// activate current line
switchOnDrive(currentLine);
PORTD &= ~0x04;
// increment current led row counter for the next interrupt call
currentLine++;
if (currentLine == 8) {
currentLine = 0;
}
}

from pixelcontroller.

devinejohnny avatar devinejohnny commented on August 20, 2024

I don't think there is a hardware issue. I bought the boards from different outlets (one from California, the other from Hong Kong) and they are both able to run my DIY LED matrix using the RainbowStudio and the example sketches from SeeedStudio.

from pixelcontroller.

devinejohnny avatar devinejohnny commented on August 20, 2024

Does my config file look ok?

Copyright (C) 2011-2013 Michael Vogt [email protected]

This file is part of PixelController.

PixelController is free software: you can redistribute it and/or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation, either version 3 of the License, or

(at your option) any later version.

PixelController is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.

You should have received a copy of the GNU General Public License

along with PixelController. If not, see http://www.gnu.org/licenses/.

#=========================
#default values for generators
#=========================
initial.image.simple=logo.gif
initial.blinken=torus.bml
initial.text=PIXELINVADERS

font.filename=04B_03__.TTF
font.size=82

#x/y offset for screen capturing generator
#if you define screen.capture.window.size.x as 0, the screen capture generator will be disabled
screen.capture.offset=100
screen.capture.window.size.x=0
#screen.capture.window.size.x=500
screen.capture.window.size.y=300

#=========================
#network port config
#=========================

#fudi protocol config, used to communicate with pure data sketch
net.listening.port=3448
net.listening.addr=127.0.0.1
net.send.port=3449

#osc protocol config
osc.listening.port=9876

#=========================
#frames per second
#=========================
fps=25

#=========================
#display internal gui window and debug buffer?
#=========================
show.debug.window=true
maximal.debug.window.xsize=600

#=========================
#per default you get # of output windows + 1 visuals
#maybe you need more, so add them here if you want...
#=========================
additional.visual.screens=0

#=========================
#the size of the software output matrix
#=========================
led.pixel.size=20

#=========================
#start in random mode?
#=========================
startup.in.randommode=false

#=========================
#load a preset if PixelController starts?
#Warning, this will overwrite your settings configured above (initial generator values)!
#=========================
#startup.load.preset.nr=1

#=========================
#use audio as input setting (true)
#or just regular fps (false)
#=========================
update.generators.by.sound=true

### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###

OUTPUT SETTINGS

enable only ONE output device (PixelInvaders, RainbowduinoV2, RainbowduinoV3, Art-Net, TPM2, UDP, Adafruit or Minidmx)

### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###

#=========================

optional, defines the color order of the output device

this option is used for ALL output devices, if you have multiple panels you must define

multiple entries, for example if you have 3 panels you need to define "BRG,BRG,BRG"

if this setting is commented out, RGB color order is assumed for all panels

#=========================
#panel.color.order=RGB

#=========================

Apply gamma correction for output panels

Valid options

- NONE

- GAMMA_20: apply gamma 2.0 correction

- GAMMA_25: apply gamma 2.5 correction

- SPECIAL1: apply special gamma correction

#=========================
panel.gamma.tab=GAMMA_25

#=========================

Settings for PixelInvaders panels, valid options:

#=========================

NO_ROTATE,

ROTATE_90,

ROTATE_90_FLIPPEDY,

ROTATE_180,

ROTATE_180_FLIPPEDY,

ROTATE_270,

#=========================
#HINT: you define how many PixelInvaders panels are in use, in this example we use four panels.
#pixelinvaders.layout.row1=NO_ROTATE,NO_ROTATE
#pixelinvaders.layout.row2=NO_ROTATE,NO_ROTATE

#do not try this device for autodetection
#pixelinvaders.blacklist.devices=/dev/ttyUSB000

#if you have multiple pixelinvaders panels wired up special, you can define this here.
#if you don't define this setting, the "default wiring" is expected
#example (the number define the wiring direction):

+---+---+---+

| 0 | 3 | 4 |

+---+---+---+

| 1 | 2 | 5 |

+---+---+---+

#HINT: the first panel is 0!
#pixelinvaders.panel.order=0,3,4,1,2,5

#pixelinvaders.panel.ip=192.168.111.22
#pixelinvaders.panel.port=5333

#=========================
#settings for null output
#=========================
#nulloutput.devices.row1=2
#nulloutput.devices.row2=0

#=========================
#settings for rainbowduinoV2
#=========================
#i2c destination address + layout definition
#layout.row1.i2c.addr=5,6
#layout.row2.i2c.addr=8,9

#=========================
#settings for rainbowduinoV3
#=========================
#serial device names + layout definition

on Linux/OSX use names like "/dev/ttyUSB1"

on Windows use names like "COM1"

This is for one of my boards:

#layout.row1.serial.devices=/dev/tty.usbserial-AD01W4YR

This is for my other board:

layout.row1.serial.devices=/dev/tty.usbserial-A901LS8Z
#layout.row2.serial.devices=/dev/ttyUSB2,/dev/ttyUSB3

#=========================
#settings for stealth panel
#=========================
#stealth.layout.row1=NO_ROTATE

#=========================
#settings for Art-Net, Null output, Minidmx, UDP, TPM2 and Adavision
#=========================
#output.resolution.x=8
#output.resolution.y=8

#flip each second scanline
#output.snake.cabling=true

#OR use manual image mapping, instead of the snake cabling setting.
#the output mapping table should contain output.resolution.x * output.resolution.y entries
#REMEMBER: the first outputs starts at 0 NOT 1!
#output.mapping=0,1,4,5,2,3...

#optional rotate image, valid options:

NO_ROTATE (default),

ROTATE_90,

ROTATE_90_FLIPPEDY,

ROTATE_180,

ROTATE_180_FLIPPEDY,

ROTATE_270

#output.layout=NO_ROTATE

#=========================
#settings for Art-Net
#Info: PixelController supports more than 1 universe
#do NOT FORGET to define the output resolution above!
#=========================
#artnet.ip=192.168.1.2

#define how many rgb pixels are used on a universe, maximal 170 (=510 Channels)
#artnet.pixels.per.universe=170

#define the first universe id
#artnet.first.universe.id=1

#=========================
#settings for udp "device"
#do NOT FORGET to define the output resolution above!
#=========================
#send to this address
#udp.ip=192.168.111.25
#udp.port=6803

#=========================
#settings for tpm2 device
#do NOT FORGET to define the output resolution above!
#=========================
#Where is the TPM2 device connected?

on Linux/OSX use names like "/dev/ttyUSB1"

on Windows use names like "COM1"

#tpm2.device=/whatever/youwant
#tpm2.baudrate=115200

#=========================
#settings for tpm2.net device
#do NOT FORGET to define the output resolution above!
#=========================
#tpm2net.ip=192.168.111.25

#define layout, valid options:

NO_ROTATE (default),

ROTATE_90,

ROTATE_90_FLIPPEDY,

ROTATE_180,

ROTATE_180_FLIPPEDY,

ROTATE_270

#HINT: you define how many Tpm2Net panels are in use, in this example we use four panels.
#tpm2net.layout.row1=NO_ROTATE,NO_ROTATE
#tpm2net.layout.row2=NO_ROTATE,NO_ROTATE

#=========================
#settings for miniDmx (like the SEDU board)
#do NOT FORGET to define the output resolution above!
#=========================
#minidmx.baudrate=115200

#=========================
#settings for adavision
#do NOT FORGET to define the output resolution above!
#=========================
#define serial port

on Linux/OSX use names like "/dev/ttyUSB1"

on Windows use names like "COM1"

#adavision.serial.port=/dev/tty.Whatever

#optional: define serial speed
#adavision.baudrate=115200

#EOF

from pixelcontroller.

devinejohnny avatar devinejohnny commented on August 20, 2024

Ok! Sorry about that blast of info. I think I have it working stably now.

In the firmware I changed this line:
const unsigned char ACK_REPLY_LENGTH = 10;

The variable was set to 4 and I increased it to 6. That allowed it to work a little longer before crashing, but now that I've put it up to 10, my Rainbowduino seems to be running just fine.

Awesome! Thanks again for this great piece of software and extra thanks for sharing it with the world.

from pixelcontroller.

neophob avatar neophob commented on August 20, 2024

ok glad it works. Hint: you may increase that value to 60, as thats the usb buffer size.

from pixelcontroller.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.