I am trying to use a mega to control 144 nanos via SPI control. I was hoping to connect them all on the same SS (since I don't need data back from each slave) and send an array of positions, using unique ID for each nano to find out the required position from the array.
The example Nick Gammon showed works, but when I try to extend it to a single int array, the slave picks up a lot of gibberish instead of the actual data, which I suspect is from syncing issue as it switches back and forth between gibberish and correct data.
Here's master:
// master (keep track of total size)
// classes needed
#include <SPI.h>
#include "SPI_anything.h"
// module identification
const int rowSize = 12;
const int heightSize = 12;
const int totalSize = rowSize*heightSize;
// create a structure to store the different data values:
typedef struct myStruct
{
int pos[totalSize];
};
myStruct dataSet;
// convert letter ID into position array pointer
int convertID(int rowID, int heightID, int rowSize){
int arrayPointer = rowSize * heightID + rowID;
return arrayPointer;
}
// Assign position of each module (later needs to be integrated with Unity)
// Currently randomly generated
void assignPosition(){
for(int module=0; module<totalSize; module++){
dataSet.pos[module] = random(1, 100);
}
}
void setup ()
{
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(SS, OUTPUT);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
assignPosition();
} // end of setup
void loop ()
{
digitalWrite(SS, LOW); // Turn on Modules
SPI_writeAnything (dataSet);
digitalWrite(SS, HIGH);
Serial.println(dataSet.pos[0]);
delay (1000); // for testing
assignPosition();
} // end of loop
Here's slave
// Slave ID: Row 0, Height 0
// Classes needed
#include <SPI.h>
#include "SPI_anything.h"
// Module identification
const int rowSize = 12;
const int heightSize = 12;
const int totalSize = rowSize*heightSize;
const int slaveRowID = 0;
const int slaveHeightID = 0;
const int slavePointer = rowSize * slaveHeightID + slaveRowID;
int switchLowPin = 2;
int switchHighPin = 3;
int switchMiddlePin = 4;
int encoderPin = 5;
int servoPin = 6;
int slavePosition;
// Create a structure to store the different data values:
typedef struct myStruct
{
int pos[totalSize];
};
myStruct dataSet;
// Setup
void setup ()
{
Serial.begin (9600); // debugging
Serial.print("Output of ");
Serial.println(slavePointer);
pinMode(MISO, OUTPUT);
pinMode(switchLowPin, INPUT);
pinMode(switchMiddlePin, INPUT);
pinMode(switchHighPin, INPUT);
pinMode(encoderPin, INPUT);
pinMode(servoPin, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
}
void loop ()
{
SPI_readAnything (dataSet);
Serial.println(dataSet.pos[slavePointer]);
}
Here's SPI_anything.h:
#include <Arduino.h>
template <typename T> unsigned int SPI_writeAnything (const T& value)
{
const byte * p = (const byte*) &value;
unsigned int i;
for (i = 0; i < sizeof value; i++)
SPI.transfer(*p++);
return i;
} // end of SPI_writeAnything
template <typename T> unsigned int SPI_readAnything(T& value)
{
byte * p = (byte*) &value;
unsigned int i;
for (i = 0; i < sizeof value; i++)
*p++ = SPI.transfer (0);
return i;
} // end of SPI_readAnything
template <typename T> unsigned int SPI_readAnything_ISR(T& value)
{
byte * p = (byte*) &value;
unsigned int i;
*p++ = SPDR; // get first byte
for (i = 1; i < sizeof value; i++)
*p++ = SPI.transfer (0);
return i;
} // end of SPI_readAnything_ISR
Am I understanding the source of the problem properly? Or is it another issue?
Many thanks in advance!
When I changed the CLK speed to 1Mhz instead, I am getting a more consistent result, but still with long periods of wrong data. Why would the clocks be out of sync if SS is connected though?
Ok, so here's a quick update; I changed a bit of the code to see if the data was potentially shifting, and turns out it is, but semi randomly. I can't figure out what the trigger is though.
New Master (changed, int array to byte array, added counter)
// master (keep track of total size)
// classes needed
#include <SPI.h>
#include "SPI_anything.h"
// module identification
const int rowSize = 12;
const int heightSize = 12;
const int totalSize = rowSize*heightSize;
int counter = 0;
// create a structure to store the different data values:
typedef struct myStruct
{
byte pos[totalSize];
};
myStruct dataSet;
// convert letter ID into position array pointer
int convertID(int rowID, int heightID, int rowSize){
int arrayPointer = rowSize * heightID + rowID;
return arrayPointer;
}
// Assign position of each module (later needs to be integrated with Unity)
// Currently randomly generated
void assignPosition(){
for(int module=0; module<totalSize; module++){
dataSet.pos[module] = module+1;
}
}
void setup ()
{
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(SS, OUTPUT);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
assignPosition();
} // end of setup
void loop ()
{
digitalWrite(SS, LOW); // Turn on Modules
SPI_writeAnything (dataSet);
digitalWrite(SS, HIGH);
Serial.println(counter++);
delay (2000); // for testing
assignPosition();
} // end of loop
New Slave (list out whole array)
// Slave ID: Row 0, Height 0
// Classes needed
#include <SPI.h>
#include "SPI_anything.h"
// Module identification
const int rowSize = 12;
const int heightSize = 12;
const int totalSize = rowSize*heightSize;
const int slaveRowID = 0;
const int slaveHeightID = 0;
const int slavePointer = rowSize * slaveHeightID + slaveRowID;
int switchLowPin = 2;
int switchHighPin = 3;
int switchMiddlePin = 4;
int encoderPin = 5;
int servoPin = 6;
int slavePosition;
int counter = 0;
// Create a structure to store the different data values:
typedef struct myStruct
{
byte pos[totalSize];
};
myStruct dataSet;
// Clear data
void clearPosition(){
for(int module=0; module<totalSize; module++){
dataSet.pos[module] = 0;
}
}
// Setup
void setup ()
{
Serial.begin (9600); // debugging
Serial.print("Output of Slave ");
Serial.println(slavePointer);
clearPosition();
pinMode(MISO, OUTPUT);
pinMode(switchLowPin, INPUT);
pinMode(switchMiddlePin, INPUT);
pinMode(switchHighPin, INPUT);
pinMode(encoderPin, INPUT);
pinMode(servoPin, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
}
void loop ()
{
SPI_readAnything (dataSet);
for(int module=0; module<totalSize; module++){
Serial.println(dataSet.pos[module]);
}
clearPosition();
}
I think it's quite 50/50 between ending at 143 and ending at 144, with occasional data jumble in between switching.
With 144 nano's, I am guessing that there is some length of cable between the master and final slave device. You may find that the clock speed is too high for the length of cable you are using. What happens if you reduce the clock speed down?
markd833:
With 144 nano's, I am guessing that there is some length of cable between the master and final slave device. You may find that the clock speed is too high for the length of cable you are using. What happens if you reduce the clock speed down?
Well for now I am simply testing with a single slave. The final design should place them less than a meter away from each other. I tried slowing the clock down, and it was producing a more consistent result for both 143 and 144 (flipping less often), so not quite helpful. Currently I'm exploring just ditching write/read_anything and simply using SPI.transfer with simpler data set formats.