SAMD21 SD Card SPI Max Speed

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everyone,

 

With the help of members of this forum I was able to successfully port FATFs to my project which includes SD Card connected to SAMD21 via SPI Interface. I am now trying to optimise the code in order to achieve maximum speed for reading and writing. I have read on Atmel knowledge database that the maximum frequency that the SPI interface of SAMD21 can achieve is 12MHz this is due to limitations of the Silicon.

 

At 12MHz a single write takes about 12ms which includes f_open f_write and f_close. I am not sure if this is the maximum speed that can be achieved at 12MHz bus speed, since I understand that the FATFS stack also consumes a portion of this time to do its stuff. Does anyone here have experience with SD card benchmarking specially with SAMD20/21 and could give me some hints as to how I can further optimise the process to reduce the time.

 

Thanks in advance.

Best regards,

Owais.

Last Edited: Thu. Oct 15, 2015 - 11:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Pretty sure there are some benchmark results on the FatFs site?

 

I'd start by looking at them to see if you're already in the right ballpark...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

12 MHz is a conservative number. You can go up to 16 without any problems if your board layout is decent (don't try that on breadboards and breakout boards connected with wires).

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have not run the SPI faster than 12MHz.    I might try this later.   Mind you,  12MHz is reasonably quick.

You should be able to read/write to the microSD SPI with DMA.    I have not done this yet.

 

There is as MMC example for the SAMD21_XPRO from ASF.   I have not run this either.

 

I reckon that DMA at 12MHz will give you the "best" results.   Especially if you are running your Application logic simultaneously.

I am sure that someone,  somewhere will have experimented with this.    Possibly with "another make or class" of ARM-Cortex chip.

 

Incidentally,   I have no problem with running Xmega SPI at 16MHz.   I do not see why the D21 should not be ok too.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

osyed wrote:
With the help of members of this forum I was able to successfully port FATFs to my project which includes SD Card connected to SAMD21 via SPI Interface.

Do you use ASF?

 

The (non-DMA) ASF SPI functions do introduce quite an overhead between bytes - so there could well be room for optimisation there.

 

Or, as David said, try DMA ...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the suggestions.

 

I am not using ASF I have implemented my own functions for SPI Transfers.

 

I am also looking into if there is room for increasing the clock for the SPI interface as alex said it could run at 16MHz as well.

 

Since I am using the DFLL generating 48MHz as source for GCLK0 which I have selected for SPI the only possible combination of clock from the following formula is either 24MHz or 12MHz

 

Fbaud = Fref / 2(Baud + 1)

 

I am looking into if I can use the FDPLL96M as a source for SERCOM0 that way I will be able to get 16MHz by using a baud value of 2.

Best regards,

Owais.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I would stick with 12MHz for the moment.

Have you looked  to see whether you have "gaps" in the SPI?

Using the "one-byte-buffer" can make quite a difference.   Likewise inline function calls.

 

DMA will give you the "best" performance.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Absolutely!

 

You need to find where the real bottlenecks are before you start trying to "optimise" stuff which might not be to any (significant) benefit!

 

Again, how does your performance compare to the figures on the FatFs site?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

why can't it do 24MHz like competitors' ? w/DMA, SDIO 1 bit or 4 bits.

Last Edited: Sat. Aug 15, 2015 - 09:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your suggestions.

 

I have managed to squeeze the duration a bit by removing an unnecessary delay in the transfer function where I was waiting for the SPI module RXC bit in the INTFLAG register. Besides this I cannot see anything which is producing overhead.

 

@David what do you mean by gaps in SPI can you please elaborate on this and also the one-byte-buffer what does that refer to exactly? I have changed the transfer function to static inline as well.

 

As to the DMA suggestion, my application is such that I have 20 bytes per transfer, this rate is fixed by an external device which can transmit 20 bytes at a time so I have to write 20 bytes to the SD card as soon as I receive and write to SD card until the external device stops sending. I am not sure how DMA would help in this case?

 

Thanks for your suggestions.

Best regards,

Owais.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

osyed wrote:
@David what do you mean by gaps in SPI

literally that - gaps between successive bytes in the SPI transfer!

 

+--------+                 +--------+                 +--------+
| a byte | ... a "gap" ... | a byte | ... a "gap" ... | a byte | ... a "gap" ... 
+--------+                 +--------+                 +--------+

 

one-byte-buffer what does that refer to exactly?

That is,

  1. load & start transmission of a byte over SPI;
  2. when done, check if there's more to send;
  3. if there's more, fetch the next byte;
  4. GOTO 1.

 

During steps 2-3, there is no transmission happening on the SPI - so this will cause gaps; if the code here is slow/bloated, they will be BIG gaps!

 

 

Last Edited: Mon. Aug 17, 2015 - 07:40 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for explaining that awneil.

 

I have done some benchmarking by performing a 2048 bytes write on the SD card. I have measured the timing it takes between f_open f_write and f_close. It sums up to about 20ms which makes the writing speed about 100KB/sec, I have also checked some test results on fatfs website and the result is much better as compared to 128MB(77KB/sec) and 512MB(28KB/sec) card.

Best regards,

Owais.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In theory,   SPI can have a continuous clock.   i.e. you get no gaps in between bytes.

To do this,  you need a one-byte transmit buffer.    So you can write to this buffer while it is transmitting the current byte.    As soon as this completes,  it sends the byte from the buffer.

 

The regular SPI peripheral in an AVR has no buffer.   You can not write to SPDR until the current byte has been shifted out.   i.e. you have to wait for SPIF.

The USART_MSPI peripheral in a modern AVR does have a buffer.   (it is the same as used by the UART).   You just need to check UDRE before writing to UDR.

 

The SPI in an ARM tends to have a buffer.    After all the SERCOM is capable of UART, SPI, I2C, ...

Other makes of ARM even have large FIFO buffers.   This means that you can write multiple bytes to the FIFO and the chip shifts them out at full speed.

 

As Andy suggested,   there are probably good explanations on Wikipedia.

Obviously the theoretical speed limit is SCK/8 bytes a second.  i.e. with no gaps

For a UART at 8-N-1 the speed limit is BAUD/10 bytes a second.  i.e. with no gaps

 

If you can let the hardware do the work,   you can use the time for software computation.

 

David.

 

Edit.  If your SPI is running at 12MHz,   2048 bytes will take at least 1.4ms to shift through the SPI.    FATfs tends to read 512 bytes at a time.   It also has to calculate which sector it needs to read or write next.   Your microSD will be doing its own internal housekeeping at the same time as it is shifting data through the SPI.

Last Edited: Mon. Aug 17, 2015 - 08:35 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Writing 20 bytes at a time will slow things down a bit - to do this, you need to read the current sector at the end of the file, insert the 20 bytes, write this back then update the FAT/dirent. if you accumulate a multiple of 512 bytes (one sector's worth) will speed things up a bit.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks for your comment Kartman.

 

You are right, this is a fixed rate at which tha data is coming in from the external device and it cannot be increased on the other hand the data cannot be evenly divided into 512Bytes other I could have created two buffers and transfer 512 bytes at a time one by one from the buffers once they were full.

 

Best regards,

Owais.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why bother?   The whole point of filesystems is to look after arbitrary reads and writes.    It will read (or write) the next buffer as required.

 

In practice,   you are happy to read with buffering.

You may want to flush() regularly when writing.   But there is no need to flush after every 20 bytes.   If you do,  it will mean that a 512 byte buffer (or two) will get written every time.    Every time that file size is changed,   the filesystem will update the directory and FAT table entries.

 

People may choose a different size of packet to ensure that packets always fit in 512 byte sectors.

 

I would just keep life simple.   e.g. f_read() and f_write() for your convenience.   (or f_printf() and other calls)

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I mean to say that I am doing the f_open f_write and f_close after every 20bytes but this way the data coming in is faster than the data being written on SD card and thus in the end what happens is that while the application is still writing to SD card the next 20 bytes come in and ultimately the end result is that data which end up written on the SD card is corrupted and not complete.

Best regards,

Owais.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you do a f_close() on every write,   you will force a flush.

 

Let's say that you have 5432 20-byte packets arriving in a "batch".  The resultant 108640 bytes will be written to disk with a single f_open(),  5432 f_write()s with a single f_close().    It will involve 213 sector-writes for the data and a handful of sector-writes for the housekeeping.

 

Quite honestly,   the microSD will have no difficulty keeping up.    OTOH,   if you are determined to flush on every 20 bytes,   you will be doing about 11000 sector-writes instead of the 220 odd sector-writes (that God intended).

 

Yes,  there is always a risk of lightning strike, nuclear holocaust,  power failure,  silicon failure, ...

You would design for power failure.   The other fatalities are extremely unlikely.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks again david for explaining that.

 

I understand that if I continuously flush after every 20bytes I will be making the process inefficient on the other hand if I just open a file once and keep doing f_write until the whole data is written this will eliminate the need of keeping up with the incoming data since f_write itself takes only about 4 to 5ms. After the data is received completely I can then f_close the file and all is well.

 

I have given a try to this approach, probably this is the valid approach that I should have tried, nevertheless I have transferred about 72KB of data and successfully written it on the SD card completely.

 

Thank you once again to everyone who contributed to this post. I am still open to any and all suggestions.

Best regards,

Owais.