SPI Slave in ATmega128

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

As an experiment on an existing product I am trying to eliminate an obsolete FPGA, by implementing an SPI Slave on an ATmega128. I need to sample 5 push-button switches and place the samples in the SPDR register for the SPI Master to read asynchronously. I had hoped in vain that a value once written to SPDR, the SPI data register, would be repeated on successive transactions from the SPI Master.

From the datasheet I understand that I can update SPDR whenever PB0(SS*) is inactive(high). Problem is I can't just test for that condition and assume it will continue to be true long enough to update SPDR. The next suggestion is to update SDPR in the interrupt routine before reading the incoming data from the SPI Master.

What happens in either case is that with no mechanical action anywhere near the front panel buttons, the SPDR contains the string of 1's meaning that no buttons are being depressed. Occasionally of byte of zeros is returned which I interpret as a "failure to update" SPDR in a timely fashion. This apparent multiple button depression drives the SPI Master absolutely "BATS".

My question: "Is there a reliable way to return a constant value on an SPI Slave port in an ATmega128?"

We never have time to do it right,
but we always have time to do it over

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

Why don't you define a protocol so the master can send a "is anything available?" command and only when the slave responds "yes I have something" the master sends a "OK, give me what you got" command to which the slave responds "data = NN"

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

In an ideal world where I can easily control both sides of the conversation your suggestion would be practical. The SPI Master is implemented in a Motorola(Freescale) MC68HC11 with a PSD-312. Those EPROM/RAM/IO combo chips are near EOL, One Time Programmable, and too precious to do development with the Edit-Compile-Burn methodology.

In all the SPI work I've done on the Atmel parts I've never had to return data to an SPI Master. If this is difficult or impossible to do reliably then the experiment to replace the FPGA is a failure and we'll make another batch of boards with the FPGA and be done with it.

We never have time to do it right,
but we always have time to do it over

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

You can return data but you don't have a lot of time between receiving the master's command enquiring for the data and him then passing the stuffing byte to clock out your return value. Best is simply to have the master delay a little after the first byte to give the slave a chance to get the return value preloaded into SPDR or you can attempt what you were previously and always just load SPDR when the current state changes but you risk the kind of problem you've seen. But exactly what is the comms. sequence here? You say it's mastered by a CPU who's algorithm cannot be changed so exactly what sequence is it sending with what (exact) timing? Is it just repeatedly sending stuffing bytes all the time simply to clock data out of the slave?

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

Yes. The SPI Master always sends a pair of zeros. According to the Beagle analyzer the total transaction is about 62 microseconds at a datarate of 921,600 bits/second. Only the second byte returned is significant and I calculate there is about 42 microseconds between the end of the first incoming byte and the beginning of the second incoming byte.

I have also tried writing the value after reading the incoming byte but that doesn't seem to work any better. My ATmega128 is running at 7.3728 MHz. The transaction happens every 32.768 milliseconds, the rate of the RTI on the MC68HC11. Here is my current interrupt routine.

unsigned char floor ;

interrupt [SPI_STC] void spi_stc_isr(void)
{
	if(spi_RxN < (SPI_QUEUE_SIZE - 1))	/* Check for NOT FULL	*/
	{
		++spi_RxN ;
		spi_RxQueue[spi_RxPut++] = SPDR ;
		SPDR = spiButtonData ;
		if(spi_RxPut > (SPI_QUEUE_SIZE - 1)) spi_RxPut = 0 ;
	}
	else
	{
		floor = SPDR ; //Throw overflow data on the floor
		SPDR = spiButtonData ;
	}
}

We never have time to do it right,
but we always have time to do it over

Last Edited: Tue. Mar 23, 2010 - 06:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

My ATmega128 is running at 7.3728 MHz.

So a 0.135us cycle time. You therefore have 309 cycles in that 42us - should be plenty of time. I presume by a "pair of 0's" you mean after SS->_SS synchronisation?

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

Yes SS* goes low the, first zero byte is written with 1 usec bits. followed by 19.5 usec of no clock followed by a second zero byte then SS* goes high about 17.2 usec later.

The Beagle Anaylzer shows that the timing is tighter than I thought, and apparently does not account for a delay from SS* going low to the first byte coming in.

Check previous post as I've added the latest incarnation of the SPI interrupt.

We never have time to do it right,
but we always have time to do it over

Last Edited: Tue. Mar 23, 2010 - 06:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you know only 0x00's are being sent what's the point of wasting time with:

spi_RxQueue[spi_RxPut++] = SPDR ;

?? Surely you aren't interested in what the 68HC11 is sending?

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

Based on inputs from the front panel buttons or an IR Remote there is display information that comes across the SPI interface. When everything is idle just the zeros come across looking for front panel buttons.

My thinking was that it is easier to put the zeros in the FIFO and ignore them later, than it is to check for them in the interrupt routine. I'm also trying not to complicate things with other details.

The original question was: if spiButtonData is always a 0x3F because no buttons are being pressed, how come the SPI slave occasionally transmits a 0x00 which is interpreted as "all the buttons are being depressed". The hypothesis is that after shifting out a value the next value shifted out is either a default zero or the last byte that came in which happens to be a zero unless a new value is written to SPDR in time.

So when is the right time to write it reliably?

The datasheet is ambiguous at best on this point.

We never have time to do it right,
but we always have time to do it over

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

You can load SPDR with your current button data at the very beginning of the ISR, before you read SPDR for the incoming data.

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

Loading the SPDR with new outgoing data before reading the incoming data was the previous attempt and it did not behave any differently. With a sequence like:

    SPDR = 0x3F ;
    spi_RxQueue[spi_RxPut++] = SPDR ; 

the Beagle Analyzer still shows occasional 0x00 bytes getting on to the MISO line from the slave device. My analysis is that the only way this can happen is if for some reason the loading of SPDR does not happen before the SPI master starts shifting the data out of the ATmega128 slave device.

I cannot explain this behavior, that is why I asked the community. It seems that we have both come to the same conclusion that we find it difficult to square the empirical evidence with the documentation. It is not the first time I've seen this and probably won't be the last.

Thanks everybody, but I think this experiment was a failure and we'll grudgingly hang on to the obsolete FPGA.

We never have time to do it right,
but we always have time to do it over

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

Papabravo wrote:
The hypothesis is that after shifting out a value the next value shifted out is either a default zero or the last byte that came in which happens to be a zero unless a new value is written to SPDR in time.

I did some experiments with an ATmega88 and it appears to be the latter. This is not surprising as pictures in Atmel's manuals show only a single shift register (eg. figure 19-2 in the ATmega128A manual), but IMO this again highlights the poor design of Atmel's SPI peripheral.

Quote:
So when is the right time to write it reliably?

My only suggestion is to construct your transfer complete interrupt handler so that the received data is read and the new byte to be transferred is written as soon as possible (ie. do your business with SPDR and then prepare the values for the next interrupt).

Also check that you don't have any other interrupt handlers that could delay the SPI interrupt. I had a short loop in my pin change interrupt handler, and inserting a check for SPIF at the top of the loop let me use a lot tighter timing. With the ATmega88 running at 8 MHz I have a delay of around 6 µs between transferred bytes.

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

Thanks for that anders_m. I may try one more time with a modification to the SPI master now that the Beagle Analyzer has given me a more precise picture of the actual timing of the bit clocks with respect to SS*.

The timing appears to be tighter than I thought.

Thanks again to all who responded.

-- PB

We never have time to do it right,
but we always have time to do it over