Hi Drogon,
Thank you SO much for your very quick reply - I am sorry I didn't thank you earlier, but for some reason I appear to have defaulted to "don't notify when reply posted" so I only just saw it - changed it back now.
And thank you also for the top tip about sprintf formatting the data to send - that'll save a fair bit of typing and mess in the future.
Yes, I see what you mean about the SPI cycling the buffer. And, of course, when I was looping through the array, the next element became what had just been sent. I mean received. Er... sent and received.
In fact, the Arduino doesn't actually NEED to display anything - that was just me sending something so I could see what was actually happening on the logic analyser to try and deduce what was going wrong.
In fact, what I have to do is read a buffer of switch and rotary encoder states from an Arduino (well, an Attiny 84 apparently, but the Arduino will do to test things).
It goes
1: Poll(ignore junk)
2: Poll(switch data (4 switches so low nybble - if high nybble is F then next packet is last)
3: Poll(rotary in two's complement)
Repeat and buffer while stage 2 high nybble isn't 0xF, otherwise do something.
Now, I'm not asking you to write my code for me here, but getting some sense back on the SPI would be a fine start!
Here's what's on the PI and Arduino. At the moment, I realise the 3 "reads" returning random numbers makes no sense as I've yet to figure out how to increment a counter on the Arduino each time an interrupt is triggered. Setting a global volatile int and incrementing it each time just doesn't seem to work within an interrupt routing. But what I WOULD expect here is random(15) to return something less zero-y than (eg) 0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,5,0,0,0,0,0.
Even though I am clearly setting the SPI buffer with something on the Arduino, it doesn't seem to actually send back what it should.
And yet, if I do a very simple test of sending, say, 0x42 to the PI in response to every single "ping", it'll do it just fine.
I've tried at slow SPI speeds, I've made the delay between "pings" up to half a second. It's no good me posting the logic analyser screenshot as the gap between readings is too wide to see, but the Arduino doesn't appear to respond to every "ping" when sending a random number. Off the responses I DO get, this is a sample:
Code: Select all
Time [s] Packet ID MOSI MISO
0 '0' '0'
0.010177 '0' '0'
0.035713 '0' '0'
0.0458855 '0' '0'
0.067803 '0' '0'
0.077997 '0' '0'
0.0986785 '0' '0'
0.108851 '0' '0'
0.129466 '0' '0'
0.139644 '0' '0'
0.1603105 '0' '4'
0.1704995 '0' '0'
0.191119 '0' '3'
So, here's the PI code, then the Arduino code. And apologies, but I've only been doing C for a couple of weeks, so don't expect quality code. Still doesn't explain the SPI oddness. Or does it?
#include <stdio.h>
#include <inttypes.h>
// provides uint8_t etc
#include <wiringPi.h>
#include <wiringPiSPI.h>
void pollSPI (
void);
uint8_t twoComp(uint8_t number);
//Nice trick to display dec as bin http://stackoverflow.com/a/3208376/2104428
#define BBPAT
"%d%d%d%d%d%d%d%d"
#define BB(
byte) \
(
byte & 0x80 ? 1 : 0), \
(
byte & 0x40 ? 1 : 0), \
(
byte & 0x20 ? 1 : 0), \
(
byte & 0x10 ? 1 : 0), \
(
byte & 0x08 ? 1 : 0), \
(
byte & 0x04 ? 1 : 0), \
(
byte & 0x02 ? 1 : 0), \
(
byte & 0x01 ? 1 : 0)
//Lookup for switch values: (E)ncoder (L)eft (M)iddle
static char lookup[][28] = {
"None",
// 00000000
"R",
// 00000001
"M",
// 00000010
"R M",
// 00000011
"L",
// 00000100
"L R",
// 00000101
"L M",
// 00000110
"L M R",
// 00000111
"E",
// 00001000
"E R",
// 00001001
"E M",
// 00001010
"E M R",
// 00001011
"E L",
// 00001100
"E L R",
// 00001101
"E L M R" // 00001111
};
int main (
void)
{
wiringPiSetup();
wiringPiSPISetup(1, 1000000);
pollSPI();
return(0);
}
void pollSPI (
void)
{
for ( ;; ){
uint8_t switches [] = { 0x00 };
uint8_t encoder [] = { 0x00 };
wiringPiSPIDataRW ( 1, 0x00, 1 );
// throw away this starter packet
delayMicroseconds ( 100 );
wiringPiSPIDataRW ( 1, switches, 1 );
// exchange for switches byte
delayMicroseconds ( 100 );
wiringPiSPIDataRW ( 1, encoder, 1 );
// exchange for encoder byte
delayMicroseconds ( 100 );
// http://stackoverflow.com/a/3124978/315699
// http://en.wikipedia.org/wiki/Nibble#Ext ... rom_a_byte
// No need to test for encoder high nibble as encoder is last byte anyway
uint8_t switchesHighNibble = (uint8_t)((switches[0] & 0xF0) >> 4);
uint8_t switchesLowNibble = (uint8_t)(switches[0] & 0xF0);
uint8_t two = twoComp(encoder[0]);
// calculate 2's comp from encoder
printf(
"Switches: %x("BBPAT
") Encoder: %o("BBPAT
") \
\t 2
's comp: %d(%x) \t = %s \n", switches[0], BB(switches[0]), \
(
int)encoder[0], BB(encoder[0]), two,two, lookup[switches[0]]);
if (switchesHighNibble == 0xF)
{
printf(
"*** GOT AN 0xF - NEXT BYTE IS LAST\n\n");
}
}
}
uint8_t twoComp(uint8_t number){
uint8_t two;
two = ~number;
//One's compliment
two = two + 1;
//Two's compliment
return(two);
}
And on the Arduino
// Based on tutorial from http://gammon.com.au/spi
#include <
SPI.h>
volatile
boolean process_it;
uint8_t clr;
uint8_t randNumber;
void setup (
void)
{
// Serial.begin (115200); // Turned off as it apparently affects interrupts
pinMode(MISO,
OUTPUT);
// master in, *slave out*
SPCR |= _BV(SPE);
// turn on SPI in slave mode
process_it =
false;
clr=SPDR;
// clear out any junk from past runs
SPI.
attachInterrupt();
}
// end of setup
// SPI interrupt routine
ISR (SPI_STC_vect)
{
process_it =
true;
}
void loop (
void)
// wait for flag set in interrupt routine
{
if (process_it)
{
randNumber =
random(15);
SPI.
transfer(randNumber);
process_it =
false;
}
}