Go Down

Topic: Learning SPI. (Read 2 times) previous topic - next topic

Mavromatis

Jun 23, 2012, 01:52 am Last Edit: Jun 23, 2012, 02:00 am by Mavromatis Reason: 1
I'm trying to learn more about SPI.  

Looking at the transfer method in Arduino SPI.h I see the following:
Code: [Select]

byte SPIClass::transfer(byte _data) {
 SPDR = _data;
 while (!(SPSR & _BV(SPIF)))
   ;
 return SPDR;
}


Looking at the ARM STM32 code I'm trying to port I see the following:
Code: [Select]

/*
   Description:- The spiRdWr function writes the data passed as the argument
                   and returns the data pushed out form the slave device
*/
UINT8 spiRdWr(UINT8 byte)
{
UINT8 readByte;
   while((SPI1->SR & SPI_SR_BSY));
       while(!(SPI1->SR & SPI_SR_TXE));
           SPI1->DR = byte;
           while(!(SPI1->SR & SPI_SR_RXNE));
               readByte = (UINT8)SPI1->DR;
   return readByte;
}


Based on how I'm reading this, both do the same -- send the byte and returns the read byte.

Right?

spirilis

Yep sounds right.  Microcontrollers with built-in SPI driver hardware employ a memory-addressable Shift Register where the I/O takes place, called "SPDR" in the AVR.

Writing to SPDR internally triggers activation of the SPI clock generator, which clocks out the bits in SPDR one at a time while shifting in the input bits from the MISO pin at the other end of the shift register, so that once the SPI clock has completed its 8 pulses the contents of SPDR are equal to the inputted byte from the slave.
There's usually a status register you can poll to check when the SPI clock is done.  Both the AVR and ARM examples show this.

Nick Gammon

http://gammon.com.au/spi
http://www.gammon.com.au/electronics

Mavromatis

What does this do:
SPI.attachInterrupt();

How is it used?

Nick Gammon

It does this (from the source):

Code: [Select]
void SPIClass::attachInterrupt() {
 SPCR |= _BV(SPIE);
}


So from the example of making a slave on my page, you would change the lines:

Code: [Select]

 // now turn on interrupts
 SPCR |= _BV(SPIE);


to:

Code: [Select]

 // now turn on interrupts
 SPI.attachInterrupt();


... which would have the same effect.

I might modify my page to do that, to keep register-fiddling down.
http://www.gammon.com.au/electronics

Mavromatis

Got it - Thanks!!

So I have made some progress with SPI.   Which leaves me with the following question.

The Arduino Mega 1280 is SPI Master @ 5.0V
The device is SPI Slave @ 3.3V with 5V tolerant pins.

Most of the time I can send a request and it arrives at the other end just fine, everything in sync -- 0x01, 0x00, 0x00, 0x00.
Sometimes, it arrives at the other side as 0x00, 0x01, 0x00, 0x00 and so on -- like it's cycling a bit over.

Then on the MISO same thing happens -- first 5 "polls" are perfect, then it seems to get out of sync.

How do you troubleshoot something like this? I have a logic analyzer now.

Thanks!

Nick Gammon

Hook up the analyzer to the 4 pins (MISO/MOSI/SS/SCK) and take a snapshot. Maybe you are in the wrong SPI mode. Maybe SS goes low too soon/late or something.
http://www.gammon.com.au/electronics

Mavromatis


Hook up the analyzer to the 4 pins (MISO/MOSI/SS/SCK) and take a snapshot. Maybe you are in the wrong SPI mode. Maybe SS goes low too soon/late or something.


Sending:
Code: [Select]

SPI.transfer(0x01);
SPI.transfer(0x37);
SPI.transfer(0x00);
SPI.transfer(0x00);


Receiving end:
Code: [Select]

   1       55        0        0   < OK
   1       55        0        0   < OK
   1       55        0        0   < OK
   1        0        0        1   < Not sure what happen here
   0        0        1       55   < Shifted should be like above
   0        0        1       55   < "" ""
   0        0        1        0   < ????
   0        1       55        0   < Shifted again?
   0        1       55        0   < "" ""



Mavromatis

Think I see the issue:

The SPI_REQ line went LOW -- weird -- noise?

Mavromatis

I put a weak pull up resister on the line -- but I'm still getting the MOSI bits off.

Code: [Select]


   55        0        0        1

   0        0        1       55
    0        0        1        0
    0        1       55        0

    1       55        0        0
    1       55       49        0
 
    0        0        1       55
    0        0        1       55
    0        0        1        0

Nick Gammon

Bump up the sample rate on the logic analyzer. I usually have mine at 16 MHz. After all, that's the processor clock speed.

The slave may not be able to respond fast enough. Try dropping back the SPI rate, or adding a gap between bytes.
http://www.gammon.com.au/electronics

Mavromatis

I've got the clock divider set at /16 or 1mhz.  I'll try putting a delay?   What's the best kind of delay to use?  Assembly nop?

Mavromatis

So it looks like I solved the problem with one of these: http://www.sparkfun.com/products/8745

The issue was running 5V MCU and 3.3V SPI device.  Apparently I was on the border, thus, getting inconsistent results.

Have been running it for a few minutes and no "sync" issues so far!

Go Up