Gap seen in SPI transmission

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

Hi Guys,

I am using an Atmega328 in SPI mode and is configured as the master. I am transmitting 0XAA in a loop. Looking at the MOSI and the SCK pins, I see the attached waveform. I am seeing a gap after each transmission of 8 bits. The SPI clock polarity is set to falling edge. I assume it is because of the clock staying high for a short time before toggling on the next 8 bit cycle. Why could this be happening?

Thanks.

Attachment(s): 

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

Well, you have to load a new byte after the previous one is finished, does it not? That takes time. You have to start the next transfer. That is a register write. That takes time, doesn't it? 1/F_CPU granularity in timing!

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

There have been rumors that there is one SPI clock between transmissions, so you cannot transmit bytes at SPI clock/8 but clock/9.

There is no way you can get continuous SPI clock, even if it would be possible to get bytes out at spiclk/8, you have at least few instruction cycles there, as takes time for the AVR to poll SPSR register for the SPIF bit to be ready for next transmission and then writing SPDR to start new transmission.

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

First of all SPI transmit has no buffering and it starts transmission right after SPDR write. If you write it periodically every 20 clocks(bitshifts, which can be as high as F_CPU/2 in master mode), it will have 20-8=12 clocks space in between.
Another problem is that even if you write a precise asm loop (with SREG_I=0), you notice the shortest possible frame must have at least 9 clocks (bitshifts), so it will have 1 idle bitshift space in between..

There are some ATMegas which can send the data seamlessly - without dummy space, but I am afraid your ATMega328 cannot do that.

No RSTDISBL, no fun!

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

If you use the USART in SPI mode, you can get continuous transmission.

I have never actually tried it, since I generally want to use the USART for regular RS232.

I would guess that Brutte's trick of just timing the transmissions should work. i.e. write to SPDR on the 15'th clock.

Using IRQ's will involve quite a few cycles of latency before you write the new value to SPDR.
A tight loop that polls SPIF will give a faster turnaround.

The real question is. Why?

A Master seldom needs to worry about the odd cycles. Implementing a Slave with an AVR will never achieve the instant reply that most hardware SPI devices perform.

If you need the performance, change to a different controller.

David.

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

I use the SPI hardware to squirt out pixels to a TV screen. At the fastest speed (F_CPU/2), the earliest you can write out the second byte is 18 cycles after the first. If you try writing before then, it's ignored. This means that the gap is unavoidable. I call this the '9th bit problem'. I've found that the MOSI output is 'high' during this gap [but I think someone else has reported duplication of the 8th bit instead]. I've never managed to get rid of this gap, merely work around it.

Using the USART in SPI mode is a different story. It will output contiguous bytes without any gaps (I've only tested this on an XMega). It makes outputing bitstreams much easier, but is only useful if you've got USART that's not being used for anything else. It also benefits from having a single byte buffer on the output, which can simplify timing of subsequent bytes.

Nigel Batten
www.batsocks.co.uk

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

Well, that answers that then. You cannot avoid the gap when using the regular SPI hardware.

I recently wasted a lot of time with a PIC. If you write to the PIC's SSPBUF early, it aborts the current SPI transfer.

The simple answer seems to be use a multi-USART AVR or XMega chip in USART-SPI mode.

David.

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

Thanks, guys that makes sense.
This obviously means with the Atmega328 max frequency of 20MHz, the best I can get out of the SPI will be (20/2)/9 or about 1.11 MHz?

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

Your units are wrong. You can get 1.1 MBytes/s.

Compare that to any other serial transmission. You can obviously go faster with parallel transmission.

SD Cards will go a lot faster than this. You just need to use an ARM or other processor to keep up!

Or load a parallel-in shift register.

Do you really need massive speed?

David.

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

If you're up for a good challenge, you can switch the MOSI pin to be 'input' during the '9th bit'. In some circumstances this can be suitable as a 0.

Nigel Batten
www.batsocks.co.uk

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

I also used SPI for video and seen the same gap as condemned has mentioned. using an external shift register was the only way to have a continuous stream. It's too bad that they did not add the needed hardware to the AVR to allow the SR to be loaded on the last cycle like a standard 74 logic SR. Too bad indeed!

Brad

I Like to Build Stuff : http://www.AtomicZombie.com

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

Ok so I am trying to understand the waveform I am getting. I am sending 0xAA(shown in green) to the slave device from the MOSI pin (it is a part that is supposed to send back the same data on another line).
However, I seem to be getting longer (or double ones) and a zero at the output, something like 110110110.. (shown in brown). Black is the clock. Why is the output not 10101010..? Is there some sort of "aliasing" going on?

In other words, in one group of 8 bits, I should be getting 10101010 but I seem to be getting just 11111111?

Attachment(s): 

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

That middle trace looks very suspect. What is it?

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

Quote:

1/F_CPU granularity in timing!

Aaah--nanoseconds.

Quote:

using an external shift register was the only way to have a continuous stream.

I think I remembered the discussion, zombie. IIRC even with cycle-counting there is a gap of an AVR cycle or two.

I would have thought that

Quote:
20. USART in SPI Mode
20.1 Features
...
• Queued Operation (Double Buffered)
...

would have taken care of it.

[to OP: Are you trying to do a streaming app such as audio where this makes a difference? It sure doesn't with "normal" SPI peripherals such as SD/MMC, RTC, DAC, ...]

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

This is not a streaming app. This is just to check if a part is in a specific mode i.e. if it has a heartbeat.

@Jim:
The middle trace is the clock. I have attached a better resolution picture. Can you make sense out of it?

Attachment(s): 

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

I am concerned about the mid-way "logic level" between each burst of clocks. It is like something is going tristate. Maybe that is part of multi-master operation? None of the AVR timing diagrams show anything like that, which makes me wonder about bus-contention.

I'd like to see just one or two bytes. Can't see enough on your dlspay, especially clock and returned data.

jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

The error is clearly in line 27 of you program. And you haven't done the initialization correctly.