chipKIT® Development Platform

Inspired by Arduino™

Multiple hardware SPI on Max32?

Created Mon, 28 May 2012 18:47:16 +0000 by rasmadrak


rasmadrak

Mon, 28 May 2012 18:47:16 +0000

Hi there,

I've been having seemingly random errors with the SD card library and other SPI devices - in which they both work separately but sometimes not together. Most of the time they do work, but a simple thing as changing the cables or reprogramming make them stop working. This makes me think it's a timing issue or that the MISO line is held high etc by the SD card/other SPI device.

So I figure I could use two different hardware SPI's, which would (hopefully) eliminate this issue?

Have I interpreted the reference manual correctly below?

SPI 1 (default, really SPI2?): MISO 50 ECRX/SDA2/SDI2A/U2ARX/PMA4/CN9/RG7 MOSI 51 ERXDV/AERXDV/ECRSDV/AECRSDV/SCL2A/SDO2A/U2ATX/PMA3/CN10/RG8 SCK 52 ECOL/SCK2A/U2BTX/U2ARTS/PMA5/CN8/RG6 SS 53 ERXCLK/AERXCLK/EREFCLK/AEREFCLK/SS2A/U2BRX/U2ACTS/PMA2/CN11/RG9

SPI 0 (non default, really SPI1?): 0 SDA1A/SDI1A/U1ARX/RF2 1 SCL1A/SDO1A/U1ATX/RF8 18 AETXD1/SCK1A/U1BTX/U1ARTS/CN21/RD15 19 AETXD0/SS1A/U1BRX/U1ACTS/CN20/RD14

Using DSPI and DSPI0 I get the default SPI working - but how come it's called DSPI0 and not DSPI2? What would the latter of the two SPI ports above be called in the DSPI library?

And finally - will this work? Are they independent and doesn't interfere with each other? Can both use interrupted transfers simultaneously?

Thanks in advance!


rasmadrak

Wed, 30 May 2012 11:28:42 +0000

Hasn't anyone used multiple hardware SPI's before? Maybe Gene Apperson at Digilent can answer this? :)


rasmadrak

Fri, 01 Jun 2012 23:03:36 +0000

Found this in the header-files:

#define PIN_DSPI0_SS 53 #define PIN_DSPI1_SS 74 #define PIN_DSPI2_SS 19 #define PIN_DSPI3_SS 15

Which should mean that DSPI1 = SS1 in the reference manual, DSPI2 = SS1A and DSPI3 = SS3A. The rest of the SPI information follows the same naming standard etc.

If I understood correctly, this should be correct:

DSPI0 (Standard SPI): 50 SDI2A 51 SDO2A 52 SCK2A 53 SS2A

DSPI1: 20 SDI1 3 SDO1 38 SCK1 74 SS1

DSPI2: 0 SDI1A 1 SDO1A 18 SCK1A 19 SS1A

DSPI3: 17 SDI3A 16 SDO3A 14 SCK3A 15 SS3A

Hope this helps anyone and that it does, in fact, work. :)


skyjumper

Sat, 14 Jul 2012 21:30:14 +0000

Did it actually work?


Jacob Christ

Sat, 14 Jul 2012 21:58:02 +0000

Are you correctly changing clock and data polarity and phase for the two SPI devices you are communicating with?

Jacob


rasmadrak

Mon, 16 Jul 2012 09:53:14 +0000

I haven't gotten time to test it actually, I'm currently remaking the electronics so the SPI ports have not been hooked up yet. But I see no reason why it shouldn't work, unless the clock cannot be independently set etc for each SPI port... :)

I use the same clock and data polarity for both devices, and it has been working excellently until it all of a sudden didn't work any more. I can't recall doing any changes and they both work, just not together.

Hopefully the new setup will allow me to stream data to the display "under the hood" while doing other stuff in the meantime. If I ever get the SD library converted to a DSPI one, the same would go for loading data as well... :)


majenko

Mon, 16 Jul 2012 10:31:59 +0000

It is quite common for an SD card to not play nicely on the SPI bus with other peripherals. This is a problem we have seen in the RetroBSD project in the past.

It is recommended to keep the SD card on its own SPI bus, or to isolate the SD card from the bus using a buffer chip of some kind (like the 74HC245) which can be controlled by the CS line.


Jacob Christ

Fri, 20 Jul 2012 20:51:33 +0000

It is quite common for an SD card to not play nicely on the SPI bus with other peripherals. This is a problem we have seen in the RetroBSD project in the past.

Unlike most SPI devices SD require some pins to be pulled high. I don't recall exactly which pin is required to be pulled high, so we just pull them all high.

Jacob


rasmadrak

Tue, 24 Jul 2012 23:32:36 +0000

By manually setting each of the four SPI-pins to high before attempting to read? Hmm.. I don't think I've tried this.

Some day soon I'll hopefully have a little time left to do some actual electronics work on the pinball. Been busy assembling the playfield lately. :)

(Feel free to check it out at [url]http://poormanspinball.blogspot.com[/url])


mikes

Tue, 24 Jul 2012 23:56:20 +0000

By manually setting each of the four SPI-pins to high before attempting to read?

No by putting a resistor with one side attached to 3.3v and the other attached to the spi pin of the card


rasmadrak

Tue, 21 Aug 2012 00:41:10 +0000

Just wanted to report back that multiple SPI's work like a charm! :)

I've connected the SD card to the regular SPI port and the LED-display to the SPI1 port and I'm currently running the display while checking if a file exists on the SD card. I'm not even toggling the slave selects as there's no need (correct?), or at least they doesn't seem to be conflicting.

Haven't tried actually reading a file yet, but if it can read that a file exists it should be fine, right?

Very nice! :)


I'm currently streaming video from the SD card and displaying it on the LED-display, so reading files obviously works as well. :)

I'm using DSPI for accessing the second port, btw. If only I could get the SD card to read with DSPI instead so that I could do background buffering! :)


GeneApperson

Wed, 29 Aug 2012 22:41:37 +0000

Sorry that I didn't get in here and answer your questions earlier. I have been too busy to spend much time on the forum lately.

When I designed the DSPI library, I didn't want there to be an association between DSPI object instance and physical SPI controller in the processor. I wanted any sketch that used DSPI1 to work on any board that supported DPI1, no matter which physical SPI port it happened to be hooked up to. The hardware abstraction layer and board variant mechanism is supposed to abstract these details away (for example you don't know or care what physical port and bit correspond to digital pin 3). This is why on some boards, DSPI1 happens to be connected to physical SPI port 2.

Each SPI controller is totally independent from the others, so they have separate clock settings, separate chip selects, etc.

In a future release, I am planning on modifying the SD library to have a variant that will allow passing a DSPI or a SoftSPI object to be used for the SPI interface. This will allow the SD card to be accessed using any SPI controller, or any four pins making up a bit-banged software SPI interface. Unfortunately, there is a bug (feature?) in the current Arduino IDE that makes it virtually impossible to use one library from within another. Once this issue is corrected, I can do the work to allow better abstraction of SPI ports used by libraries (such as SD).

Hope this helps answer some of your questions. Also, if you have a question for me, and I'm not answering (because I don't get on here often enough occasionally) go ahead and send me a private message.

Gene Apperson Digilent


rasmadrak

Fri, 31 Aug 2012 22:04:52 +0000

Thanks for your reply (and excellent work on the DSPI library)!

When you do rewrite the SD library, I suggest redoing it from scratch since it's quite a mess. Global variables are evil and i.m.h.o should be replaced by the much more elegant version of creating an object when needed and being able to discard it when not needed.

But I guess the real problem is balancing different needs for the library - for instance, my application requires no filesystem. I'm perfectly happy reading raw sectors of the SD card but for most users I believe a filesystem would make sense, even if that portion could easily add up to 50% of the time it takes to read small segments of data.

I worked around this by using raw sector reading. Since the file is read only and created by me the offsets of all files are known and computer generated into a header file. And by using the DSPI library hotswapping of cards is now enabled as well (or rather - hotswapping of an identical card or by using some function to determine what card is inserted) by simply checking the card-inserted pin and force a re-init if that pin ever gets toggled. Works wonderfully and at 8 ms/frame compared to almost 15 ms/frame previously.

Multiple SPI's has really saved my butt however. :) I would be interested to learn more about the interrupt transfers eventually - hopefully the SD card loading can be offloaded into a separate "process" to create a poor mans multithreading....


educa

Tue, 04 Sep 2012 21:07:14 +0000

rasmadrak,

Are you using a max32 ?

I am also interested to know how to read a file byte per byte in raw sector read (I don't need fat, but just raw access)

The project I make needs to read 4 bytes at a time, then wait a little and then 4 bytes again over and over.

Could you help me a little in the right direction on how I should read from a SD card in raw mode?

Also are you using hardware SPI for this ? At what speed?

You say you read a frame in 8ms. But how big is a frame? I did tests previously on arduino with reading 512 bytes and that took around 2ms on arduino. I wonder what it would be on chipkit and if there would be speed gain by getting my 4 bytes over raw read instead of trying to read blocks from a fat library ?

Kind regards,

Bart


rasmadrak

Thu, 06 Sep 2012 11:58:44 +0000

Hi there!

Yes, I'm using a Max32 and hardware SPI.

My card may be a slow one, it's unmarked so I don't know for sure - but my frame size is 1536 bytes and gives approx 2.3 ms for a single sector. The code is using CRC checks, but I guess if they're removed a tiny timefactor could be shaved.

As for reading raw sectors - you need to initalize the SD card as usual and send the READ_SINGLE_SECTOR (?) SD-command and use the sector you wish to read as parameter. After that you simply fetch each byte with SPI.transfer(0xFF); Preferably if the SD library is modified (or replaced) to use DSPI you could let the DSPI write directly into a buffer instead of using a local cache first. But the biggest time-thief is the FAT code, which requires a rather hefty amount of processing.

The SD card is "formatted" in my case using "dd if=somebinaryfile.dat of=/dev/my_sd_card".

It's also possible to do a tradeoff using FAT, by letting the FAT structure find the start of the file you need and then read raw sectors. But if you already now the sectors this is just added overhead.


rasmadrak

Thu, 06 Sep 2012 18:51:10 +0000

A little more info:

I've tested to write files to my SD card from a computer and it's pretty blazing fast: 1577909 bytes/sec.... So it's NOT a slow card. :(

In order to use dd successfully (with a Mac) I'm using the following procedure:

  1. diskutil list
  2. find the disk you want to copy to
  3. diskutil unmountDisk /dev/disk1 (for instance)
  4. dd if=flashdisc.bin of=/dev/disk1

Using the regular Mac eject volume did not work for me. With Linux I suspect this is not an issue. With Windows... not a clue!


educa

Thu, 06 Sep 2012 18:59:15 +0000

Did you get that info like Sd init and READ_SINGLE_SECTOR from the sandisk specification ?


rasmadrak

Thu, 06 Sep 2012 19:43:21 +0000

I noticed it's actually READ_SINGLE_BLOCK... :)

But anyway - This particular command is used in the regular SD library as well, but there's plenty of other commands available in the SD specs.

I based my code around the library SDuFAT and took the parts I needed and adapted it to use DSPI instead (changing the transfer functions and adding a begin()).


educa

Thu, 06 Sep 2012 19:47:14 +0000

DSPI = hardware SPI ?

If I use the regular SPI functions, then will I use hardware SPI?

Or is DSPI used by you to select other pins on the controller ?


rasmadrak

Thu, 06 Sep 2012 21:04:55 +0000

I'm using DSPI because it's a better library and it's also easier to port and combine with interrupt driven transfers etc.

But it's still pointing towards the regular SPI (or DSPI0) bus and you could use the regular SPI, but if you're rewriting you might as well improve the library. ;)


Jacob Christ

Fri, 07 Sep 2012 13:35:29 +0000

Is the SPI clock running as fast as it can for talking to SD?

Jacob


rasmadrak

Sun, 09 Sep 2012 19:29:28 +0000

Great catch!

I used to only set the speed once during initialization - but I didn't realize that once initialized the speed can be bumped up MUCH higher! I kept raising and raising the speed and now I'm setting the speed to the following:

Before init: 1 332 000 Hz After init: 13 320 000 Hz (10x!)

The card works with even higher speeds (I've tested up to 35 MHz) but that corrupts the data. It seems that my SD reader is a resistor-based, which I've learned has slower fall/rise times than "proper" SD readers.

This now gives me a nice reading speed of 2.5 ms per 1536 byte frame = 614 KB/sec! As for writing, I have not yet tested - but I figure I could lower the speed and raise it after writing is completed in case there are any problems.

While not 4bit proprietary format-speed, this is a net 3x increase in SD-reading for my pinball machine!

Thanks Jacob! :D


educa

Sun, 09 Sep 2012 19:36:31 +0000

Jacob, how did you raise that speed ? With what commands ???

And you say your card reader is resistor based, but since chipkit is 3.3V can't you connect directly GND,VCC, CLK and MOSI/MISO from chipkit pins to sd card?

I did tonight and it works, but I would like to learn now how to increase that read speed

Hope you can help me a little?

Kind regards,

Bart


rasmadrak

Sun, 09 Sep 2012 19:55:56 +0000

Yes, I might be able to do that - but I am using a breakout SD-board purchased from a non-Chipkit/Arduino store. Connecting directly would most probably be faster. I'm not sure how to change the SPI clock it using the regular SD library, since I'm using a custom one with DSPI. But all I did was this:

sd.setSpeed(LOW_SPEED); initialize_sdcard(); sd.setSpeed(HIGH_SPEED);

Using the regular SD library I figure you could write to the SPI clock register to set the speed after SD.begin(). The SD library does not use the standard SPI wrapper, making it a little difficult to change.

Maybe someone more experienced with the SPI library can pitch in?