Timing question: if I have a loop that’s constantly updating two strings (32 pixels each) at anywhere between 10-50ms, and the AVR receives I2C data via its onReceive() event, that just stuffs the data into a buffer and moves on (as in return to the main loop and keep running), how much of a risk am I running that it will cause havoc with the running loop? Technically speaking, it should be able to receive the data within nanoseconds, but I don’t know if the event call will cause problems.
My guess is that the event probably won’t get called every time from the I2C because all interrupts are disabled by FastSPI during outputs to the LED strings. This is to keep the data output timings to the LEDs to be as accurate as possible, thus preventing of corruption of the data sequence. But to the expense of anything else that uses interrupts.
Because of this, the the onReceive event won’t get called (very often) unless the timing is ‘just right’.
Yeah, I kinda figured … so I need @Daniel_Garcia or @Mark_Kriegsman to chime in here. I need to figure out how to effectively communicate via I2C without affecting the output. And I need to do it fast.
What is the messaging that’s coming in via I2C? If it’s frame data, then i’m assuming your world would look roughly like message->show frame->message->show frame, etc… ? If so - then maybe having the slave AVRs send a message back (a sort of “ready”) response when they’re ready for the next update from the host?
Your frames are only taking up 1.92ms to write out, which means you have anywhere from 8-48ms between each write - enough time to do a bit more handshaking.
Slightly differently - how much data are you sending?
Also - if you feel like guinea pigging an idea for making interrupt handling a bit saner, ping me on g+ hangout/IM and i’ll walk you through a possible change to clockless.h that might work for you. I’ve been curious about whether or not I can enable/disable interrupts on an RGB led level basis - assuming your interrupt handler is fast - you may be able to handle interrupts in between each rgb led, and assuming that the world won’t fall over if your interrupts aren’t handled in 30µs, this may provide the best of both worlds.
So here’s the idea:
There’s one master and 25 slaves. Each slave has built-in code to display random stuff on two 32-pixel strings. Every so often (maybe every minute?) the master will then send 192 bytes to each slave, and each slave in turn needs to take that buffer and display it on their respective string and pause till the master tells them they can return to their previous “work”, whatever it might’ve been.
192 bytes = RGB data for two strings of 32 pixels
So let’s say a slave is randomly flashing it’s pixels, updating the strings every 20ms. I2C data comes in which should trigger the slave’s onReceive() event to stuff the info in a buffer (ideally two CRGB(leds) buffers, one per string) and then update the string as soon as that data has arrived and stop. A little bit later the master will send a continue signal (whatever single byte that is) and the slave returns to flashing its pixels (or some other pattern.)
Make sense?
Oh, the master will blast all the slaves in a loop, and they need to all be able to consistently receive that data, otherwise it won’t work.
File.open(…);
for (int slv = 1; slv <= 25; slv++) {
File.read(buffer, 192);
Wire.beginTransmission(slv);
Wire.write(buffer, 192); // forgot to add the 192
Wire.endTransmission();
}
File.close();
Also just a general point: on most systems, if an interrupt is signaled while interrupt handling is disabled, usually the interrupt handling routine is triggered immediately after interrupt handling is re-enabled by the code.
I’ll have to check to see what ATmegas specifically do.
So then the question is, how often does FastSPI dis-/enable that?
AVR’s will fire any interrupt handlers for interrupts triggered while interrupts were disabled. The problem is, right now - the library disables entires will writing out an entire controller’s worth of leds. So with @Ashley_M_Kirchner_No 's code, every 960µs (30µs per led, 32 leds per strip, so 960µs that interrupts are disabled) the interrupts will fire. Unfortunately - while the I2C and serial code can buffer incoming data, the buffer is small, only one or 2 bytes. This means if data continues coming in before it is handled, older data will get blown away which means the data you read gets corrupted.
However, some people have claimed that the WS2811 family timing is only strict within a single RGB led’s data, but that you have a fair bit of swing between rgb leds. If this is true, then we can toggle interrupts at the end of each led’s worth of data, which means every 30µs. In that case, as long as the data rate is under about 250kbps it means that each byte would get handled before the next byte comes in. I just haven’t had a chance to dig into testing that, yet 
Which from the AVR docs, i2c bit rate is CPU/(16+(2*TWBR)Prescalar) - if pre scalar is 1, then TWBR needs to be 24 or higher ((16Mhz/(16 + (224)) == 0.25). If pre scalar is 4, then TWBR needs to be 12 or higher. if pre scalar is 16, then TWBR needs to be 2 or higher. If pre scalar is 64, TWBR can be any value you want.
I’m using LPD8806 strips on a 328p AVR. When I send the buffer out, the onReceive() event collects (or should collect) all the data before doing anything, one byte at a time though:
void setup()
{
Wire.begin(4);
Wire.onReceive(receiveEvent);
}
void loop()
{
…
// run LED code
}
void receiveEvent(int howMany)
{
while(1 <= Wire.available())
{
byte c = Wire.read();
// stuff in buffer or read straight into
}
}
Oh wait, you’re using LPD8806’s? Are you using them on the hardware spi port or the software SPI port?
Software …
I still need to grasp the idea of having a single string, but managed as two separate ones, or “sections” rather … So for now, I use software pins to have two individual strings connected.
Ah! In that case then, I think you should be ok, because there’s no interrupt disabling that happens with SPI, bitbang’d or otherwise.
There is one last sanity check, though for software bit banging, there’s an optimization that assumes none of the other pins on the port will change their value while writing out data. The I2C pins are on PortC, which has digital pins 12-19. So, if any of those pins are what you’re using to drive the LPD8806’s, then you need to add the following line:
#defin FAST_SPI_INTERRUPTS_WRITE_PINS
BEFORE the #include line
Yeah, I’m thinking I’m going to have to move them. Right now they’re on A0/A1, A2/A3, but on the 328p, they’re all on PortC, as is I2C. I can move them to PortD instead since I don’t have anything at all on those pins.
all the FAST_SPI_INTERRUPTS_WRITE_PINS line does is removes an optimization for pre-computing the register values for the clock/data registers when bit-banging, instead it does P |= MASK for set or P &= ~MASK for clearing - which take 2 cycles per op instead of 1 - so slightly slower bit’bang’d output, but no interrupts between the I2C pins and the spi data writing.