Offline
Jr. Member
Karma: 0
Posts: 57
|
 |
« on: December 18, 2012, 08:33:54 am » |
Hello, I'm trying to get 2 arduinos to talk to each other over SPI. Now it works just fine, as long as SCK is at 1MHz or lower (DIV16, DIV32, DIV64 or DIV128). My program is simple, the master sends a string of numbers (0-255) and the slave prints these numbers out in hex, checking them to ensure all bytes have been recieved. If there is a mismatch, it stops.
At 1MHz, it will happily run for hours without a mismatch, but anything higher causes a mismatch within less than a second.
Has anyone got any advice on properly terminating the SCK line? currently I just have jumper wires (very short, not more than 6cm) between the two arduinos.
Surely impedance matching isn't necessary for such short distance/low freq?
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 57
|
 |
« Reply #1 on: December 18, 2012, 08:36:22 am » |
Hello, I'm trying to get 2 arduinos to talk to each other over SPI. Now it works just fine, as long as SCK is at 1MHz or lower (DIV16, DIV32, DIV64 or DIV128). My program is simple, the master sends a string of numbers (0-255) and the slave prints these numbers out in hex, checking them to ensure all bytes have been recieved. If there is a mismatch, it stops.
At 1MHz, it will happily run for hours without a mismatch, but anything higher causes a mismatch within less than a second.
Has anyone got any advice on properly terminating the SCK line? currently I just have jumper wires (very short, not more than 6cm) between the two arduinos.
Surely impedance matching isn't necessary for such short distance/low freq?
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 57
|
 |
« Reply #2 on: December 18, 2012, 08:41:10 am » |
Hello, I'm trying to get 2 arduinos to talk to each other over SPI. Now it works just fine, as long as SCK is at 1MHz or lower (DIV16, DIV32, DIV64 or DIV128). My program is simple, the master sends a string of numbers (0-255) and the slave prints these numbers out in hex, checking them to ensure all bytes have been recieved. If there is a mismatch, it stops.
At 1MHz, it will happily run for hours without a mismatch, but anything higher causes a mismatch within less than a second.
Has anyone got any advice on properly terminating the SCK line? currently I just have jumper wires (very short, not more than 6cm) between the two arduinos.
Surely impedance matching isn't necessary for such short distance/low freq?
|
|
|
|
|
Logged
|
|
|
|
|
Poole, Dorset, UK
Offline
God Member
Karma: 8
Posts: 669
|
 |
« Reply #3 on: December 18, 2012, 08:41:29 am » |
The Uno runs at 16Mz this may be a clue to your problem.
Mark
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 57
|
 |
« Reply #4 on: December 18, 2012, 08:45:01 am » |
yup it does, and although the SPI interface uses this same clock signal, you can set a divider to scale it down. works fine with a divider of 16, meaning the freq is 1MHz. But I start to lose bytes at frequencies above this. Has anyone successfully received SPI data on an arduino at > 1MHz?
|
|
|
|
|
Logged
|
|
|
|
|
Gosport, UK
Offline
Faraday Member
Karma: 19
Posts: 3118
|
 |
« Reply #5 on: December 18, 2012, 08:51:39 am » |
|
|
|
|
|
Logged
|
|
|
|
|
Valencia, Spain
Online
Edison Member
Karma: 65
Posts: 2233
|
 |
« Reply #6 on: December 18, 2012, 08:51:49 am » |
Surely impedance matching isn't necessary for such short distance/low freq?
Nope. I suspect something like an interrupt coming along and using up more time than it takes two bytes to arrive over SPI, losing one of them. Try doing "cli()". This will disable all interrupts. millis(), delay(), etc. will stop working but at least you'll know if that's the problem so you know where to start looking.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 57
|
 |
« Reply #7 on: December 18, 2012, 09:09:43 am » |
ok, thanks for the suggestion. Now, I have to ask, how do I implement that? is it as simple as adding
cli();
to my code in the setup?
|
|
|
|
|
Logged
|
|
|
|
|
Manchester (England England)
Offline
Brattain Member
Karma: 272
Posts: 25433
Solder is electric glue
|
 |
« Reply #8 on: December 18, 2012, 09:50:40 am » |
ok, thanks for the suggestion. Now, I have to ask, how do I implement that? is it as simple as adding
cli();
to my code in the setup?
Yes
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 114
Posts: 2205
|
 |
« Reply #9 on: December 18, 2012, 10:19:06 am » |
Surely impedance matching isn't necessary for such short distance/low freq? I would say that anything over 20/24Mhz, you need to think about signal integrity (the digital equivalent of impedance matching). At 16Mhz, it is questionable / fuzzle and likely implementation dependent - you should have no problem if it is done correctly via hardware spi.
|
|
|
|
|
Logged
|
|
|
|
|
Left Coast, CA (USA)
Offline
Brattain Member
Karma: 279
Posts: 15312
Measurement changes behavior
|
 |
« Reply #10 on: December 18, 2012, 11:11:20 am » |
ok, thanks for the suggestion. Now, I have to ask, how do I implement that? is it as simple as adding
cli();
to my code in the setup?
There are predefined macros that can be used: void setup() {}
void loop() { noInterrupts(); // critical, time-sensitive code here interrupts(); // other code here }
Lefty
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Offline
Tesla Member
Karma: 71
Posts: 6811
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #11 on: December 18, 2012, 11:23:08 am » |
How are you printing the numbers out? SPI waits for no man, if you a dicking around with serial printing and converting binary to ASCII HEX you may well lose data. How are you storing the numbers? Are you using interrupts for the SPI? I think you should post both halves of the code, there's little point commenting without all the facts. Surely impedance matching isn't necessary for such short distance/low freq? No. As yes, don't cross post. _____ Rob
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 57
|
 |
« Reply #12 on: December 18, 2012, 12:01:53 pm » |
Sorry for cross-posting guys. Didn't realise it was a no no- won't happen again! Heres my master and slave code anyway.
[code] MASTER:
#include <SPI.h>
void setup (void) { unsigned int i; digitalWrite(SS, HIGH); // ensure SS stays high for now
// Put SCK, MOSI, SS pins into output mode // also put SCK, MOSI into LOW state, and SS into HIGH state. // Then put SPI hardware into Master mode and turn SPI on SPI.begin (); Serial.begin(9600);
// Slow down the master a bit SPI.setClockDivider(SPI_CLOCK_DIV8); // enable Slave Select
} // end of setup
void loop (void) { unsigned int i; digitalWrite(SS, LOW); // SS is pin 10
// send test string //for (const char * p = "Hello, world!\n" ; c = *p; p++) // SPI.transfer (c);
for(i=0;i<250;i++){ SPI.transfer (i); } // SPI.transfer (c);
// disable Slave Select digitalWrite(SS, HIGH);
delay (2000); // 1 seconds delay byte a = SPDR; Serial.println(a);
} // end of loop
SLAVE:
#include <SPI.h> unsigned char buf [300]; volatile byte pos; volatile boolean process_it; char p;
void setup (void) { Serial.begin (9600); // debugging // have to send on master in, *slave out* pinMode(MISO, OUTPUT); // turn on SPI in slave mode SPCR |= _BV(SPE); // get ready for an interrupt pos = 0; // buffer empty process_it = false; // Slow down the master a bit SPI.setClockDivider(SPI_CLOCK_DIV8);
// now turn on interrupts SPI.attachInterrupt(); //SPI.setDataMode() } // end of setup // SPI interrupt routine ISR (SPI_STC_vect) { byte c = SPDR; // grab byte from SPI Data Register // add to buffer if room if (pos < sizeof buf) { buf [pos++] = c; // example: newline means time to process buffer // if this is set to 255 and master sends 255 then the whole things goes buck ape if (c == 249) process_it = true; } // end of room available } // end of interrupt routine SPI_STC_vect // main loop - wait for flag set in interrupt routine void loop (void) { int i; /* SPI.begin(); SPI.transfer (SPDR);*/ if (process_it) { buf [pos] = 0; Serial.print("\n\rstart...\n\r"); for(i=0; i< pos; i++){ Serial.print(buf[i], HEX); // print as an ASCII-encoded hexadecimal Serial.print(" "); if(buf[i] != i){ Serial.print("\n\rmismatch at byte no :"); Serial.print(i, DEC); Serial.print("\n\r"); Serial.print("value is: "); Serial.print(buf[i],DEC); Serial.print("\n\r"); // do nothing as were now hosed while(1) { } } } Serial.print("\n\rend...\n\r"); pos = 0; process_it = false; } // end of flag set } // end of loop
[/code]
|
|
|
|
« Last Edit: December 19, 2012, 06:30:46 am by eriknyquist »
|
Logged
|
|
|
|
|
Offline
Jr. Member
Karma: 0
Posts: 57
|
 |
« Reply #13 on: December 18, 2012, 12:12:57 pm » |
So yes, I am indeed dicking around with serial printing....however this works no problem at 1MHz and lower so I didn't think it was a problem. You think the serial printing might be slowing it down too much?
|
|
|
|
« Last Edit: December 19, 2012, 06:27:17 am by eriknyquist »
|
Logged
|
|
|
|
|
Switzerland
Offline
Faraday Member
Karma: 69
Posts: 3256
|
 |
« Reply #14 on: December 18, 2012, 01:20:22 pm » |
The serial printing needs almost a second in best case to print out the characters. During this time it interrupts the CPU after every character to put the next character in the buffer into the serial data register. The interrupts may block each other.
The other problem may be your interrupt routine. With 2MHz SPI speed you have 64 cycles between one SPI byte and the next one. A few cycles are needed to load the interrupt vector and save the processor state before entering your interrupt routine. Your routine is maybe 20-25 cycles so about half of the time slots available are used in the ISR leaving the other half to do the processing and printing to the serial port. At a speed of 9600 this may not be enough. Have you tried increasing your serial speed to let's say 57600? Does that change anything?
|
|
|
|
|
Logged
|
|
|
|
|
|