Page 1 of 1
Lots of I2C where are the SPI examples?
Posted: 14 March 2006, 11:39 AM
by TimC
Hi,
I am looking for examples of using the SPI bus.
Both Hardware SPI and Software SPI examples.
I am using 2 SPI chips, one is the old DS1302 and the other is a D->A chip with a SPI interface that needs to run flat out.
Thank You
Tim C.
Posted: 14 March 2006, 12:49 PM
by dkinzer
You can find some example code for connecting to an external EEPROM on Prof. Anderson's site:
http://www.phanderson.com/bx24/spieeprom.html
Scroll down to SPI_EEPROM_4.Bas, which example uses the BasicX SPICmd(). The same code should work on the ZX-24.
Also, I can post some experimental code that I used to connect an additional AT25256A to the ZX-24 for data logging.
Posted: 14 March 2006, 17:09 PM
by spamiam
Also check my project in the FILES section. It is the one about SD/MMC interface. It uses the bit-banged SPI interface instead of the hardware SPI.
The reason for this is that the SD card does not like to share the SPI bus with anything else. So, if it loses the /CS, then the transaction in progress is aborted. This means it will not play nicely with the ZBasic EEPROM.
-Tony
Posted: 14 March 2006, 18:41 PM
by TimC
Sharing and flat out are going to be interesting to work on
Thanks everybody
TimC
Posted: 15 March 2006, 10:51 AM
by spamiam
TimC wrote:Sharing and flat out are going to be interesting to work on
Thanks everybody
TimC
When you say you need "flat out", what speed do you need?
I bet the A-D chip runs at less that 200KHZ. Lets say 100KHZ, but do you need that many measurements? Can you do anything with that many measurements?
I do not know what the remaining bandwidth is for the ZX chip after servicing the EEPROM. The ATMega32 hardware SPI port can run at max speed, at OSC/2. THis means 8mhz on the ZX. So, you can get at best 1024 KByte/sec bandwidth on the SPI interface. Probably no more than half that is available to you when sharing with the ZX EEPROM.
So, what bandwidth do you need?
I have never tested the bandwidth available to the user because I never used a device which could share the bus. SPI FRAM and EEPROM can share as far as I can tell, but I have not yet tried SPI FRAM.
I would be interested to see what SPI bandwidth is possible for the ZX user (using the ZBasic SPI commands). I could see how a single multi-byte transfer in a single ZBasic command might run very quickly, and have minimal sharing of the SPI bus for that one command. I have no idea if the ZX hardware needs EEPROM access during a single SPI command. I do know that some EEPROM access occurs in the course of an entire SPI transaction, but maybe not during the multibyte transfer itself. Therefore the peak bandwidth could be at full SPI speed, and for large transfers, this efficiency could be very meaningful.
I would be very interested to see what the real-world results are for various size multibyte transfers. With a little statistics, the overhead can be eliminated, and the speed of the actual transfer can be deduced.
I can't do that because I do not have the appropriate SPI hardware to test with. SPI FRAM would be a great test case because it is rated for speeds well above the ATMega32 hardware capabilities. SPI EEPROM is probably also rates for real fast transfers, but I have not looked at those specs.
-Tony
Posted: 15 March 2006, 11:47 AM
by dkinzer
I have no idea if the ZX hardware needs EEPROM access during a single SPI command.
Each SPICmd() is atomic. This means that there will be no other SPI bus activity for the duration of the execution an individual SPICmd() call. Note, also, that the specified chip select pin is set low at the beginning of the SPICmd() and returned high at the end.
As soon as the call finishes, however, the VM will use the SPI bus to fetch the next instruction.
Posted: 15 March 2006, 15:26 PM
by spamiam
dkinzer wrote:I have no idea if the ZX hardware needs EEPROM access during a single SPI command.
Each SPICmd() is atomic. This means that there will be no other SPI bus activity for the duration of the execution an individual SPICmd() call.
As soon as the call finishes, however, the VM will use the SPI bus to fetch the next instruction.

I had hoped that this would be tre. Therefore a large (up to 255 bytes) data transfer will run at the full SPI speed with no interruption. Therefore it can get the full Fosc/2 SPI speed! For the 14+ MHz ZX clock, you will get 7+MHz bus speed. A byte will take 16 clocks, plus the time to service the SPI interrrupt (something like 11 clocks I am told), and a several more clocks to load the next byte into the SPI hardware.
This adds up to something like 35 clocks total? This seems as if it would give a bandwidth of something like 420K bytes per second overall for the transfer itself. I think that this adds up to about 10x the speed of the I2C bus.
Are these guestimates in the right ballpark? Has anyone tested the thruput on the ZX?
-Tony
Posted: 15 March 2006, 17:34 PM
by dkinzer
Has anyone tested the thruput on the ZX?
I ran the test program below and inspected the CS, SCK and MISO lines using a logic analyzer. The timing was 1 byte approximately every 5.4uS (185KB/s).
In reviewing the VM code, I can see ways to decrease the cycle time. It might be possible to get the cycle time down to 2-3 uS/byte.
Code: Select all
Sub Main()
Dim ba(1 to 20) As Byte
Const chan as Byte = 1
Call MemSet(ba.DataAddress, SizeOf(ba), &Ha0)
Call OpenSPI(chan, &H80, 12)
Call SPICmd(chan, SizeOf(ba), ba, 0, 0)
End Sub
Posted: 15 March 2006, 17:57 PM
by spamiam
dkinzer wrote:The timing was 1 byte approximately every 5.4uS (185KB/s).
In reviewing the VM code, I can see ways to decrease the cycle time. It might be possible to get the cycle time down to 2-3 uS/byte.
5.4uS is about 80 clocks on the ZX. This is somewhat slower than I expected. 2-3us seems like a very streamlined routine. As I said before, the SPI interrupt probably consumes 11 clocks just entering the ISR (pushing all the stuff on the stack, etc), then there is the 16 clocks to send/receive the byte, and then the code to load the next byte into the hardware which I would imagine is: place the received byte at the RAM data location, increment the pointer, place the data at the pointer into the SPI hardware, and initiate the next SPI transfer. This would be at least 4 clocks and probably 10 or more. So, 2-3uS is pretty good!
While SPI is not something that many users will end up using, those that do use it probably will be looking for the greatest speed possible, and an optimized SPICmd() would probably be well received.
-Tony
Posted: 15 March 2006, 18:13 PM
by dkinzer
5.4uS is about 80 clocks on the ZX.
True. And in reviewing the code, I'm not sure where they are all used. The send loop looks like this:
Code: Select all
cmdSPI_sendLoop:
dec outCnt
breq cmdSPI_receiveData
ld r24, ptr+
out IO(SPDR), r24
cmdSPI_sendWait:
sbis IO(SPSR), SPIF
rjmp cmdSPI_sendWait
rjmp cmdSPI_sendLoop
cmdSPI_receiveData:
That loop should add at most 10 cycles to the actual transmit time (16 cycles at the highest speed). The only thing that I can think of is if the AVR doesn't begin transmitting the data as soon as it is placed in the SPDR register.
The loop above could be improved by performing the counter decrementing and data fetching in parallel with the data transmission instead of in series with it. Still, if the AVR adds another 50 cycles that won't help much.
Posted: 15 March 2006, 20:57 PM
by mikep
dkinzer wrote:I ran the test program below and inspected the CS, SCK and MISO lines using a logic analyzer. The timing was 1 byte approximately every 5.4uS (185KB/s).
In reviewing the VM code, I can see ways to decrease the cycle time. It might be possible to get the cycle time down to 2-3 uS/byte.
Code: Select all
Sub Main()
Dim ba(1 to 20) As Byte
Const chan as Byte = 1
Call MemSet(ba.DataAddress, SizeOf(ba), &Ha0)
Call OpenSPI(chan, &H80, 12)
Call SPICmd(chan, SizeOf(ba), ba, 0, 0)
End Sub
How did you measure 5.4us? Was that the average per byte for the whole transfer? If so then you can certainly get faster speeds by increasing the buffer size to 64 bytes for example. Please re-measure with a larger buffer size and tell us the result.
I have test program that reads from a FRAM (or EEPROM) and gets a bytes/sec transfer rate of approx 500K bytes/sec. The calculation ignores start up time by differencing the times for two buffer sizes and averages the rate by doing the transfer for a 1000 iterations. However I'm not sure I have measured this correctly so I'm not posting the code just yet.
Posted: 15 March 2006, 21:16 PM
by dkinzer
How did you measure 5.4us?
That was the time, measured on a logic analyzer, from the first SCK of one byte to the first SCK of the next byte.
Posted: 16 March 2006, 5:46 AM
by spamiam
dkinzer wrote:Still, if the AVR adds another 50 cycles that won't help much.
I am sure that there is some degree of latency, and I have no idea what it would be. BUT, 50 clocks seems a rather high egree of latency to me, but I have never actually measured SPI speed in any way.....
-Tony