PDA

View Full Version : Teensy 3 SPI Basic Clock Questions



t3andy
11-26-2012, 05:00 PM
What is the "default" SPI clock rate on the Teensy 3?

Please note: I would like to do a search, on this board, for only "SPI" but it does not work?


Does the default clock rate change with the K20 CPU clock frequency?

If so, what are the values below?

24 MHZ = x SPI clock rate ?

48 MHZ = x SPI clock rate ?

96 MHz (overclocked) = x SPI clock rate ?



Can you adjust this SPI "default" clock rate on the Teensy 3?


I found in the SPI library these defines

//#define SPI_CLOCK_DIV4 0x00
//#define SPI_CLOCK_DIV16 0x01
//#define SPI_CLOCK_DIV64 0x02
//#define SPI_CLOCK_DIV128 0x03
//#define SPI_CLOCK_DIV2 0x04
//#define SPI_CLOCK_DIV8 0x05
//#define SPI_CLOCK_DIV32 0x06

SPI.setClockDivider(SPI_CLOCK_DIV128);


Will the above command work on the Teensy 3?

t3andy
11-27-2012, 04:57 PM
#include <SPI.h>

const int cs=9; //chip select

//#define SPI_CLOCK_DIV2 0x04
//#define SPI_CLOCK_DIV4 0x00
//#define SPI_CLOCK_DIV8 0x05
//#define SPI_CLOCK_DIV16 0x01
//#define SPI_CLOCK_DIV32 0x06
//#define SPI_CLOCK_DIV64 0x02
//#define SPI_CLOCK_DIV128 0x03

void setup() {
// set the cs as an output:
pinMode(cs,OUTPUT); // chip select
}

void loop() {
delay(10000); // wait tens seconds for T3
Serial.println("Start SPI Test");
// start the SPI library:
SPI.begin();
//SPI speed @ CPU Clock Teensy 3 @ 24 MHz @ 48 Mhz @ 96 MHz - (overclock)
//SPI.setClockDivider(SPI_CLOCK_DIV2); // ~1.738 MHz 3.039 MHz 3.275 MHz
//SPI.setClockDivider(SPI_CLOCK_DIV4); // ~1.211 MHz 2.202 MHz 2.351 MHz <-- Default Teensy 3 SPI ?
//SPI.setClockDivider(SPI_CLOCK_DIV8); // ~754 KHz 1.420 MHz 1.516 MHz
//SPI.setClockDivider(SPI_CLOCK_DIV16); // ~446 KHz 860 KHz 886 KHz
//SPI.setClockDivider(SPI_CLOCK_DIV32); // ~238 KHz 466 KHz 476 KHz
//SPI.setClockDivider(SPI_CLOCK_DIV64); // ~127 KHz 251 KHz 253 KHz
//SPI.setClockDivider(SPI_CLOCK_DIV128); // ~ 65 KHz 129 KHz 130 KHz

SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE3);
start:
digitalWrite(cs, LOW);
SPI.transfer(-1);
SPI.transfer(0);
digitalWrite(cs, HIGH);
goto start;
}


I will answer my own questions to tech support.

Got out the Wavetek to measure the SPI frequencies at different clock speeds on the Teensy 3 (Beta8)


#1 Default SPI clock rate on Teensy 3 //SPI.setClockDivider(SPI_CLOCK_DIV4); // ~1.211 MHz @24 2.202 MHz @48 2.351 MHz @96 <-- Default Teensy 3 SPI ?

#2. Yes, the SPI clock rate changes when the Teensy 3 K20 clock changes. (see values above)

#3. Yes, the SPI command "SPI.setClockDivider(SPI_CLOCK_DIVx);" does change the SPI clock frequency. It should be always set (used) when using SPI.;)

I like to point out that a user needs to know, at all times, what the SPI clock frequency is under
different K20 CPU clock frequencies. If a SPI device specify a maximum of 2 Mhz then exceeding this spec
might cause problems. Also, as further help, using the Arduino IDE, there should be another helpful indication on
the bottom task bar, along with the "Teensy type" and "comport port". The Teensy 3 K20 "CPU Mhz" should also be displayed.

t3andy
11-28-2012, 04:03 AM
The SPI question that begs to be answered is why limit the Teensy 3 SPI clock rate only 3.275 Mhz? The Arduino can run SPI faster than the K20? :confused:

jgmrequel
12-12-2012, 12:44 PM
The SPI question that begs to be answered is why limit the Teensy 3 SPI clock rate only 3.275 Mhz? The Arduino can run SPI faster than the K20? :confused:

If you read the datasheets on the mic that Teensy 3 uses, it's DSPI interface can run 25MHz at a limited voltage range and 12.5MHz over a full voltage range. Given that its a different serial interface (DSPI v. SPI), I would imagine that the Arduino library needs tweaks to make the most of the Teensy's SPI interface (such as setting the double clock bit, etc. etc.). I've been digging into this in order to maximize the speed at which I can write to a AMC7812 control chip (adds 16adc, 12dac, 8gpio over SPI up to 50MHz or I2C up to Fast Mode), so if I figure out the modifications to get the most out of the interface, I will gladly share.

PaulStoffregen
12-12-2012, 09:09 PM
Teensy 3.0's SPI port can run at 24 Mbit/sec speed, but the SPI library isn't going to work for high speed.

Aide from lacking the option to set faster than 8 Mbit/sec, the main problem is SPI.transfer() sends a byte and waits for all the bits to be shifted, so it can return the received byte. As you attempt higher speeds, the overhead of waiting and looping, even with the processor at 96 MHz, becomes a substantial part of the time. The hardware has a small FIFO which is intended to allow using the SPI at the maximum speed with no delay between transfers. But you can't use the FIFO with the Arduino SPI library. You'll need to use native code to fully utilize the SPI port.

Right now, the very native best code is in Bill Greiman's SdFat library. I also have some code I wrote, which I sent to Bill when he ported SdFat to Teensy 3.0. Bill made improvements and did a lot of speed testing, so your best option it to look at Bill's code. You'll need to get the new beta version. Here's the page to download it. Look for the Dec 3 version.

http://code.google.com/p/beta-lib/downloads/list

Look in Sd2Card.cpp. There is a LOT of code in that file, supporting high speed SPI in lots of ways, but most of it is for other chips, so don't be discouraged by the amount of code. The part you want is selected by USE_NATIVE_MK20DX128_SPI.

Bill's added some impressive features, like using both 8 and 16 bit transfers for lower overhead when 2 bytes are needed. Bill's spiSend(buffer, len) function is extremely fast when you need to send lots of bytes.

jgmrequel
12-12-2012, 09:47 PM
I do quite a lot of infrastructure work at my day job (I work in the same department as this guy: http://books.google.com/books/about/Large_scale_C++_software_design.html), so writing solid libraries shouldn't be difficult. Dealing with my company's IP policies will be more difficult if I ever want to release anything though, but lets see if this starting point will let me tie the AMC7812 to the Teensy. I'll dig through those libraries tonight.

btmcmahan
03-01-2013, 01:50 AM
Hey guys, I am about to get some Teensy3's to upgrade my Atmega328's. I don't have a lot of SPI experience, but If I understand correctly, SPI has much faster transfer rates than serial. Is there a good way to use SPI to communicate between 2 teensy's? Or a library I can pull source from? I need something that can allow two boards to talk very fast. And if SPI isn't my solution, is there some other recommendation, like usb or something? Serial just won't work well for my applications.

PaulStoffregen
03-01-2013, 07:41 AM
SPI is the fastest way, but unfortunately all the software that exists only supports master mode. There's no library (yet) which supports slave mode. Writing such a library isn't simple, and it would be particularly complex to do with support for the fastest speeds. You'd certainly need to use DMA and complex buffer management to keep up with the highest speeds. It's theoretically possible, but in practice that software would be incredibly difficult to write.

I know you said serial won't work.... but why? Teensy 3.0 has a FIFO on Serial1 (but not on Serial2 and Serial3), so it's capable of fast baud rates. Exactly how fast has never been carefully tested, but I believe 1000000 baud is likely to work. The nice thing about Serial is the code is very well developed and easy to use.

ploveday
03-01-2013, 08:45 AM
Be a little cautious of some of the code in SdFat though; it does some nasty things, like setting MCR explicitly rather than changing bits it needs and leaving the rest alone.

The biggest issue this causes, is that it clobbers any attempts you might make to use hardware chip selects, you'll wind up with all the CS pins going active whenever you use SdFat calls.

But it's well worth a look. I used similar techniques (8/16 bit, 24MHz clock, FIFO) with my Teensy 3 optimized ST7735 LCD library.

- Peter

manitou
03-08-2013, 01:00 AM
FYI, I ran some unconnected SPI tests with the SdFat SPI routines and the default SPI routines on teensy 3.0. See file SPIperf.txt at

https://github.com/manitou48/DUEZoo

There are also some SPI tests with SD (SDperf.txt) and with the W5200 ether chip (wizperf.txt). Results include tests with UNO, maple, and DUE.

your mileage may vary.

PaulStoffregen
03-08-2013, 03:06 AM
Yup. Those test results confirm the Arduino SPI library, built around the unbuffered AVR SPI, really isn't any good at utilizing the full potential of more advanced hardware!

ploveday
03-08-2013, 03:28 AM
Indeed.

I'm seeing around 20Mbit/s pixel fill (write) speed to my LCD via 24MHz SPI. I would assume SD card would be similar, within limitations of the card.

- Peter

PaulStoffregen
03-08-2013, 03:34 AM
I've considered writing a high performance SPI library. But at this point, there's 3 major problems.

1: It would depend on collaborating with others to support non-Teensy boards like Due and Maple.

2: I'm not sure what API would work well for all the hardware types. Obviously handling big buffers is a must. Maybe it should allow queuing multiple transfers? The API design would be tricky to keep Arduino-style simple yet allow good performance.

3: I have limited time available....

Over the long term, a high performance library would allow lots of other libraries to talk to high speed SPI devices and be compatible across boards, hopefully only requiring the SPI library to be ported to new boards?

Donziboy2
03-17-2013, 05:22 PM
Would this same issue apply to IC's like the TLC5940?
Spec says they can go upto 30Mhz, but if your stuck at 3Mhz on the Teensy 3 its kind of a killjoy.

My current project in planning requires me to send close to 350KBytes/S to 12 TLC5940's, and the faster the data moves means more time to do other things in between bursts.
My current plan is to send 144 Bytes every 428uS (337KB/s) and if possible every 300uS(480KB/s).

I'm planning a Mk2 Version of this.
Skip to 2:24 to avoid most of the boring stuff ;)

http://www.youtube.com/watch?v=L9BaXpfreVg
This was capstone I did with a friend.
This thing has a few short comings and I am looking to build something that avoids those. And adds alot more features and power.

Donziboy2
03-21-2013, 11:47 PM
So there is noone even willing to attempt to tackle SPI on the Teensy 3?

Is it possible to bitbang the teensy 3 fast enough to get around 15Mhz speeds?

ploveday
03-22-2013, 12:25 AM
I'm sure there will ultimately be a way to do it via a library, but in the meantime you can do it manually without too much trouble. The biggest issue may be interoperability with other SPI code/libraries, depending what you're using.

Here's some macros adapted from what I use for 24MHz SPI to the ST7735. Note this uses "software" chip select, as hardware chip select isn't really compatible with other libraries at this point.



Define SPI clock speed:
#define BAUD_DIV 0 /* 24MHz SPI */
//#define BAUD_DIV 1 /* 12MHz SPI */
//#define BAUD_DIV 2 /* 8MHz SPI */
//#define BAUD_DIV 3 /* 6MHz SPI */
//#define BAUD_DIV 4 /* 3MHz SPI */

Globals/members:
uint32_t ctar0, ctar1, mcr;

Init code:
// First set up SPI via library
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);

// Now reconfigure some stuff

// remember MCR
mcr = SPI0_MCR;

// Use both CTARs, one for 8 bit, the other 16 bit
ctar0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(BAUD_DIV) | SPI_CTAR_CSSCK(BAUD_DIV) | SPI_CTAR_DBR;
ctar1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(BAUD_DIV) | SPI_CTAR_CSSCK(BAUD_DIV) | SPI_CTAR_DBR;

SPI0_CTAR0 = ctar0;
SPI0_CTAR1 = ctar1;

//And some macros:

#define SPI_WRITE_8(c) \
do { \
while ((SPI0_SR & SPI_SR_TXCTR) >= 0x00004000); \
SPI0_PUSHR = ((c)&0xff) | SPI0_PUSHR_CTAS(0) | SPI0_PUSHR_CONT; \
} while(0)

#define SPI_WRITE_16(w) \
do { \
while ((SPI0_SR & SPI_SR_TXCTR) >= 0x00004000); \
SPI0_PUSHR = ((w)&0xffff) | SPI0_PUSHR_CTAS(1) | SPI0_PUSHR_CONT; \
} while(0)

#define SPI_WAIT() \
while ((SPI0_SR & SPI_SR_TXCTR) != 0); \
while (!(SPI0_SR & SPI_SR_TCF)); \
SPI0_SR |= SPI_SR_TCF;

#define SPI_CS_ON(pin) digitalWrite(pin, 0); \
SPI0_CTAR0 = ctar0; SPI0_CTAR1 = ctar1; SPI0_MCR = mcr;

#define SPI_CS_OFF(pin) SPI_WAIT(); \
digitalWrite(pin, 1);



So, more or less, having done the appropriate init code, you should be able to send a sequence of bytes via:


void spi_send_bytes(uint8_t *data, int len)
{
SPI_CS_ON(MY_CS_PIN);
for (int i=0; i < len; i++)
SPI_WRITE_8(data[i]);
SPI_CS_OFF(MY_CS_PIN);
}


Or for word transfers:


void spi_send_words(uint16_t *data, int len)
{
SPI_CS_ON(MY_CS_PIN);
for (int i=0; i < len; i++)
SPI_WRITE_16(data[i]);
SPI_CS_OFF(MY_CS_PIN);
}


Or just mix and match:


SPI_CS_ON(MY_CS_PIN);
SPI_WRITE_8(12);
SPI_WRITE_16(1234);
SPI_WRITE_16(5678);
SPI_WRITE_8(34);
SPI_WRITE_16(1234);
SPI_WRITE_16(5678);
SPI_CS_OFF(MY_CS_PIN);



Hope this helps,
- Peter

Donziboy2
03-22-2013, 02:47 AM
Thanks Ploveday, that's a start in the right direction.

I think one of the big factors thats killing alot of us less educated people is that we just cant find documentation on how the libraries work.
Ive had a basic C programming class and using small command prompt programs on a computer and understanding what alot of what I see in arduino libraries is just totally different.


OK, playing around, either I put it in the wrong place or im missing something or probably both. :( Think I will sleep on it.



#include <SPI.h>


//Define SPI clock speed:
#define BAUD_DIV 0 /* 24MHz SPI */
//#define BAUD_DIV 1 /* 12MHz SPI */
//#define BAUD_DIV 2 /* 8MHz SPI */
//#define BAUD_DIV 3 /* 6MHz SPI */
//#define BAUD_DIV 4 /* 3MHz SPI */

//Globals/members:
uint32_t ctar0, ctar1, mcr;

void setup(){
//Init code:
// First set up SPI via library
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);

// Now reconfigure some stuff

// remember MCR
mcr = SPI0_MCR;

// Use both CTARs, one for 8 bit, the other 16 bit
ctar0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(BAUD_DIV) | SPI_CTAR_CSSCK(BAUD_DIV) | SPI_CTAR_DBR;
ctar1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(BAUD_DIV) | SPI_CTAR_CSSCK(BAUD_DIV) | SPI_CTAR_DBR;

SPI0_CTAR0 = ctar0;
SPI0_CTAR1 = ctar1;

//And some macros:

#define SPI_WRITE_8(c) \
do { \
while ((SPI0_SR & SPI_SR_TXCTR) >= 0x00004000); \
SPI0_PUSHR = ((c)&0xff) | SPI0_PUSHR_CTAS(0) | SPI0_PUSHR_CONT; \
} while(0)

#define SPI_WRITE_16(w) \
do { \
while ((SPI0_SR & SPI_SR_TXCTR) >= 0x00004000); \
SPI0_PUSHR = ((w)&0xffff) | SPI0_PUSHR_CTAS(1) | SPI0_PUSHR_CONT; \
} while(0)

#define SPI_WAIT() \
while ((SPI0_SR & SPI_SR_TXCTR) != 0); \
while (!(SPI0_SR & SPI_SR_TCF)); \
SPI0_SR |= SPI_SR_TCF;

#define SPI_CS_ON(pin) digitalWrite(pin, 0); \
SPI0_CTAR0 = ctar0; SPI0_CTAR1 = ctar1; SPI0_MCR = mcr;

#define SPI_CS_OFF(pin) SPI_WAIT(); \
digitalWrite(pin, 1);
}

void loop(){

// empty till I fix the Init script....


}


SPI_screwup.ino: In function 'void setup()':
SPI_screwup:24: error: 'SPI0_MCR' was not declared in this scope
SPI_screwup:27: error: 'SPI_CTAR_FMSZ' was not declared in this scope
SPI_screwup:27: error: 'SPI_CTAR_PBR' was not declared in this scope
SPI_screwup:27: error: 'SPI_CTAR_BR' was not declared in this scope
SPI_screwup:27: error: 'SPI_CTAR_CSSCK' was not declared in this scope
SPI_screwup:27: error: 'SPI_CTAR_DBR' was not declared in this scope
SPI_screwup:30: error: 'SPI0_CTAR0' was not declared in this scope
SPI_screwup:31: error: 'SPI0_CTAR1' was not declared in this scope

Donziboy2
03-22-2013, 11:28 AM
Ok, now with my dunce cap on I will answer my own question....

You have to have the Teensy 3 selected under Board in the Arduino IDE. :eek:

Donziboy2
03-24-2013, 01:18 PM
Ploveday is SPI_SR_TXCTR part of a library or do i just set it up as an a value?
What sets its value in the first place?

When I drop your last code example into the main loop it gives me "SPI_screwup.ino:76:3: error: 'SPI_SR_TXCTR' was not declared in this scope" .

ploveday
03-25-2013, 12:36 AM
My apologies, that one is missing from the mk20dx128.h file it seems, I forgot I had added my own define for it.


#define SPI_SR_TXCTR 0x0000f000

- Peter

Donziboy2
03-25-2013, 02:01 AM
Awesome Thanks :cool:

dgarcia42
03-25-2013, 08:06 AM
One of the things that I've been doing with the FastSPI_LED2 library is making it so that the portions related to fast spi are usable on their own, even without anything having to do with LEDs - and across all the arduino-friendly platforms for bonus. This weekend i've been putting in support for using the teensy 3's SPI directly rather than the arduino emulation layer and right now I'm pushing ~20Mbps (real data rates) out to the LPD8806 strip (best I can pull off of an AVR is about 6.5Mbps). I'm still doing some cleanup with it, and then want to get DMA support in, and then i'll throw up a 3rd preview of the library with the teensy SPI tunings. It would've saved me a couple of hours if I had found this thread earlier today, though :) What i've got going is pretty similar, code wise, to what's in here. Alas, at this data rate the LPD8806's seem to like to glitch :/

Donziboy2
03-25-2013, 02:17 PM
dgarcia42 have you tried putting your outputs on a logic analyzer, it may be since your running at such high rates that your running in limited voltage range which may mess with the LPD8806's.

dgarcia42
03-25-2013, 05:59 PM
There might be something to that, if I ground the other end of the strip as well as supply 5v to power at that end as well, then I can get up to 14-15Mbps for up to about 200-210 leds, then I start seeing glitching again. Any thoughts on what I can do to work around this - or is this just a limitation with the chipsets? (I've seen this in the past with various other SPIish chipsets - the longer the run, the more likely there's glitching at higher data rates).

Donziboy2
03-25-2013, 07:40 PM
There is a limit to the number of chips a single output pin on a device can drive. Each LPD8806 draws a small amount of current on the signal lines. The datasheet for them is very poorly created and lacks information that would tell us how much current they draw for signals.

If you have access to an oscilloscope I would try that, go down to 100 led's and see what your signals look like then go up to 200 and look at the same signals.
Im not sure you can see the voltage ranges using a logic analyzer also.

If its a matter of overdraw on the pin, there are devices that can allow you to enhance the signal in the line.

dgarcia42
03-25-2013, 08:11 PM
Yes, but it's not just length - it's a combination of data rate and length. The slower the data rate, the longer runs that I can get. I don't have an oscilliscope, unfortunately - just a seale logic analyzier. To be fair, a 10Mbps data rate is fantastic, but I'd love to be able to pull everything out of here that I can, if possible.

This is an area of electronics where my "off the top of my head" knowledge falls pretty short - what kinds of things would you suggest for enhancing the signal in the line? (How much of this is related to the teensy 3's data pins being 3.3v instead of 5v?)

PaulStoffregen
03-25-2013, 09:10 PM
what kinds of things would you suggest for enhancing the signal in the line?


I'd try CAT6 cable, with the clock and data on 2 of the colored wires, and all 6 other wires (or at least all 4 white wires) connected to ground. The ground wires must connect to Teensy 3.0 and also to the LPD8806. I'd use 100 ohm resistors between the Teensy 3.0 pins and the colored wires.

This is called source termination. There are better ways (used by USB, Ethernet, even DDR2 memory), but they usually result in lowering the signal voltage, so they don't tend to work with ordinary chips unless you build a very special driver circuit.



(How much of this is related to the teensy 3's data pins being 3.3v instead of 5v?)

On the OctoWS2811 page (http://www.pjrc.com/teensy/td_libs_OctoWS2811.html) there's a section called "Signal Quality" that talks about these problems. The issue is basically the same, except the 3.3 volt level is closer to the threshold that a LPD8806 recognizes high to low, so any ringing or cross-coupling of signals from the other wires has less voltage margin than if the signal had been 5 volts.

dgarcia42
03-25-2013, 09:22 PM
I'm seeing this glitching with a fairly short run of wires (like ~3 inches) from the teensy directly to the lpd8806's - I've got the data, clock, and ground lines from the far end of the strip grounding to the teensy's ground at the moment as well.

From experimenting, it looks like I can push up to 150 leds at 20Mbps before I start to see glitches towards the end of the line with the above setup. (Of course, combine that with a multiplexer and I can have N-150 led strips that I can push, in aggregate, at 20Mbps - the library allows you to define an arbitrary object as a "selector" for a line - so while right now a pin is the default to select a given pin hi/low, the selector object could be a set of pins and hi/low arrangements for them if, say, one were to be driving a multiplexer :).

I'll try the 100Ohm resistors between the teensy and the clock/data lines and see what i get. Thanks for the info!

Donziboy2
03-26-2013, 12:59 AM
Took a closer look at some of the datasheets I can find. So from what I can see you send in data on one side and it sends it out, so its not voltage level related... The thing i find strange is all your lines from the uController go to the first chip and it propagates to the next... So your receiving and sending those blocks up to or over 150 times... Think I would rather play the lottery.

dgarcia42
03-26-2013, 01:10 AM
I don't recall whether the LPD8806 actively regenerates/re-sends the signals (which the ws2811's do) or if it just routes the signal through to the out pin otherwise untouched. That said, I've had good luck with a number of chipsets for upwards of 400-500 leds with no problems. Also, to be fair, I only have problems with the LPD8806 when I try to go longer than 150. I can do 150 leds at 20Mbps right now (or ~5000fps if I wanted to do nothing but update leds :).

Donziboy2
03-26-2013, 11:20 AM
Thats the elephant in the room dgarcia42 there is no proper documentation on the LPD8806, even the Chinese stuff is lacking. Its as if they learned from our mistakes of making IC documentation with all the relevant information to remake that device.....

https://solarbotics.com/download.php?file=1889 <found the best one so far.


"VCC: Power supply voltage is 3.3-5.5V, recommend an external the 10uF decoupling capacitor." <595's will act erratic in large numbers if you don't decouple near each one. But 10uF is a little large? I use 100nF on 595's.

Recommended Data/clk freq is odd....
345
Delay times :)
346

Can you swap your LPD8806 Strings and see if that makes it better or worse? You may have a bad chip somewhere.

As a Test Tech I learned to always check the signal first, if its not there or it does not look right then something is wrong.

PaulStoffregen
03-26-2013, 11:38 AM
The WS2811 documentation is terrible too. :(

Donziboy2
04-09-2013, 11:37 AM
So 5 minutes after I post this I come across a similar thread that answers my dumb question..... If I go down to - void spi_send_bytes(uint8_t *data, int len) and change it to void spi_send_bytes(uint8_t *data, int) ...
WTB a way to kick myself in the arse.


Ok, I dont really want to start yet another thread. So I have reinstalled my dunce cap yet again, I am playing with Ploveday's example and I am setting it up so I can send groups of data.

As you can see below I have been trimming the fat to suit my needs. Atm I just want it to send predefined data so I can look at the timing on my OpenBench Logic Sniffer, I dont need a CS pin for this since it will be talking to TLC5940's and they don't use CS like most SPI devices. I just want to make sure I can reach 24MHz.
The errors are.

SPI_WIP.ino:25:40: error: expected ',' or '...' before numeric constant
SPI_WIP.ino:105:40: error: expected ',' or '...' before numeric constant

Line 25 and 105 are just after uint8_t gsData, and void spi_send_bytes. So I assume its something I did, or didn't do.

If I comment out void spi_send_bytes and whats in my loop it compiles...

I think I will create a special lighted dunce cap just for these occasions.



//////////////////////////////////////////////////////////
//Code example provided by Ploveday at PJRC forums.

//////////////////////////////////////////////////////////




#include <SPI.h>

#define TLC5940_N 1
#define SPI_SR_TXCTR 0x0000f000
#define len 24
//Define SPI clock speed:
#define BAUD_DIV 0 /* 24MHz SPI */
//#define BAUD_DIV 1 /* 12MHz SPI */
//#define BAUD_DIV 2 /* 8MHz SPI */
//#define BAUD_DIV 3 /* 6MHz SPI */
//#define BAUD_DIV 4 /* 3MHz SPI */

//Globals/members:
uint32_t ctar0, ctar1, mcr;

uint8_t gsData[24 * TLC5940_N] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000001,
0b00000000,
0b00100000,
0b00000100,
0b00000000,
0b10000000,
0b00010000,
0b00000010,
0b00000000,
0b01000000,
0b00001000,
0b00000001,
0b00000000,
0b00100000,
0b00000100,
0b00000000,
0b10000000,
0b00001111,
0b11111111,
};




void setup(){
//Init code:
// First set up SPI via library
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);

// Now reconfigure some stuff

// remember MCR
mcr = SPI0_MCR;

// Use both CTARs, one for 8 bit, the other 16 bit
ctar0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(BAUD_DIV) | SPI_CTAR_CSSCK(BAUD_DIV) | SPI_CTAR_DBR;
ctar1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(BAUD_DIV) | SPI_CTAR_CSSCK(BAUD_DIV) | SPI_CTAR_DBR;

SPI0_CTAR0 = ctar0;
SPI0_CTAR1 = ctar1;

//And some macros:

#define SPI_WRITE_8(c) \
do { \
while ((SPI0_SR & SPI_SR_TXCTR) >= 0x00004000); \
SPI0_PUSHR = ((c)&0xff) | SPI0_PUSHR_CTAS(0) | SPI0_PUSHR_CONT; \
} while(0)





/*
#define SPI_WRITE_16(w) \
do { \
while ((SPI0_SR & SPI_SR_TXCTR) >= 0x00004000); \
SPI0_PUSHR = ((w)&0xffff) | SPI0_PUSHR_CTAS(1) | SPI0_PUSHR_CONT; \
} while(0)

#define SPI_WAIT() \
while ((SPI0_SR & SPI_SR_TXCTR) != 0); \
while (!(SPI0_SR & SPI_SR_TCF)); \
SPI0_SR |= SPI_SR_TCF;
*/
}

void loop(){

spi_send_bytes(gsData, len);

}

void spi_send_bytes(uint8_t *data, int len)
{
for (int i=0; i < len; i++)
SPI_WRITE_8(data[i]);
}

ploveday
04-09-2013, 12:09 PM
Change the name of your len define to something less generic, like MY_LEN or something.

It's conflicting with something in the headers and causing unexpected errors.

Or actually, conflicting with your own code, as you've now noticed. Anyways, change that name :)

- Peter

Donziboy2
04-09-2013, 10:43 PM
Proof that it does infact run at 25Mhz.

This is 192 bits sent 4 times then a pause.
368

367

Markus_L811
04-23-2013, 07:36 PM
Change the name of your len define to something less generic, like MY_LEN or something.

It's conflicting with something in the headers and causing unexpected errors.

Or actually, conflicting with your own code, as you've now noticed. Anyways, change that name :)

- Peter

Hello Guys,

Is there anywhere the complete lib with the faster SPI support?

Looking around and don't find the SPI.h in this thread

dgarcia42
04-23-2013, 08:02 PM
The SPI code in the fastspi_led2 library will be usable for just straight SPI work (at least writing) - but i'm still doing tuning work with it. While I've been able to get the SPI output to run at a 24Mhz(ish) clock - irritatingly enough, the SPI subsystem insists on inserting extra delays between transfers, so my real data rate is capped at about 22.5Mbit of data, and attempting to run with the clock set to continuous is a bit of a disaster in the making. However, that's not the library they're referring to up there.

Markus_L811
04-23-2013, 08:38 PM
The SPI code in the fastspi_led2 library will be usable for just straight SPI work (at least writing) - but i'm still doing tuning work with it. While I've been able to get the SPI output to run at a 24Mhz(ish) clock - irritatingly enough, the SPI subsystem insists on inserting extra delays between transfers, so my real data rate is capped at about 22.5Mbit of data, and attempting to run with the clock set to continuous is a bit of a disaster in the making. However, that's not the library they're referring to up there.

You extracted the SPI-Code from the fastspi_led2? Whats about the Sd2Card library and the Teensy 3.0 Part did you take a look at this?

https://github.com/manitou48/teensy3/blob/master/spiperf.ino

dgarcia42
04-23-2013, 08:43 PM
No - I didn't extract it, I wrote it. There are spi classes in there that can be used for writing to SPI independently of just writing to LED library (for both hardware ARM and AVR SPI as well as bit-banging emulation (that runs at 4.5Mbit on the teensy 3) if you don't want to use the hardware SPI port - and working on adding DMA support for the teensy 3) - once I finish the LED library i'll see about making it work for generic reading as well. The interfaces need some cleaning up before they get used for general work though.

I don't have anything to do with the sd2card library.

What, specifically, are you looking for?

Markus_L811
04-24-2013, 06:35 AM
I wrote it
My bad I don't know.

What, specifically, are you looking for?
For a fast SPI library.

dgarcia42
04-24-2013, 08:01 PM
Right, but more specifically - are you just looking for something to write data out over SPI as quickly as possible? Are you looking for something that can read as well?

Right now the SPI class in my library is focused on writing SPI data, but not reading, also it's tuned to the led strips that my library works with - there may be things that I need to do to make it a bit more generically useful, but without some more details I can't tell whether or not what I have now would be useful for you.

btmcmahan
05-23-2013, 04:14 AM
I just did some tests and got a max serial transfer rate of 1843200. I got to this number by doing 115200 *2 *2 *2 *2 =1843200. I don't know that this is the scientific way of testing it, but I was able to get reliable communication between 2 teensy3.0's using the SerialHandler library I used for arduino a while back.

Here's my issue, and maybe someone can point me in a better direction:
I am using two sets of (teensy 3.0 to control a stepper driver), and a third teensy3 to be the master controller. I am pulsing the stepper drivers on inturrupts every 75uSec, so I wanted to achieve speeds fast enough to sneak in transmissions between pulses. I know my SerialHandler is adding a few extra bytes to each transmission, but I don't know enough about checksums to do my communication without it, although I am looking into it.

Will interrupts hurt my serial transmissions, or am I just worrying too much about this? And does Serial2 & Serial3 not transfer as fast as Serial1? I would really love to work with SPI and get these super fast speeds, but I would need to send from one teensy and READ from the other. Any ideas?

adrianfreed
05-23-2013, 05:10 AM
I've considered writing a high performance SPI library. But at this point, there's 3 major problems.

1: It would depend on collaborating with others to support non-Teensy boards like Due and Maple.



I tried to test our OSC library on maple but their IDE is just too old (no stream class). It looks like they are just going to fade out because they don't have
the resources to move libraries and stay up on the latest IDE versions.
For me the board to watch is the Fubarino Mini. It has much in common performance wise with the Teensy 3 and an interesting
capacitance sensing scheme.

PaulStoffregen
05-23-2013, 06:25 AM
Rick Anderson gave me a Fubarino Mini this weekend at Maker Faire. I tested it for the first time today. It is indeed fast, almost as fast as Teensy 3.0 with the Serial.available() & Serial.read() test. However, it too lacks the Arduino Stream class, so no Serial.readBytes().

Donziboy2
05-23-2013, 11:23 AM
The problem with the Maple is that the creators aren't really doing much with it, they have put all their new boards on permanent hold. The current maple has tons of power including 2 SPI with DMA, but nobody is really working on it. I considered asking the same questions there as I have here, and in other posts I have going but I fear they will go in about the same direction as here, nowhere.

There current chip has STM32F103.

Serial peripheral interface (SPI)
Up to two SPIs are able to communicate up to 18 Mbits/s in slave and master modes in fullduplex
and simplex communication modes. The 3-bit prescaler gives 8 master mode
frequencies and the frame is configurable to 8 bits or 16 bits. The hardware CRC
generation/verification supports basic SD Card/MMC modes.
Both SPIs can be served by the DMA controller.

They where working on a STM32F407 but stopped I believe.

Serial peripheral interface (SPI)
The STM32F40x feature up to three SPIs in slave and master modes in full-duplex and
simplex communication modes. SPI1 can communicate at up to 37.5 Mbits/s, SPI2 and
SPI3 can communicate at up to 21 Mbit/s. The 3-bit prescaler gives 8 master mode
frequencies and the frame is configurable to 8 bits or 16 bits. The hardware CRC
generation/verification supports basic SD Card/MMC modes. All SPIs can be served by the
DMA controller.
The SPI interface can be configured to operate in TI mode for communications in master
mode and slave mode.

I drooled, and then noticed that nobody had done anything in weeks/months..... :(

adrianfreed
05-23-2013, 02:54 PM
Rick Anderson gave me a Fubarino Mini this weekend at Maker Faire. I tested it for the first time today. It is indeed fast, almost as fast as Teensy 3.0 with the Serial.available() & Serial.read() test. However, it too lacks the Arduino Stream class, so no Serial.readBytes().

Yes, at least MPIDE 23 has a stream.h (Maple doesn't) but it is not the Arduino one with the block readBytes() as you note.
I am optimistic that by the end of the year all the major forked IDE's for variants will synchronize to 1.5. Some of the cases are really easy to do
such as Flora.

PaulStoffregen
05-23-2013, 06:25 PM
I am optimistic that by the end of the year all the major forked IDE's for variants will synchronize to 1.5.


Really?

MPIDE might, since Rick and Mark wrote much of the "platforms" code that became Arduino 1.5.x. But I had a conversation with Rick at Maker Faire. Among several topics, he talked about porting newer Arduino code into MPIDE (which appears to be mostly based on Arduino 0023). He never mentioned a package for 1.5.x.

The many clones that are only AVR chips using the Arduino core (with little or no customization) are likely to support 1.5.x. It's really made for them.

I plan to start supporting it at 1.5.3. It's probably going to be a lot of work, so I'm really not looking forward to it...

I really doubt others will support 1.5.x as an add-on. Completely forking is simply a lot easier. Most people take the easiest path.

Markus_L811
05-23-2013, 07:18 PM
Really?

MPIDE might, since Rick and Mark wrote much of the "platforms" code that became Arduino 1.5.x. But I had a conversation with Rick at Maker Faire. Among several topics, he talked about porting newer Arduino code into MPIDE (which appears to be mostly based on Arduino 0023). He never mentioned a package for 1.5.x.

The many clones that are only AVR chips using the Arduino core (with little or no customization) are likely to support 1.5.x. It's really made for them.

I plan to start supporting it at 1.5.3. It's probably going to be a lot of work, so I'm really not looking forward to it...

I really doubt others will support 1.5.x as an add-on. Completely forking is simply a lot easier. Most people take the easiest path.

The both way path that Arduino walk at the moment make me tiered. There is 1.5.x for the Due mostly and 1.0.x for Teensy and other Arduino-Stuff or Arduino-like. It's one thing to have 2 folders for hardwarespecific librarys but 4 or more with both IDE's and the Teensy it's hard to find the librarys where I lost it. 1.5.x is still beta but works good for me. Btw. I don't think they make there work easyer with porting in every way from 1.0 to 1.5 and back.

btmcmahan
05-26-2013, 12:34 AM
Donziboy, where did you get these numbers from? I've been looking at the datasheet, but I still don't understand the correlation between
0x000f000 and 0x0004000.

Can you explain how you determined 0x0000f000


#define SPI_SR_TXCTR 0x0000f000



and how you got 0x00004000


#define SPI_WRITE_8(c) \
do { \
while ((SPI0_SR & SPI_SR_TXCTR) >= 0x00004000); \
SPI0_PUSHR = ((c)&0xff) | SPI0_PUSHR_CTAS(0) | SPI0_PUSHR_CONT; \
} while(0)

adrianfreed
05-26-2013, 12:51 AM
Really?

MPIDE might, since Rick and Mark wrote much of the "platforms" code that became Arduino 1.5.x. But I had a conversation with Rick at Maker Faire. Among several topics, he talked about porting newer Arduino code into MPIDE (which appears to be mostly based on Arduino 0023). He never mentioned a package for 1.5.x.

The many clones that are only AVR chips using the Arduino core (with little or no customization) are likely to support 1.5.x. It's really made for them.

I plan to start supporting it at 1.5.3. It's probably going to be a lot of work, so I'm really not looking forward to it...

I really doubt others will support 1.5.x as an add-on. Completely forking is simply a lot easier. Most people take the easiest path.

Yes, in fact after finishing that first release of OSC for Arduino, I switched to working on what is needed to support Fubarino MINI. There is enough of a stream.h to do what the OSC SLIP library needs. However there are some surprises in MPIDE that make me nervous. For example, I like to read all the analog inputs on a platform by a call to analogRead() enumerating the channel number from 0,1,2,3 until the number of analog inputs. They seem to have interpreted things so that you have to pass in A0, A1, A2 etc which are symbolic and I can't enumerate:


int analogRead(uint8_t pin)
{
int analogValue;
uint8_t channelNumber;
uint8_t ain;

/* Check if pin number is in valid range.
*/
if (pin >= NUM_DIGITAL_PINS_EXTENDED)
{
return 0;
}
/* Pin number is allowed to be either the digital pin number or the
** analog pin number. Map the input so that it is guaranteed to be
** an analog pin number.
*/
ain = (pin < NUM_DIGITAL_PINS) ? digitalPinToAnalog(pin) : NOT_ANALOG_PIN;
if (ain == NOT_ANALOG_PIN) {
return 0;
}



Fubarino MINI has little to offer for most applications over the Teensy 3.0 - just a few easier to reach pins. However
the PIC32 capacitance sensing module is more flexible and can do unusual things like time to digital conversion.

Donziboy2
05-26-2013, 03:38 PM
Donziboy, where did you get these numbers from? I've been looking at the datasheet, but I still don't understand the correlation between
0x000f000 and 0x0004000.

Can you explain how you determined 0x0000f000


#define SPI_SR_TXCTR 0x0000f000



and how you got 0x00004000


#define SPI_WRITE_8(c) \
do { \
while ((SPI0_SR & SPI_SR_TXCTR) >= 0x00004000); \
SPI0_PUSHR = ((c)&0xff) | SPI0_PUSHR_CTAS(0) | SPI0_PUSHR_CONT; \
} while(0)


I did not come up with them read the rest of thread. It is Plovedays code not mine.

btmcmahan
05-26-2013, 04:18 PM
My mistake, but really I'm directing these questions to anyone who knows the answer. I see that the 0x0000f000 is used to as a mask to isolate the TXCTR bits, I just don't understand why you only PUSHR when the TXCTR is >= 4. Does it have to do with the minimum frame size, or am I missing some basic concept?

btmcmahan
05-27-2013, 03:09 AM
I spent all day trying to start a SPI slave sketch, and it's making me crazy. I can't even get any data to shift into the RX FIFO registers. At least I think it isn't shifting in, I can't increment the RXCTR (in the SPI0_SR register).

I've read through the SPI section of the datasheet many times now, and I'm just stuck.
I'm using Plovedays code for my master (modified, sending 2 bytes of 8 bits). It was working for another application.

I'm using SPI0_MCR=0x00000000 and SPI0_CTAR0_SLAVE=0x38000000. This should put me in slave mode and a FMSZ size of 7.
From what I get from the datasheet, (I thought) the data should shift in automatically if it is in SLAVE mode & getting the clock signal.
But it isn't doing that.
Using SS pin 10 active low.

Is there something I need in my sketch to get this going? I've tried pullup resistors, I've even tried clocking it by hand.
I'm sorry to keep asking stupid questions, I probably sound like a complete newb, but I'm ok with that.

Also, whats up with the "grayed out" SPI pins on the pinout card that comes with the Teensy3? I even tried those.

Here's what I'm working with...


//Globals/members:
uint32_t ctar0, ctar1, ctar_slave, mcr;
bool serialPrint_ONS=LOW;

void setup(){
Serial.begin(57600);

pinMode(SS, INPUT);
pinMode(SCK, INPUT);
pinMode(MISO, INPUT);
pinMode(MOSI, INPUT);

SPCR =0x40; // |= _BV(SPE); //From arduino SPI...I still get error is this is missing?
mcr = SPI0_MCR;
SPI0_MCR=0x00000000;

SPI0_CTAR0_SLAVE = 0x38000000;
}

void loop(){

if(!serialPrint_ONS){
Serial.print("SPIO_MCR: ");
Serial.println(SPI0_MCR,BIN);
Serial.print("SPIO_CTAR0_SLAVE: ");
Serial.println(SPI0_CTAR0_SLAVE,BIN);
Serial.print("SPI_SR: ");
Serial.println(SPI0_SR,BIN);
Serial.print("SPI_RXFR ");
Serial.println(SPI0_RXFR0,BIN);
Serial.println();
delay (1000);
}
}

Donziboy2
05-27-2013, 11:36 AM
Sadly I have no clue how to work with the SPI Slave. I am kind of in limbo with my project atm, from everything I have seen I probably wont be using a Teensy for much longer. I am also taking a hiatus from my project.

cmason
05-27-2013, 05:55 PM
I spent a bunch of time messing with the SPI unit before finally getting it to work. I haven't tried to use it as a slave. Three things that helped me:

Make sure you enable the clock to the SPI unit:


// Enable Clock to SPI. from page 241 of Kinetis K20 Reference Manual.
SIM_SCGC6 |= SIM_SCGC6_SPI0;
// wait for clocks to come up.
delay(1000);

Make sure that you re-enable the pins after configuring the SPI:


// do this after you've configured the SPI unit:
CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN12_CONFIG = PORT_PCR_MUX(2);
CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);

I found that doing this after configuring the unit was essential.

I also shifted the clock signal to pin 14 so I could use the LED to debug:


// It is VERY IMPORTANT that the pins be reassigned AFTER ALL
// SPI initialization INCLUDING datamode or bitorder etc.

// First reassign pin 13 to the default so that it is not SCK
CORE_PIN13_CONFIG = PORT_PCR_MUX(1);
pinMode(13, OUTPUT);
// and then reassign pin 14 to SCK
CORE_PIN14_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);

The code I wrote (http://hg.cmason.com/teensy3/src/d4eefa8bc59c249aedae2a1f0173a87fad867966/teensy/T3SPI.h?at=default) is for SPI master, but may be helpful.

If you have further issues, you may want to consider starting a new thread, as this one has wandered off somewhat. :)

-c

btmcmahan
05-27-2013, 11:33 PM
Unfortunately, no luck with those edits. I did try using the pull-down resistors on the clock too. And dropping the DSE since it isn't an output pin

For future reference, I'm moving to a more specific thread I found a little while ago:
Teensy 3.0 as SPI Slave (http://forum.pjrc.com/threads/23428-Teensy-3-0-as-SPI-Slave)

btmcmahan
05-29-2013, 04:09 AM
I'm receiving SPI data on my slave. I have a lot of cleanup to do with the logic, but I'm getting data.
Thanks CMASON & PLOVEDAY...I'm using big chunks of code that you two did before me.
I'll try post something more significant in the next couple of days.

btmcmahan
06-02-2013, 07:30 AM
Teensy3 SPI Master/Slave is ready for anyone interested.

Teensy 3.0 as SPI Slave (PJRC Forum) (http://forum.pjrc.com/threads/23428-Teensy-3-0-as-SPI-Slave)
Teensy3.0 SPI Master & Slave Set (on GitHub) (https://github.com/btmcmahan/Teensy3_SPI.git)