Pages: [1]   Go Down
Author Topic: Learning SPI.  (Read 1983 times)
0 Members and 1 Guest are viewing this topic.
Seattle, WA
Offline Offline
Full Member
***
Karma: 0
Posts: 194
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm trying to learn more about SPI.  

Looking at the transfer method in Arduino SPI.h I see the following:
Code:
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:
/*
    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?
« Last Edit: June 22, 2012, 07:00:12 pm by Mavromatis » Logged

Maryland, USA
Offline Offline
Full Member
***
Karma: 0
Posts: 162
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 484
Posts: 18768
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

http://gammon.com.au/spi
Logged


Seattle, WA
Offline Offline
Full Member
***
Karma: 0
Posts: 194
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What does this do:
SPI.attachInterrupt();

How is it used?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 484
Posts: 18768
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It does this (from the source):

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

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

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

to:

Code:
 // 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.
Logged


Seattle, WA
Offline Offline
Full Member
***
Karma: 0
Posts: 194
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 484
Posts: 18768
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Seattle, WA
Offline Offline
Full Member
***
Karma: 0
Posts: 194
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
SPI.transfer(0x01);
SPI.transfer(0x37);
SPI.transfer(0x00);
SPI.transfer(0x00);

Receiving end:
Code:
   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   < "" ""



* LogicScreenSnapz001.jpg (391.03 KB, 1380x566 - viewed 48 times.)
Logged

Seattle, WA
Offline Offline
Full Member
***
Karma: 0
Posts: 194
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Think I see the issue:

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


* LogicScreenSnapz002.jpg (133.91 KB, 609x486 - viewed 42 times.)
Logged

Seattle, WA
Offline Offline
Full Member
***
Karma: 0
Posts: 194
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:

   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
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 484
Posts: 18768
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Seattle, WA
Offline Offline
Full Member
***
Karma: 0
Posts: 194
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Seattle, WA
Offline Offline
Full Member
***
Karma: 0
Posts: 194
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
Logged

Pages: [1]   Go Up
Jump to: