Apparent problem w/ no SRAM but not [SOLVED]

Sorry for the cryptic title but the dang thing isn't long enough to really state my problem.

I've been try for the past two days to write a pair of sketches that will let me control 6 RGB led matrix's based on the Rainbowduino from Seeed Studio, but right now I'm just trying to get one to play nice.

I've had to do a number of things to the base code in order to be able to send 97 bytes of data (command byte followed by 96 bytes of RGB pixel/led data) to a rainbow. For starters, the Wire Library does not support more than 32 bytes transmitted in a beginTransmission/send/endTransmission session. To fix that problem, I've set up a special send function on the master arduino and tinkered with the onRecieve on the slave rainbow so that the data can be send in multiple sessions and recomposed on the other side.

The problem is I appear to be getting garbled data introduced in to the command array (RainbowCMD[97]) that would normally point to running out of SRAM but this isn't the case. I've set up a stripped down version of my code that Serial.prints the RainbowCMD array before and after the SendCMD function and the data comes out just fine. During the send the first two sessions of 32 bytes are fine, but the third block A) isn't long enough and B) is full or garbage that isn't what it's supposed to be. The final session, which is only a byte, isn't right either.

Here is the Master side code:

#include <Wire.h>
#define waitingcmd 0x00
#define morecmd 0x01
#define processing 0x02
#define checking 0x03

#define transcmd 0x10
#define checkslavestate 0x11
#define slavedone 0x12

unsigned char RainbowCMD[97]={
'F',
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,

0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,

0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
unsigned char State= transcmd;
unsigned char slavestate= waitingcmd;
unsigned long timeout;

void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600);
delay(2000);
}

void loop()
{
int i;
for (i=0;i<97;i++){
Serial.print(RainbowCMD*,HEX);*

  • }*

  • Serial.println();*

  • SendCMD(4);*

  • delay(1000);*

  • for (i=0;i<97;i++){*
    _ Serial.print(RainbowCMD*,HEX);_
    _
    }_
    _
    Serial.println();_
    _
    delay(1000);_
    _
    }_
    _
    //--------------------------------------------------------------------------_
    _
    //Name:SendCMD*_
    //function: Send a 5 or 97 byte Rainbow command/frame out
    *//parameter: address *
    //----------------------------------------------------------------------------
    void SendCMD(int Add)
    *{ *
    * unsigned char OK=0;*
    * unsigned char i;*
    * char transnumber;*
    * unsigned char startnumber=0;*
    * unsigned char cmdsession=0;*
    * while(!OK) //cycle until slave transmits it's done*
    * { *
    * switch (State)*
    * { *
    * case transcmd: //transmit up to 32 bytes*
    * switch (RainbowCMD[0]){ //if the data is a command*
    * case 'R':*
    * transnumber =5; //only transmit the 5 bytes*
    * break;*
    * case 'F': //if it's a frame*
    _ transnumber=sizeof(RainbowCMD)-(32cmdsession); //find how many untransmitted bytes there are_
    _
    transnumber= min(32,transnumber); //make sure it's less than 32*_
    * Serial.println();*
    * Serial.print(startnumber,DEC);*
    * Serial.print(' ');*
    * Serial.print(transnumber,DEC);*
    * Serial.print(' ');*
    * Serial.print(cmdsession,DEC);*
    * Serial.print(' ');*
    * delay(1000);*
    * break;*
    * }*
    * if (transnumber>0){ //if ther are bytes to send*
    * Wire.beginTransmission(Add); //start*
    * for (i=startnumber;i<(startnumber+transnumber);i++){*
    _ Wire.send(RainbowCMD[(i+(32cmdsession))]);
    Serial.print(RainbowCMD[(i+(32
    cmdsession))],HEX);_

    * }*
    * Wire.endTransmission();*
    * delay(1000);*
    * }*
    * State=checkslavestate;*
    * break;*
    * case checkslavestate:*
    * Wire.requestFrom(Add,1); *
    * if (Wire.available()>0)*
    * slavestate=Wire.receive(); *
    * else {*
    * slavestate =0xFF;*
    * timeout++;*
    * }*
    * switch (slavestate){*
    * case morecmd:*
    * cmdsession++;*
    * startnumber= startnumber+32;*
    * State= transcmd;*
    * break;*
    * case processing:*
    * State=slavedone;*
    * break;*
    * case checking:*
    * State=slavedone;*
    * break;*
    * default:*
    * State=transcmd;*
    * break;*
    * }*
    * if (timeout>5000) //time out occurs*
    * {*
    * timeout=0; //reset timout*
    * State=transcmd; //trans failure, resend*
    * }*
    * delay(5);*
    * break;*
    * case slavedone: //trans done*
    * OK=1; //trans confirmed and OK, will exit while loop*
    * State=transcmd; //reset state for next call of cmd*
    * break;*
    * default:*
    * State=transcmd;*
    * break;*
    * }*
    * }*
    }
    [/quote]

And here is the slave side code:

#include "Rainbow.h"
#include <Wire.h>
#include <avr/pgmspace.h>

//=============================================================
extern unsigned char dots_color[2][3][8][4]; //define Two Buffs (one for Display ,the other for receive data)
extern unsigned char GamaTab[16]; //define the Gamma value for correct the different LED matrix
extern unsigned char Prefabnicatel[5][3][8][4];
extern unsigned char ASCII_Char[52][8];
extern unsigned char ASCII_Number[10][8];
//=============================================================
unsigned char Address=4; //Address of the device. Note: this must be changed and compiled for all unique Rainbowduinos
unsigned char line,level;
unsigned char Buffprt=0; //define variable that keeps track of which buffer is displaying and which recieves
unsigned char State=0;
unsigned char g8Flag1;
unsigned char cmdsession=0;
unsigned char sendsize=32;
unsigned char RainbowCMD[97]={
0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0x0f,

0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0x0f,

0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0x0f};

void setup()
{
_init();

}

void loop()
{
switch (State)
{
case waitingcmd:
break;

case morecmd:
break;

case processing:
RunCMD();
State=checking;
break;

case checking:
if(CheckRequest)
{
State=waitingcmd;
ClrRequest;
}
break;

default:
State=waitingcmd;
break;
}

}

ISR(TIMER2_OVF_vect) //Timer2 Service
{
TCNT2 = GamaTab[level]; // Reset a scanning time by gamma value table
flash_next_line(line,level); // sacan the next line in LED matrix level by level.
line++;
if(line>7) // when have scaned all LEC the back to line 0 and add the level
{
line=0;
level++;
if(level>15) level=0;
}
}

void init_timer2(void)
{
TCCR2A |= (1 << WGM21) | (1 << WGM20);
TCCR2B |= (1<<CS22); // by clk/64
TCCR2B &= ~((1<<CS21) | (1<<CS20)); // by clk/64
TCCR2B &= ~((1<<WGM21) | (1<<WGM20)); // Use normal mode
ASSR |= (0<<AS2); // Use internal clock - external clock not used in Arduino
TIMSK2 |= (1<<TOIE2) | (0<<OCIE2B); //Timer2 Overflow Interrupt Enable
TCNT2 = GamaTab[0];
sei();
}

void _init(void) // define the pin mode
{
DDRD=0xff;
DDRC=0xff;
DDRB=0xff;
PORTD=0;
PORTB=0;
Wire.begin(Address); // join i2c bus (address optional for master)
Wire.onReceive(receiveEvent); // define the receive function for receiving data from master
Wire.onRequest(requestEvent); // define the request function for the request from maseter
init_timer2(); // initialize the timer for scanning the LED matrix
}

void receiveEvent(int howMany)
{
unsigned char i=0;
while(Wire.available()>0)
{
RainbowCMD[(i+(cmdsession*sendsize))]=Wire.receive();
i++;
}
cmdsession++;

if((i==5)&&(cmdsession==1)&&(RainbowCMD[0]=='R')){
State=processing;
cmdsession=0;
}
else if ((i==sendsize)&&(RainbowCMD[0]=='F')){
State=morecmd;
}
else if ((i==1)&&(cmdsession==4)&&(RainbowCMD[0]=='F')){
State=processing;
cmdsession=0;
}

else State=waitingcmd;
}

void requestEvent(void)
{
Wire.send(State);
if ((State==processing)||(State==checking)) SetRequest;
}

void DispshowFrame(void)
{
unsigned char color=0,row=0,dots=0;
unsigned char temp;
unsigned char fir,sec;

for(color=0;color<3;color++)
{
for (row=0;row<8;row++)
{
for (dots=0;dots<4;dots++)
{
dots_color[((Buffprt+1)&1)][row][dots]=RainbowCMD[(1+(color84)+(row*4)+dots)];
}
}
}
Buffprt++;
Buffprt&=1;
}

void RunCMD(void)
{
if (RainbowCMD[0]=='F')
{
DispshowFrame();
}
}

//==============================================================
void shift_1_bit(unsigned char LS) //shift 1 bit of 1 Byte color data into Shift register by clock
{
if(LS)
{
shift_data_1;
}
else
{
shift_data_0;
}
clk_rising;
}
//==============================================================
void flash_next_line(unsigned char line,unsigned char level) // scan one line
{
disable_oe;
close_all_line;
open_line(line);
shift_24_bit(line,level);
enable_oe;
}

//==============================================================
void shift_24_bit(unsigned char line,unsigned char level) // display one line by the color level in buff
{
unsigned char color=0,row=0;
unsigned char data0=0,data1=0;
le_high;
for(color=0;color<3;color++)//GBR
{
for(row=0;row<4;row++)
{
data1=dots_color[Buffprt][line][row]&0x0f;
data0=dots_color[Buffprt][line][row]>>4;

if(data0>level) //gray scale,0x0f aways light
{
shift_1_bit(1);
}
else
{
shift_1_bit(0);
}

if(data1>level)
{
shift_1_bit(1);
}
else
{
shift_1_bit(0);
}
}
}
le_low;
}

//==============================================================
void open_line(unsigned char line) // open the scaning line
{
switch(line)
{
case 0:
{
open_line0;
break;
}
case 1:
{
open_line1;
break;
}
case 2:
{
open_line2;
break;
}
case 3:
{
open_line3;
break;
}
case 4:
{
open_line4;
break;
}
case 5:
{
open_line5;
break;
}
case 6:
{
open_line6;
break;
}
case 7:
{
open_line7;
break;
}
}
}
[/quote]

And finally here is an output that I've formatted a bit for easier readability. First is the print of the command array RainbowCMD, then the hex the SendCMD sends during the function, then another printing of RainbowCMD like before the command was sent. The leading numbers before the hex are what position in the RainbowCMD array the session starts with, then the number of bytes that will be sent, then the number of that session.

46FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FF

0 32 0 46FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

32 32 1 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

64 32 2 19F200C120FF10000000000000000000000

96 1 3 0

46FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FF

Am I missing something trivial? Is the array running over in a way I'm not seeing? Amazingly, the convoluted transmission routine seems to work just fine (the leds do display what is sent to them, it does interpret the junk and displays what that would mean if I'd programmed it that way) but the RainbowCMD array gets garbled only during the running of SendCMD. I'm at a total loss right now, and I can't figure any way to move forward.

Well, turns out I managed to fix it. And now everything works! I have a 4096 color combination 8x8 RGB LED display that communicates over I2C, despite the 32 byte send limit!

I never did find out what the problem was with the memory, but I've changed that array to be [4][32] which seems to have solved it at least for the time being.

If anyone is ever looking for a way to do Arduino to Arduino communication with I2C and 32 bytes isn't enough, let me know and I'll pass along my working code for your reference. It's not perfect, for instance it doesn't handle interrupted communications well/at all, but it works enough for me to put that part of the project on the back burner for now.

Hi,
nice to hear you managed to make it work!
I'd be interested in knowing more and seeing the code if possible,
I'm currently learning and some working example can help me so much!
What I'm trying to do is
to send patterns to 4-rainbowduino chained together,
but I'm a bit loss:
how can I address single rainbowduino_matrix on a I2C bus?
how should I format a 64x64 pixel image to send it to the matrix?

Thanks a lot,
have a nice day,
gio

conti.gio AT gmail DOT com

First of all when you upload the sketch to the rainbowduino, make sure you give each one a unique address in the wire.begin(Address) line of setup(). That's what determines what address a rainbow will respond to.

My code isn't quite in a presentable state at the moment, and I've stripped out a lot of the default functionality. Plus I'm dog tired from working like a fiend on this and need to take the rest of today off just to relax. I might send my code off to Seeed and maybe they'll publish it on the site. We'll see, just not today. Sorry about that. Bug me in a few days and we'll see where things have gone.

Thanks, I managed to set the I2C address for each matrix,
that was easy!

But now I'm reading the code in the Rainbow_CMD_V2_0 sketch,
and can't understand how to use the hex code to dim the LED I want. For example, to show ascii charachter A it's: {0x0,0x78,0x44,0x78,0x40,0x38,0x0,0x0}
How does this translates into informations for single LEDs?
I know it's a mixture of shift registers and some magic,
but I'm quite lost at the moment...
Hope someone can help with this,
thanks a lot for the moment!
ciao,
gio

Actually, not only is it magic, it's genius. For the ASCII commands, you'll notice that the color values are sent as part of the command (0-15 for each color, aka brightness). So if the rainbow is going to receive the command with the desired color value, what you have to do is 'post' that color value to each led that will be on when that particular letter is being shown. That's where that hex array comes in. Each byte of the array is essentially a row of the led matrix, with bit values stating if the led is off or on for that particular ascii character. With 8 hex values you have 8 rows, and 64 on/off values for the led. Saves you lots of memory.

I've actually implemented a total of 4 more command/data structures than just the 'R' commands that the 2.0 firmware supports.

'F' for frame: sends 'F' followed by three 32 byte sessions, each session containing one color data for the whole matrix. Even with a the 400Khz IIC hack and cranking down some delays, still ~20fps on a 3x2 'screen' of rainbows (24x16 leds).

'M' for monochrome: sends 'M' followed by two bytes of color data (like ascii or other 'R' commands) followed by 8 bytes of on/off data just like a ascii letter is constructed. great for one color images, and only 11 bytes to send via IIC. Speed in excess of 100fps. More like 200 but that is past the saturation point of the rainbows refresh rate, so your sending more than one command in a 'step' that the rainbow uses to POV brightness. Causes blinking of sorts, but is fast enough that sending independent red, followed by green, followed by blue commands will get you white.

'D' for dichrome: like monochrome only with two colors selectable and two 8 byte blocks like before. 20 bytes and in excess of 100 fps.

'T' for trichrome: not technically a word but whatever. Same again, three colors, three sets of 8 bytes. 30 bytes, >70 fps. slowed down a bit (12ms) but command still fits in the first data session so only one IIC transmit delay is needed which is where most of the speed loss occurs.

I could have 'quadchrome' and so on but up to trichrome fit in the first data session so I decides to stop there.

I'm feeling better after yesterdays break of Mario Kart and tinkering in Processing (I want to do a spectrum analyzer on the display) so I'll give the slave side code a commenting once through and I might re-write SeeedMaster to include the commands I added. Right now my Master code is written mostly for the 3x2 screen I have set up, and there is a lot of 'direct to command' in those functions, ie the function is not passed an array to then show because that would eat up the SRAM instantly (a single RGB screen of 24x16 leds is 576 bytes of SRAM, more than half of of my 168). Instead the functions pgm_read_byte the needed information from PROGMEM stored in the flash and directly put that in the command array, which is then sent to the correct rainbow, and repeated for all 6 rainbows.

I'll see how things go today and I might send out a code package to Seeed and yourself.

Hi, I'm trying to drive an rgb led matrix (11x11 leds) with three max 6956 chips (I2C), and I've some trouble with Arduino (MsTimer2 lib that unexpectly breaks, Wire lib that doesn't works correctly with max's...).

I've solved some problem, and thanks to your "code inspiration" I'll try to use the Timer2 interrupt directly, not with MsTimer2 lib.

I've read that "Even with a the 400Khz IIC hack and cranking down some delays, still ~20fps on a 3x2 'screen' of rainbows (24x16 leds).", so I'm worry about refresh time for my rgb matrix... Is Arduino too slow to refresh a simple rgb led?

In fact, at this time, I've a very low refresh time with an evident flickering effect (also with a refresh call time about 1ms) because I need to send over 40bytes to max's to refresh every matrix col and this means that the real time refresh is 1msec+max_setup_time...

So, what's is the 400KHz I2C hack? It's a tip to increase the I2C communication speed with Arduino?

Thankx

Thanks a lot 3FN that was ->sweeeeeet<-
gonna study hard, but now things got much clearer!
And i discovered that a lot of problems where due to the atmega8 I had on myold NG,
I've replaced it with a 168 and everything works now!

If someone is interested in Arduino+PWM info check here:

Tattik check it out maybe it can help you.

Double bless to 3FN :o
kk

Ahh, IIC, the bane of my existence. Ok, just this project really.

So the ATMega chips support up to 400KHz transmission speeds, but the Wire library doesn't do that out of the box. Have a read of this thread on how to hack the library, but make sure your 6956 chips will support that speed.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1241668644/0

I think that speed is technically called 'Fast Plus' but check the wiki on IIC to make sure.

The biggest difference between your setup and mine is that both sides of my communication system are arduinos at heart, so the code reflects that. The way the Wire library actually works is that when you Wire.beginTransmission you set up a buffer for data to be transmitted, and that buffer can only be 32 bytes. This cannot be hacked, which makes me think that it's a hardware limitation of the ATMega. During the Wire.send commands, all you're actually doing is putting stuff in the buffer. When you Wire.endTransmission, that's when the data is sent, but like the serial buffer, this happens WHILE your code continues to run.

I should really take that code down, it's so ugly I have to explain the errors so you don't do them :p. Ok, let's continue. If you look carefully, there is a delay right after Wire.endTransmission. This is to let the transmission occur, before it switches state to 'checking.' IIC is very much based on handshakes, meaning you'll have a few back and forth sends and requests to get one 'thing' of data or whatever you send/request. After the transmission with color data, there is a request, which asks what state the rainbowduino is in, so that the master knows what to do next. But really none of this particularly applies to you.

Ok, so you're driving 11x11 with three max chips, fair enough. Since I assume each one has it's own address and receives commands independently, you're probably actually sending 40/3 bytes in each transmission session, so no problems with the IIC buffer.

I don't think you need a timer for your application as it stands right now. Timers and transmission code do not play well with each other, because communication really likes to finish it's code blocks before something else happens, and timers like to hijack things no matter what's going on. The timer in my code is actually on the slave side, not the master, and the timer runs the POV and brightness by cycling. I didn't actually write the timers or the shifting stuff, that was done by whoever wrote Rainbowduino V2, I just hacked everything above that level. I will take credit for the changes involving IIC and above, but the nitty gritty wasn't my doing.

I would just use delays to get frame rates that are viewable. YOU DO NEED THE DELAY AFTER ENDTRANSMISSION, but this can be really short, like 2ms. actually, with the 400KHz hack, my delay is set to 250us and there are no problems, but down at 220us things start to wig out. And make sure you do whatever handshake (request data from the max after transmission) the data sheet allows for, because it makes things much easier to debug when you know what the slave is doing.

A potential problem that could be the reason behind the flicker is saturation of the max's refresh rate. let me explain: IIC receives are probably interrupt driven, when something comes in over the bus, things get stopped, the communication is dealt with, things are changed per the command, and then they start back up again. If you are sending commands fast enough to send two or more commands per frame refresh of the slave (I assume the max does some POV stuff for brightness/color etc with multiplexing) then you are essentially adding a delay because every time a command comes in it has to be dealt with, taking up precious time. This is actually a problem with my rainbowduino, not a major one, but when I test commands with no delay between each frame (a data integrity test really) I tend to get a flickering white color, probably because as I said, I'm sending more than one command per refresh of the rainbow. Of course, all I just said is very dependent on the refresh rate of your chips and I could be totally wrong, but try putting in a 10ms or 100ms delay instead of 1 and see what happens.

I managed to comment all the code as best I understood it for the master/slave side sketches, plus a nice little explanatory blurb to help people get started. Today I hope to get the 'manual' done which will detail the CMD protocols the new slave side supports. Certainly will be able to get something out this weekend, but I am still working on the project I rewrote all the code for, so keep that in mind.

If you'd like to see my project, search youtube for user ThreeFN.

Thanks to ThreeFN for his tips! :wink:

I still have very strange problems working with Arduino (e.g. static variables that doesn't work...) , but at this time I thinks that some problem is due to that the circuit is temporary mounted over an experimental board with fliyng wires... so sometimes the I2C commands was lost, also with the wire library set to 100KHz speed.

I also had to slice the commands sent to the max 6956 to have the chips work right. You've to consider that the chip is every time driven with a 20 byte sequence to setup ports and registers.

I don't know if this is a bug or anything else... Here you can read about the problem:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1247128577/0#0

Slowing the refresh time to update the led matrix haven't solved the problem anyway, but measuring the max's setup time via a digital scope now I know that I've to change the circuit design, because this time is to high to obtain a flickering free refresh time.

One of the apparent reasons the code at the top of the page didn't work was because the RainbowCMD array was 97 bytes long originally. When I separated that into [4][32] the problems went away. As much as I love the arduino, the documentation kind of falls down when you want to do something that is between the 'simple' stuff that it's normally used for, and the level of a day-to-day avr programmer. I looked everywhere to see if there was a "maximum array length" but got not even a hint.

If you want an example of how bad the documentation falls on it's face, look at the pointers section in the extended reference. I just about fell on the floor convulsive laughing when I read it. Even though arduino is essentially C you'd think they would at least fill out the section if they even bothered to put it there.

I looked at the max doc real quick and are you sure you need to setup the registers and all that each time you send a 'frame?' Or are you cycling each chip on/off as part of your color multiplexing with common cathode/anode? Maybe you can figure a way to leave the chip on but not get ghosting?