Yes you can improve the performance by doing some changes to the SPI library. We ran some tests and by using the SPI.setClockDivider(dividers) we got with the divider SPI_CLOCK_DIV4 4Mhz which is the standard, with the SPI_CLOCK_DIV2 we received 8.33MHz. In case you haven’t used this function it is normally used in the void setup(), and it looks like this:
The dividers available for this are SPI_CLOCK_DIV2, SPI_CLOCK_DIV4, SPI_CLOCK_DIV8, SPI_CLOCK_DIV16, SPI_CLOCK_DIV32, SPI_CLOCK_DIV64 and SPI_CLOCK_DIV128. The SPI_CLOCK_DIV2 is the fastest and SPI_CLOCK_DIV8 the slowest.
The library for the SPI is located in C:\Arduino-1.5.3\hardware\arduino\x86\libraries\SPI. We modified the SPI.cpp file, in the section that says “void SPIClass::setClockDivider(uint8_t clkDiv)”, in there are some cases, which dictates the behavior of the dividers used in the setClockDivider function. To improve the speed we changed the value of the SPI_CLOCK_DIV2 by modifying the line
maxSpeedHz = SPI_CLK_DEFAULT_HZ << 1;
And we change the value to 2, and the line looked like this:
maxSpeedHz = SPI_CLK_DEFAULT_HZ << 2;
With this modification we got 12.5MHz, and if you change the value to 3 it will give 25MHz. You can try with this, but I really don’t know if this change will affect anything else, and the signal might not be as accurate as with lower speeds, but If you decide to try it let us know your results.
Thanks for your detailed reply.
I see that the GPIO including the SPI (from ICSP header) is handled via the Cypress chip, from the pdf schematics. However, it was inconsistent with what I observed during the tests. I measured the SPI clock to be 4MHz and above. How is this achieved through the cypress chip if itself is on 100kHz I2C bus? And why is the point to do so?
I don't think SPI comes via the Cypress chip at all.
Lets trace the pins on the schematic. I'll start with the pin headers and work back to the processor.
Lets trace the MOSI signal which appears on Pin 11 of the Arduino header.
Page "23 of 27" shows the pin headers.
**NOTE The page numbers in the schematic are all out by one. I have reported this before. **
Pin 11 from the header goes through Resistor "R3M18" and becomes a signal called "IO11" Which leaves this page and goes to <22B1>. Due to the page references all being wrong (out by 1) this is actually page 21 Section B1.
On Page 21, Section B1, the signal IO11 goes through the Mulitplexor (MUX) and can be selected as either of the signals LVL_SPI1_MOSI or IO11_GPIO_PWM, so lets follow LVL_SPI1_MOSI.
It goes off to <22C1> (which is actually 21C1) so on page 21 at section C1 we see that it goes through the 3.3V to 5V level shifter and comes out, now called SPI1_MOSI:
So now, called SPI1_MOSI it goes off to 7D7, (which is actually 6D7 grrr... that stupid page bug!!!)
On page 7D7 6D7 we see it going straight into the Quark X1000 SoC, i.e. the main processor.
So, you should be able to get full native speed on the SPI bus, one way or another.
If doing it through the file system with System() commands from Arduino, you must remember to switch on the Level translator and the MUX too.
Then you need to look at the data sheet for the MUX chip and Level translator chip and make sure they can also support your desired frequency. You then also need to take into account that Resistor R3M18 which is there for protection from ESD and for impedance matching, and worry about whether that is going to affect any pull-up resistors on your shield, and the slew rate of the signal edges. Rather than try to do a bunch of complicated engineers maths, the best approach would be to try it, test it and see if it works.
The MUX chip has a stated bandwidth of 100 MHz.
The level translator has a maximum signal frequency of 60 Mbps in push-pull mode, or just 2 Mbps in open-drain mode. It is not immediately clear which mode is being used here.
I hope this helps!
>>The level translator has a maximum signal frequency of 60 Mbps in push-pull mode, or just 2 Mbps in open-drain mode.
I suspect most SPI signals are open drain (driven low) with a passive pull up to VCC, meaning you might find that the maximum data rate of just 2 Mbps applies here. I might be wrong about that. It would certainly tie in which my experience with my LED Matrix shield, because it started to misbehave above 1 Mbps, and I am sure it was the signal slew rate that was the issue. You can probably work around this though.
Firstly, thanks for providing such a detailed response, I appreciate all the effort.
I'm confused now though. JPMontero_Intel is this consistent with what the results of your experiments show? I'm relatively new to Arduino programming and learning fast!
>>I'm confused now though
When accessing SPI through Arduino sketches it may not be possible to achieve the theoretical maximum throughput, as (and this is not verified) I suspect there is some setup and teardown overhead with each SPI transaction through Arduino functions. I opted to use C programs compiled right on the Galileo itself and using Linux user mode libraries rather than arduino libraries because it works for me, and fits into my comfort zone. You could probably go even further and modify or even write your own linux kernel mode code to create an optimised SPI driver for a specific function, but that is probably not a great approach.
I've figured out the SPI configuration:
1. SPI is provided at SoC level, SCK, MISO, MOSI, come out of the Quark chip
2. Muxing to bring out SPI lines is performed by the cypress gpio expander
3. SPI chip select line is gpio controlled.
Quick question, in the SPI libary can you choose which lines to use for SS, MOSI, MISO and SCK? Could I use the two fast GPIOs IO2 and IO3 to speed up the performance? Data only flows in one direction so I don't need MISO. Of the remaining 3 which 2 should I (could I) assign to SS, MOSI and SCK for optimal performance?
I'm surprised that the library allows you to choose GPIO lines for the signals, as their is no routing available on the board.
If it indeed does work that you can select alternate lines, I think they must be 'bit banged' by the library, which would be slow.
Like I always say, test it and see if it works!
I don't think the library allows you to choose GPIO lines, I'm looking at it now and can't see anything, but I really don't know...