Offline
Sr. Member
Karma: 15
Posts: 463
|
 |
« on: December 21, 2012, 06:26:39 pm » |
Hi all, I've been playing with a new 128 x 64 pixel vacuum fluorescent display (a Noritake GU128X64E-U100) module which has several different interface modes (i.e. parallel and 3 different types of serial).  I have it working using the library code supplied by Noritake, but this code bit-bangs the ports with digitalWrite() and digitalRead() statements. When trying to send data fast (like a live, runtime bar graph), the transfer rate is slow enough that the display doesn't move smoothly (hard to explain). I can see the updated image "sweep" across the display... imagine an old CRT TV set with a slow scan rate. Anyway, I wonder if I use the Arduino hardware SPI pins and the SPI.h library (and modify the Noritake library to use it), could I expect to see better results (i.e. faster data transfers)? Thanks! -- Roger
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Boston area, metrowest
Online
Brattain Member
Karma: 242
Posts: 16506
Available for Design & Build services
|
 |
« Reply #1 on: December 21, 2012, 06:29:12 pm » |
Yes. Hardware SPI is much quicker than software SPI, if the receiving device can accept the data at the faster rate.
|
|
|
|
|
Logged
|
|
|
|
|
Leeds, UK
Offline
God Member
Karma: 35
Posts: 983
Once the magic blue smoke is released, it won't go back in!
|
 |
« Reply #2 on: December 21, 2012, 06:59:12 pm » |
A digitalWrite() call takes about 15us to execute. There are two pins that need to be controlled meaning that the absolute max speed you can achieve using the wiring library is 2*15us = 30us per clock cycle, or 33kHz.
The Hardware SPI can run at a maximum of half FCPU. For an Arduino, that is 8MHz.
Based on that, using the SPI library should be around 240 times faster.
|
|
|
|
|
Logged
|
~Tom~
|
|
|
|
Left Coast, CA (USA)
Online
Brattain Member
Karma: 279
Posts: 15315
Measurement changes behavior
|
 |
« Reply #3 on: December 21, 2012, 07:04:10 pm » |
A digitalWrite() call takes about 15us to execute. There are two pins that need to be controlled meaning that the absolute max speed you can achieve using the wiring library is 2*15us = 30us per clock cycle, or 33kHz.
The Hardware SPI can run at a maximum of half FCPU. For an Arduino, that is 8MHz.
Based on that, using the SPI library should be around 240 times faster.
There could also be a alternate method using direct port access in the software SPI that would be somewhere between hardware SPI and software SPI using arduino digital pin commands. Lefty
|
|
|
|
|
Logged
|
|
|
|
|
SF Bay Area (USA)
Offline
Faraday Member
Karma: 78
Posts: 5453
Strongly opinionated, but not official!
|
 |
« Reply #4 on: December 21, 2012, 07:05:27 pm » |
(whether the faster communications rate will actually improve the way things LOOK is a separate question.)
You could speed up the comm a great deal, without running into the limitations of hardware SPI, but replacing the digitalWrite/digitalRead calls with "port IO" statements.
|
|
|
|
|
Logged
|
|
|
|
|
Leeds, UK
Offline
God Member
Karma: 35
Posts: 983
Once the magic blue smoke is released, it won't go back in!
|
 |
« Reply #5 on: December 21, 2012, 07:13:55 pm » |
Yup, you can get about 250kHz from a bitbanged software SPI using direct port writes from what I have seen. I can get 125k on an 8MHz ATTiny with the software SPI library I wrote.
I've attached the library. It is not quite finished, but it works, and has all the features of the Hardware SPI library except that you call begin() with the four arduino pin numbers for your SPI interface: begin(SCK, MOSI, MISO, SS);
|
|
|
|
|
Logged
|
~Tom~
|
|
|
|
UK
Offline
Tesla Member
Karma: 89
Posts: 6367
-
|
 |
« Reply #6 on: December 21, 2012, 07:19:27 pm » |
Thanks for sharing the software SPI implementation, Tom, it looks damned useful.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 71
Posts: 6611
Arduino rocks
|
 |
« Reply #7 on: December 21, 2012, 07:31:44 pm » |
A digitalWrite() call takes about 15us to execute.
No, its about 4us with constant parameters on a 16MHz Uno, meaning about 15kB/s rate for bit-banged SPI using digitalWrite (about 18 calls) With full speed Hardware SPI on that board you get bytes sent at 8MHz, but some overhead between bytes, so the practical rate is about 500kB/s so long as you toggle the CS pin with direct port manipulation (using digitalWrite for that will dominate the time in SPI handling) Bit-banging with direct port manipulation can get you close to the hardware SPI speeds. The UART can be programmed to do SPI master mode too I believe.
|
|
|
|
|
Logged
|
|
|
|
|
Dallas, TX USA
Offline
Edison Member
Karma: 25
Posts: 1617
|
 |
« Reply #8 on: December 21, 2012, 07:43:09 pm » |
A digitalWrite() call takes about 15us to execute.
It isn't that long on a 16mhz AVR. I've measured this many times and just measured it again earlier today on a 16mhz atmega328 using a logic analyzer and it is right at about 4.8us. Still pretty abysmal compared to what an AVR can do with direct port i/o which is 62.5ns --- bill
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Sr. Member
Karma: 6
Posts: 399
|
 |
« Reply #9 on: December 21, 2012, 08:57:20 pm » |
I've used a lot of SPI and I've never really used the SPI library yet. I ususally use direct port access to set my slave select pins and then I just write bytes to SPDR and watch SPIF to see when it's time to load on another. It can go really really fast like that. I would probably use the SPI library if I hadn't already found that method from reading the datasheet and a bit of code. But that's how I do it. A blocking example: SPDR = byteToSend; while(!(SPSR & (1<<SPIF)));
For a non-blocking code, you could check SPIF every time to let you know you can send another byte or I suppose you could even set up an interrupt to handle it.
|
|
|
|
|
Logged
|
|
|
|
|
UK
Offline
Tesla Member
Karma: 89
Posts: 6367
-
|
 |
« Reply #10 on: December 21, 2012, 09:02:51 pm » |
I haven't tried anything like that but I'm curious to know whether there's a reason for doing the send/wait in that order. Intuitively I've have guessed it would be more efficient to do it the other way round (prepare the byte to send, wait for the hardware to become idle, send the byte, move on and do something else).
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 114
Posts: 2205
|
 |
« Reply #11 on: December 21, 2012, 09:04:45 pm » |
A blocking example: I would flip the sequence: while(!(SPSR & (1<<SPIF))) continue; //wait if the prior transmission hasn't ended
SPDR = byteToSend;
This can be considerably faster than your sequency.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Sr. Member
Karma: 6
Posts: 399
|
 |
« Reply #12 on: December 21, 2012, 09:38:20 pm » |
I see. I guess you're right. The code I grabbed was actually waiting for a reply. So it had a line after that. byteRecieved = SPDR;
And in that code I was waiting for the flag so I would know there would be good data in SPDR to read.
|
|
|
|
|
Logged
|
|
|
|
|
United Kingdom
Offline
Faraday Member
Karma: 131
Posts: 4670
|
 |
« Reply #13 on: December 22, 2012, 04:48:40 am » |
If you want to get the maximum speed out of the hardware SPI, It's even faster if you don't wait for the SPIF bit but instead include just the right number of NOPs between writing one byte and the next to SPDR.
|
|
|
|
|
Logged
|
Formal verification of safety-critical software, software development, and electronic design and prototyping. http://www.eschertech.com
|
|
|
|
Dubai, UAE
Offline
Edison Member
Karma: 20
Posts: 1627
|
 |
« Reply #14 on: December 22, 2012, 06:34:40 am » |
And the right number is ? And is it constant for a given SPI Clock setting ?
Duane B
|
|
|
|
|
Logged
|
|
|
|
|
|