SPI with wiringPI on Raspberry PI as master.

After a bit of a fight, I managed to get wiringpi2 and the the wiringpi2 python wrapper installed on the NOOBS Raspbian PI distro. The Adafruit 4 channel logic level converter kept the PI safe and sending data to the Arduino was as simple as this on the PI side:

import wiringpi2
wiringpi2.wiringPiSPISetup(1,5000)
wiringpi2.wiringPiSPIDataRW(1,'HELLO WORLD\n')

and the Arduino code here from Nick Gammon.

So, I know the wiring works. But that's not the way round I actually want - I want to read a pin from the Arduino to the PI.
Well, ultimately, I've got to read the number of clicks from a rotary encoder since it was last read, and the direction turned. But right now I'd be happy to read ANYTHING!

I read the SPI reference which states:

This library allows you to communicate with SPI devices, with the Arduino as the master device.

The PI must be the master device. I thought I was doomed until I read Nick Gammon's excellent page about SPI which demonstrates 2 Arduinii talking to each other.

Also, the SPI transfer() command would suggest you CAN write from the Arduino.

I'm now at the stage where all the links of the the first 4 result pages of Google show as "followed" - so it's not for lack of Googling!

In theory, shouldn't this work if I use the READ method on the PI end? (Note: this is just one of many, many attempts, not the only one!)

#include <SPI.h>
void setup (void)
{
  SPI.begin();
  pinMode(MISO, OUTPUT);
  
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);
}

void loop  (void) {
  SPI.transfer('TEST'); 
}

And on the PI end of things:

import wiringpi2
wiringpi2.wiringPiSPISetup(1,5000)
stuff = wiringpi2.wiringPiSPIDataRW(1,'\n')
print stuff

WiringPI says the incoming data will overwrite my data, and the SPIDataRW takes exactly 2 inputs, so shouldn't I be getting "test" back?

What am I missing here? Any pointers greatly appreciated.

What am I missing here?

A clue as to the difference between single and double quotes, for one thing.

void loop  (void) {
  SPI.transfer('TEST'); 
}

Sending ONE multibyte character is probably not what you want to do. The Arduino knows about, but does not provide support for, multibyte characters.

Ahhh! OK - good spot. It had been a long couple of days and I was goggle eyed by then!

OK, so something like this which I found elsewhere:

void loop  (void) {
byte data[] = {0x00, 0x00, 0x00, 0x00};  // this is 24 bits (8bits/byte * 4 bytes) // Transfer 24 bits of data
for (int i=0; i<4; i++) {
SPI.transfer(data[i]);   // Send 8 bits
}
}

I guess I'm still getting the bit wrong where the PI actually calls for this data to be sent back?

You know what I found earlier? A logic analyzer for a tenner on ebay; I think that should help me understand this better as soon as a courier delivers it. But more tips meantime would be welcome :slight_smile:

Thanks again.

OK, logic analyser helped a lot, so I'm now at the stage where I've got something working. I've documented and written up the whole thing along with code and Fritzing diagrams, installation guide etc.
https://gist.github.com/lardconcepts/6528855

It works. Just. But the code is horribly inefficient especially in a couple of places and makes the PI run at 50% CPU when polling the Arduino 100 times a second.

I realise this post in an Arduino forum is more about the RaspberryPI side of things, but I'm sure I'm not the only one to want to link the two!

I'd appreciated advice on two bits of my python code in particular. When you send a bit on SPI, you get a bit back. That first bit is junk really, as the slave end doesn't know what you want.
If I just use "wiringpi2.wiringPiSPIDataRW(1,myData)" to get a response from the Arduino, I find the data "ping pongs" back and forth up to 7 (but never more) times.
To make matters more confusing, myData becomes the data being received back at the same time as you send it.
The only way I found round it was to call wiringPiSPIDataRW TWICE - this stops the "ping pong" but doubles the load.

    # Because SPI recevies a byte when it sends, for some reason I found you 
    # need to send TWO calls oherwise you get into a "ping pong" scenario 
    wiringpi2.wiringPiSPIDataRW(1,myData)
    wiringpi2.wiringPiSPIDataRW(1,myData)
    print myData

The other problem I had was testing the byte for junk before processing it.
If it's 0x03, it's nothing that I want - it means no buttons are pressed. Anything else and I want to do a switch/case on it.

If I run the incoming byte through hexdata = ''.join('%02x' % ord(byte) for byte in myData) then I get something that both python and myself can "see".

But if I try

if myData != 0x03 (or 03 or '03' or '0x03' or '3' or 3 and so on)

then it never tests true (or false). So it always has to be run through the hexdata routine, meaning more unnecessary CPU work.

    # Turn the data into something we can use
    # http://stackoverflow.com/questions/1916928/
    hexdata = ''.join('%02x' % ord(byte) for byte in myData)
    doActions(hexdata)

[...]

def doActions(hexdata):    
# See http://www.asciitable.com/
# DEFAULT 03 LEFT: 13 MID: 0b RIGHT: 07 L+M 1b R+M: 0f
    for case in switch(hexdata):
        if case('03'): # default, could also just omit condition or 'if True'
            #print hexdata
            middle.config(state='disabled')
            right.config(state='disabled')
            left.config(state='disabled')
            break
         # No need to break here, it'll stop anyway        
        if case('13'):
            #print ("left")
            left.config(state='normal')
            break
        if case('0b'):
            #print "middle"
            middle.config(state='normal')
            break
[...]

And finally, a tkinter question!

I've setup 3 buttons to represent switches pressed. Is there a more efficient way of getting the buttons to default to their disabled state than resetting their config to "disabled" on each and every pass (ie: 100 times per second) which I'm doing here:

if case('03'): # default, could also just omit condition or 'if True'
            #print hexdata
            middle.config(state='disabled')
            right.config(state='disabled')
            left.config(state='disabled')
            break
[...]

All advice appreciated by this learning newbie who's googled but not found all the answers....