Need help with Teensy3 + uSD + WS2801 LED strips SPI problem

Status
Not open for further replies.

Frollard

Member
Greetings

TL/DR - I'm using 2 spi peripherals, and they fight with one another. My code worked with oldDuino but not Teensy (I think the teensy is so fast it runs into problems).

Long version: I have some code I put together on my arduino Mega and it worked, albeit slow (less than 100fps updates of 64 leds). I load a bitmap from the sd card, and output it line by line to a strip of leds. This can store animations, or more importantly, a POV image that I can move around the strip to get the image to show up in the air.
It's been done before, BUT, this time it's full RGB 24 bit.

The uSD card is the Waveshield adapter board, 3v3 native.
I'm using the sdFAT library - the new version adapted for the teensy, since its wicked fast.
The files I deal with are in the order of 32x100, or generally about 10k. In theory they could be very large since we only ever load one line at a time. Even small files are much larger than the uC has ram to hold, hence the stuttered process.
http://code.google.com/p/beta-lib/

The strips are WS2801 led strips - with synchronous clock and data, but NO chip select. I address this by using an npn transistor to interrupt the spi clock signal to the strip whenever it's not needed. This way, the SD card data doesn't write random info to the strip.
I'm using the fastSPI library from Daniel Garcia - new version adapted for the teensy 3.0
http://code.google.com/p/fastspi/

I've had success (if a bit slower) using the adafruit ws2801 library.

pseudocode: (Attached is the real thing)
Code:
setup
load sd file, library takes care of file handling/buffering
/setup

loop

read entire file, one line at a time of the bitmap (32 bytes * 3rgb) to a buffer  //I can do this, and serial.print it all day long, flawless.
write one line to 32 rgb leds from buffer //I can procedurally generate animations, flawless
//I can't do both at the same time.
/loop

I have a hunch that the spi data rate is getting mad between changes of 'who' is using the spi bus at the same time. The pinout diagram leads me to believe there is more than one SPI bus (greyed out scl, sda, din dout) -- the datasheet says the chip has one spi module.
I've asked around the arduino forums with limited success - The sdFat and fastSPI authors are relatively busy so I imagine they don't have time for my little project :(.
If I was bitbanging the output it would work, but it would be brutally inefficient.

Long story shorter: Is there a way to tell when the sdFat library is done doing its buffering so I know it won't interfere with the strip output?
and
Does the Teensy3 actually have multiple spi ports?
-if so, how does one point an spi library at the second port?

For your viewing pleasure:
https://www.youtube.com/watch?v=tWjcMlhfz1Y
 

Attachments

  • LedStripSDLoaderSdFat.zip
    130.3 KB · Views: 342
Last edited:
Hmm, interesting question. I've used both libraries, though not both at the same time on any platform.

It's only a guess, but I wonder if this library has an issue similar to the RFM12 library for Teensy 3 (https://github.com/tht/T3Libs). In the 'disadvantages' section there, it says that it assumes nothing else is using the SPI bus. Essentially, that driver doesn't use the CS pin. In this case, it's certainly possible to add code to implement the use of the CS pin, though the interrupt handler would also need modification.

The FastSPI driver does something similar, but in this case, the LED pixels don't have a CS pin. While this means the CS pin doesn't do anything, the LEDs never send data, so the uC 'should' have full control over when LED data is placed on the SPI bus. However, this also means that they will see all data passed on the SPI bus, essentially acting like an SPI sniffer. This may cause them to see data not intended for them and take action on it. At minimum I'd expect this to put the 2801s in an indeterminate state, at worst they'll display data as it's placed on the bus, even if it's the SD card doing so. Neither is likely desirable.

I notice you placed a delay(100) in the code. It's commented out at the moment, though it'd be interesting to know if that allowed the read/display cycle to work.

My expectation would be that it doesn't help. That said, I'd also think that this setup wouldn't work on an atmega328 either, though you report that it does. With that as evidence, spending time playing with timings on the teensy may well provide a solution.

You didn't mention how you're using the Adafruit library. Are you using its hardware SPI mode, or the arbitrary pin mode?

That library also documents 1MHz as the max SPI speed supporting reliable 2801 operation, which equates to a value of 3 in the FastSPI library's setDataRate function. The default there is 7, which is pretty safe. If you're using a value under 3, it's possible issues could exist, though the FastSPI library may be able to handle faster rates. That said, the datasheet for the Teensy3 uC indicates that the SPI clock could run up to 25 MHz by default. This is the limit of the stated maximum in the 2801 datasheet (well, the one I grabbed at least...) and a good bit higher than the 16MHz of an Arduino. In order to stay under 1 MHz with that as the base rate, a higher value may be needed. If the overclocking used by default by the Teensy3 dev tools increases that, a correspondingly larger increase may be necessary. Well, either that, or switching back to the officially supported clock rate :p

If a software based solution doesn't end up working out, it's possible to implement a CS function with a couple transistors (FETs would likely be best to avoid potential voltage drop issues) on the data and clock lines connected to the LEDs. This would ensure that the LEDs only see clock and data when it's meaningful for them.

I also see your point on the additional SPI pins. I'm really not sure if that's a truly separate SPI port, or if there are two possible pinouts for the same SPI port. If it's an alternate pin layout, the next question becomes whether the layout is selectable at runtime or not.

Just some thoughts really, hopefully they're of some kind of help.
 
Hey Frollard, I'm new here, but saw your youtube videos a couple of weeks ago and got inspired, so I got the same hardware as what you're using (Teensy 3 + WS2801 strip). Have you had any further work done on your project, or made any advancements with the sharing of SPI amongst both the strip and the SD adapter, using FastSPI?

Also, would you mind sharing a schematic of how to wire up the transistor for the clock signal interrupt?

I'm doing a similar project right now, building a staff with a Teensy 3, and have a pretty decent working prototype up and running already. I'm now into the phase of programming algorithms, but would like to add POV with images also. I have one of these: https://www.pjrc.com/teensy/sd_adaptor.html and also wondering how to make use of that whilst using SPI for the WS2801 strip that I'm also using.

I see you've attached some of your code, I'm going to see if I can make a start with that for my own POV implementation.
 
Last edited:
It turns out that I can reasonably well run both the 2801 strip and the SD adapter in the same program, although I've used the standard Arduino SD library. I've done a similar thing where I let the CS signal interrupt the clock signal to the 2801 strip to not have the noise come out there. This works okay. However as soon as I start wiring everything really closely bundled together in a staff I'm making, I run into troubles. When I then run my program that first initializes both the strip and the SD card, and start doing seeks and reads followed by outputting to the strip using fastSPI, the Teensy often just locks up completely. Even to a point where uploading new compiles is not possible (the loader just gets not response from the Teensy). I then have to disconnect the clock and data wires from the strip, and power down the Teensy, repower it, and only then can I reprogram it.

It's really frustrating as everything works okay on a breadboard every time, but then runs into this problem when I start building it into the staff. So at this point I am thinking I need to shield the wires more perhaps. I am using basic jumper wire that I cut up for this purpose. Everything is really close together so maybe there is interference going on. I don't have a scope so it's hard for me to debug this.
 
neep -- I don't know exactly how you are doing this, but 'the CS signal interrupt the clock signal' sounds like you just have a switch in series -- that's probably not good enough and you really need a logic gate, else you might be getting capacitive coupling between other signals and the (now floating input) clock signal at the 2801 strip. do you even have a pulldown R on the 2801 strip ? Try 1kohm or lower.
 
What I'm doing is I have the SCK drive a MOSFET gate to sit in between the SCK signal from the Teensy to the WS2801 strip.

Ah right a logic gate. I need to start ordering some more standard parts like that. I'm only starting out and my lab is still a bit under-equipped.

Also I don't have a pulldown resistor on the strip. Where should I place that exactly? Between ground and the data signal?

Thanks
 
Okay, I've followed your instructions you gave me via youtube (I'm "tubeneep" there) and I now have a setup that keeps working. Not using a MOSFET anymore but just a 2N2222, seems to work best, with 10k on the base driven from pin 14 like in your code, and 100k on the emitter.

The sdFAT lib is not working out at all, only when I do a sd.begin at SPI_HALF_SPEED or SPI_QUARTER_SPEED, and then usually only when I clock the Teensy down to 24MHz. So I stuck with the standard SD lib. I am able to read in small bitmaps (8 x 16 bits) in between outputting to POV just fine. I can share the code if you're interested, although it needs some cleanup due to all the experimenting.

However, I just found out this morning, that some previous code I had written to drive some generic patterns through the staff has become much slower when I do anything at all with the SD, like a simple begin() and then nothing else throughout the program. For example I have these little snippets:

Code:
   // in / out fast
   for (int i = 0; i < 150; i++) {
      getMotionColor(accel);
      colorWipe(r, g, b, 3000, 2);
      colorWipe(0, 0, 0, 1500, 3);
   }

The above sets bytes r, g, b to colors based on the accelerometer output, then calls colorWipe which wipes these colors from the middle to the end of the staff, and w/o color back to the middle, at a speed of 3 and 1.5 milliseconds, respectively. This is really fast with FastSPI and creates its own kind of POV (see my avatar pic for example). But when I do a simple SD.begin() and an SD.open() in the setup() function, this thing slows down a *lot* to a point where the whole cool effect is gone. So my guess is whatever you need to do on the SPI bus that requires top speed, it's pretty much the only thing you can then do.

So unfortunately after about a week of experimenting I'm going to have to let go of the idea of driving an SD card from inside my staff for POV, at least for now. And I'll be working more towards generating patterns using algorithms, and some basic POV using characters I'll just commit to memory. Does the Teensy have a similar concept of "PROGMEM" that the Arduino has?
 
Status
Not open for further replies.
Back
Top