I am having problems using SPI to communicate with two SPI devices: the adafruit micro-SD card breakout board+ and a YEI 3-Space Sensor Embedded (Inertial Measurement Unit / Attitude & Heading Reference System).
Hardware setup:
Arduino UNO R3 http://arduino.cc/en/Main/ArduinoBoardUno
Micro-SD Card Breakout Board+ http://www.adafruit.com/products/254
3-Space Sensor Embedded (3SS) http://tech.yostengineering.com/3-space ... y/embedded
1. Micro-SD Card Breakout Board+ & Arduino:
I have followed the very helpful tutorial provided through adafruit, http://www.ladyada.net/products/microsd/, and can get the Arduino to successfully run all of the example programs provided in the new SD library.
2. 3-Space Sensor Embedded & Arduino:
The 3SS is a complex beast, but I can get it working perfectly with the Arduino SPI library: sending commands and receiving data. It would be best to think of this as a black box, outside of the SPI interface. It operates by receiving commands (from Arduino) and sending data in full duplex. I have this code if necessary.
3. Micro-SD Card Breakout Board+, 3-Space Sensor Embedded & Arduino:
I essentially combined the above two programs into this "end game" program, while making sure the setup remains correct according to each of the requirements. Right off the bat, the program showed itself to be very finicky and prone to stop running in the first loop or having one of the two SPI devices not run/return data. I have tried a myriad of options, hacks and suggestions found through Arduino, adafruit, and other sources; but they are not worth listing unless the topic comes up in the future.
Here is the code:
Code: Select all
/*
IMUData2SDcard
Get the 3-axis accelerometer and 3-axis gyroscope data from the IMU
using SPI then save the results in a file on the microSD card.
Uses the SPI and SD library.
Hardware Setup
Arduino SDcard TSS-EM
pin 7 SS
pin 10 SS
pin 11 MOSI MOSI
pin 12 MISO MISO
pin 13 SCK SCK
created 03/01/2013
by David Hughes
*/
#include <SPI.h>
#include <SD.h>
/* Pins used for SPI connection */
const int chipSelectPinIMU = 7;
const int chipSelectPinSDcard = 10;
// the rest are controlled by the SPI library
/* Union for each of the 9 sensors */
// Needed to convert the bytes from SPI to float
union u_types {
byte b[4];
float fval;
} data[9]; // Create 9 unions, one for each sensor from the IMU
// Gyroscope: x-axis, y-axis, z-axis
// Accelerometer: x-axis, y-axis, z-axis
// Compass: x-axis, y-axis, z-axis
/* File object */
File myFile;
/* Initialization */
void setup() {
Serial.begin(9600);
// Start the SPI library:
digitalWrite(chipSelectPinIMU, HIGH);
SPI.begin();
// Set the chip select pin for IMU:
pinMode(chipSelectPinIMU, OUTPUT);
Serial.print(F("Initializing SD card..."));
// Set the chip select pin for the SDcard board:
pinMode(chipSelectPinSDcard, OUTPUT);
// Initialize the SDcard and library
if (!SD.begin(chipSelectPinSDcard)) {
Serial.println(F("initialization failed!"));
} else {
Serial.println(F("initialization done."));
}
// Give the sensor time to set up:
delay(1000);
}
// Debugging code, to check usage of RAM
// Example Call: Serial.println(freeRam());
//int freeRam () {
// extern int __heap_start, *__brkval;
// int v;
// return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
//}
/* Main Loop */
void loop() {
Serial.print(F("Sending packet..."));
// Take the chip select low to select the device:
digitalWrite(chipSelectPinIMU, LOW);
// Clear the internal data buffer on the IMU
SPI.transfer(0x01);
delay(10);
// Send start of packet:
SPI.transfer(0xF6);
delay(1);
// Send command:
SPI.transfer(0x40);
delay(1);
// Get status of device:
byte result = SPI.transfer(0xFF);
while (result != 0x01) { // Repeat until device is Ready
delay(1);
result = SPI.transfer(0xFF);
}
// Get the 36 bytes of return data from the device:
for (int ii=0; ii<9; ii++) {
for (int jj=0; jj<4; jj++) {
data[ii].b[jj] = SPI.transfer(0xFF);
delay(1);
Serial.print("data[");
Serial.print(ii);
Serial.print("].b[");
Serial.print(jj);
Serial.print("]: ");
Serial.println(data[ii].b[jj],HEX);
}
}
// Take the chip select high to de-select:
digitalWrite(chipSelectPinIMU, HIGH);
Serial.println(("Packet send/receive complete."));
// Convert Big Endian (IMU) to Little Endian (Arduino)
for( int mm=0; mm<9; mm++) {
endianSwap(data[mm].b);
}
Serial.println(F("Data endian swap complete."));
// Traverse the union to print the data values
Serial.println(F("Gyroscope:"));
for (int kk=0; kk<9; kk++) {
Serial.print(data[kk].fval);
if (kk == 2) {
Serial.println("");
Serial.println(F("Acceleration:"));
} else if (kk == 5) {
Serial.println("");
Serial.println(F("Compass:"));
} else {
Serial.println("");
}
}
// Open the file. Note that only one file can be open at a time
myFile = SD.open("test.txt", FILE_WRITE);
// Write data to the file
if (myFile) { // if the file opened okay, write to it:
Serial.print(F("Writing to test.txt..."));
// Traverse the union to print the data values
myFile.println("Gyroscope:");
for (int kk=0; kk<9; kk++) {
myFile.print(data[kk].fval);
if (kk == 2) {
myFile.println("");
myFile.println("Acceleration:");
} else if (kk == 5) {
myFile.println("");
myFile.println("Compass:");
} else {
myFile.println("");
}
}
myFile.close(); // close the file
Serial.println(F("Write to file complete."));
} else {
// if the file didn't open, print an error:
Serial.println(F("error opening test.txt"));
}
myFile.println("");
delay(5000); // Wait x/1000 seconds before next loop
}
/* Endian swap - big to little */
inline void endianSwap(byte temp[4]) {
// Serial.println("Before swap: ");
// Serial.println(temp[0],HEX);
// Serial.println(temp[1],HEX);
// Serial.println(temp[2],HEX);
// Serial.println(temp[3],HEX);
byte myTemp = temp[0];
temp[0] = temp[3];
temp[3] = myTemp;
myTemp = temp[1];
temp[1] = temp[2];
temp[2] = myTemp;
// Serial.println("After swap: ");
// Serial.println(temp[0],HEX);
// Serial.println(temp[1],HEX);
// Serial.println(temp[2],HEX);
// Serial.println(temp[3],HEX);
}
Here picture of the data returned from the 3SS during operation of the 3SS & Arduino program, which shows how the correct data should be received (nicely organized in 4 bytes):
Here is a picture of the data returned from the 3SS during operation of the above program, 3SS & SD board & Arduino, which shows the incorrect byte-stream:
My initial conclusion was based on this line of reasoning, in that there is a conflict between the libraries. Could they be in conflict with initializing the SPI twice? What is the SPI "mode" of the adafruit board, defined as clock polarity (CPOL) and clock phase (CPHA)? [3SS is CPOL=0, CPHA=0.]
I am happy to include more information, or clarification, on any of the above information. We hope to hear back soon and look forward to finding a solution to this problem.
Thank you.