Need help getting an SD card (MISO pin) to work

Hi

I am trying to use a) an SD card and b) a LoRa Radio shield, which is also an SPI device. Both work perfectly when separate. However when I use them together, only the SD works. More specifically: The LoRa Shield works as long as MISO from the SD is disconnected. Everything else(Mosi, CS, VCC etc.) can be left connected. And yes, I am not sharing a CS pin or something. I've checked that every pin the shield uses is otherwise unused and vice versa.

Any one got an Idea?

Pins used by LoRa

ss - new slave select pin to use, defaults to 10
reset - new reset pin to use, defaults to 9
dio0 - new DIO0 pin to use, defaults to 2

SD uses as CS Pin 4

LoRa library

#include <SPI.h>
#include <LoRa.h>

int counter = 0;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0));

  Serial.println("LoRa Sender");

  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  Serial.print("Sending packet: ");
  Serial.println(counter);

  // send packet
  LoRa.beginPacket();
  LoRa.print("hello ");
  LoRa.print(counter);
  LoRa.endPacket();

  counter++;

  delay(5000);
}

Need to buffer MISO from the SD card to get it off the SPI bus when the SD card's slave select is not active.
Use one gate of 74HC125 with the Gate Enable connected to the SD card slave select.

Ok, but why? Shouldn't it work anyway?

Ps: (As I haven't got that IC right now) I guess it wouldn't work with just a transistor?

Anyone?

SD cards can sometimes output on MISO while they finish up their internal processing,

Transistor - depends how you connect it up. Don't want to end up with MISO inverted going back to the uC.

The problem of SD cards holding on to MISO appears to be discussed at length in this thread, there do appear to be software solutions ?

http://forum.arduino.cc/index.php?topic=276274.0

I add the buffer in my designs, just in case SD cards have clamp diodes, I don't want interference on the 5V bus messing up programming or other MISO drivers.

SPI is not nearly as standard as one would like - two nominally SPI devices can't just be assumed to
work together.

By the way SDcards shouldn't be assumed to be 5V tolerant, 3.3V is the highest voltage they support
(fortunately the SPI interface doesn't switch to lower voltages dynamically like the native interface!).

srnet:
SD Card - MISO doesn't release [Bad MISO, Bad MISO!!] - Storage - Arduino Forum

As noted in #28 in that link, if you are using the SD library (you don't show your SD code, so who knows what lib you're using?)...

SD.h does have a problem with MISO. You can cause MISO to go high-Z with SD.h by sending a byte like this while SD chip select is high. Any value will work since SD cards only need some clocks to release MISO.

SPI.transfer(0XFF);

OTOH, SdFat causes MISO to go high-Z so that is not likely the problem. There are SD modules that won't share the SPI bus properly. The modules have a level shifter that causes a problem with MISO.

Well, if you insist on the code, here goes:

//SD///////
#include <SPI.h>
#include <SD.h>

//LORA
#include <LoRa.h>

//TEMPERATURE N HUMIDITY//////////////
#include <SparkFunHTU21D.h>

//BMP180////////////////////////////////////////
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>
/////////////////////////// 

//GPS STUFF////////////////
#include <SoftwareSerial.h>
SoftwareSerial GPS(3, 5);
byte gps_set_sucess = 0 ; 
char gpssentence[66];
//////////////////////////

//BMP180//////////
Adafruit_BMP085_Unified bmp = Adafruit_BMP085_Unified(10085);
float pressure;
float inTemp;
///////////////////////

//Ozone//////////////
int OZval;
/////////////////////

//UV/////
float uvIntensity;

/////////

/////Temp +Hum///////
HTU21D myHumidity;
float humidity;
float temp;
////////////////////

//SD//////
const int chipSelect = 4;
/////////
void setup() {
   pinMode(A0, INPUT);
  
  //GPS STUF/////////////////////////
  GPS.begin(9600); 
  // START OUR SERIAL DEBUG PORT
  Serial.begin(9600);
  Serial.println(F("GPS Level Convertor Board Test Script"));
  Serial.println(F("03/06/2012 2E0UPU"));
  Serial.println(F("Initialising...."));
  //
  // THE FOLLOWING COMMAND SWITCHES MODULE TO 4800 BAUD
  // THEN SWITCHES THE SOFTWARE SERIAL TO 4,800 BAUD
  //
  GPS.print(F("$PUBX,41,1,0007,0003,4800,0*13\r\n")); 
  GPS.begin(4800);
  GPS.flush();
 
  //  THIS COMMAND SETS FLIGHT MODE AND CONFIRMS IT 
  Serial.println(F("Setting uBlox nav mode: "));
  uint8_t setNav[] = {
    0xB5, 0x62, 0x06, 0x24, 0x24, 0x00, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x27, 0x00, 0x00, 
    0x05, 0x00, 0xFA, 0x00, 0xFA, 0x00, 0x64, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xDC };
  while(!gps_set_sucess)
  {
    sendUBX(setNav, sizeof(setNav)/sizeof(uint8_t));
    gps_set_sucess=getUBX_ACK(setNav);
  }
  gps_set_sucess=0;
 

GPS.println(F("$PUBX,40,GLL,0,0,0,0*5C"));
GPS.println(F("$PUBX,40,GGA,0,0,0,0*5A"));
GPS.println(F("$PUBX,40,GSA,0,0,0,0*4E"));
GPS.println(F("$PUBX,40,RMC,0,0,0,0*47"));
GPS.println(F("$PUBX,40,GSV,0,0,0,0*59"));
GPS.println(F("$PUBX,40,VTG,0,0,0,0*5E"));
////////////////////////////////////////////////////////////////////////////////////////////////////

//BMP180////////////////////
  if(!bmp.begin())
  {
    /* There was a problem detecting the BMP085 ... check your connections */
    Serial.print(F("Ooops, no BMP085 detected ... Check your wiring or I2C ADDR!"));
    while(1);
  }
  ////////////////////////////////////

  //Temp + Humidity///////
  myHumidity.begin();
  ////////////////

  //SD////////
  Serial.print(F("Initializing SD card..."));

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println(F("Card failed, or not present"));
    // don't do anything more:
    return;
  }
  Serial.println(F("card initialized."));
Serial.println("$PUBX, ID, Time, Lattitude, N, Longtitude, E, Altitude, SatFix, Hacc, Vacc, Rest, pressure, InTemp, OZ, UV, outTemp, Humidity");
File logdataE = SD.open("TheData.txt", FILE_WRITE);
  if (logdataE) {
  logdataE.println("$PUBX, ID, Time, Lattitude, N, Longtitude, E, Altitude, SatFix, Hacc, Vacc, Rest, pressure, InTemp, OZ, UV, outTemp, Humidity");
    logdataE.close();
    } 
    else {
    //Datei kann nicht geöffnet werden
        Serial.println("Error");
}

//LORA

if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
}

void loop() {
  getgps();
  readsensors();
  logdata();
  senddata();
/*
 unsigned long previousMillis = millis();
   unsigned long currentMillis = millis(); 
  while (currentMillis - previousMillis <= 3000) {
    // save the last time you blinked the LED
     currentMillis = millis();
  }
  */
  
}


void getgps(){

   GPS.println(F("$PUBX,00*33"));
   
   unsigned long previousMillis = millis();
   unsigned long currentMillis = millis(); 
  while (currentMillis - previousMillis <= 3000) {
    // save the last time you blinked the LED
     currentMillis = millis();
  }


  while (GPS.available())
{
    for (int i=0; i <66 ; i++)
    {
        gpssentence[i] = GPS.read();
    }
}
  
}
void readsensors(){
  getBarTemp();
  getOZ();
  getUV();
  getTempHum();
  
  
}

void logdata(){
  File dataFile = SD.open("theData.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    for (int i=0; i <66 ; i++)
    {
        dataFile.print(gpssentence[i]);
    }
    dataFile.print(F(", "));
    dataFile.print(pressure);
    dataFile.print(F(", "));
    dataFile.print(inTemp);
    dataFile.print(F(", "));
    dataFile.print(OZval);
    dataFile.print(F(", "));
    dataFile.print(uvIntensity);
    dataFile.print(F(", "));
    dataFile.print(temp);
    dataFile.print(F(", "));
    dataFile.println(humidity); 
    dataFile.close();


for (int i=0; i <66 ; i++)
    {
        Serial.print(gpssentence[i]);
    }
    Serial.print(F(", "));
    Serial.print(pressure);
    Serial.print(F(", "));
    Serial.print(inTemp);
    Serial.print(F(", "));
    Serial.print(OZval);
    Serial.print(F(", "));
    Serial.print(uvIntensity);
    Serial.print(F(", "));
    Serial.print(temp);
    Serial.print(F(", "));
    Serial.println(humidity); 
    
   
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println(F("error opening datalog.txt"));
  }
  
  
}




void getBarTemp(){
 /* Get a new sensor event */ 
  sensors_event_t event;
  bmp.getEvent(&event);

  if (event.pressure)
  {
    pressure = event.pressure;
   
    bmp.getTemperature(&inTemp);
  }
  else
  {
    Serial.println(F("Sensor error"));
  }
}

void getOZ(){
  OZval = analogRead(1);
}

void getUV(){
  int uvLevel = averageAnalogRead(A0);
  
  float outputVoltage = uvLevel * (5.0 / 1023.0);
  
  uvIntensity = mapfloat(outputVoltage, 0.99, 2.8, 0.0, 15.0);
}

void getTempHum(){
  humidity = myHumidity.readHumidity();
  temp = myHumidity.readTemperature();
  
}

void senddata(){
  LoRa.beginPacket();

  for (int i=0; i <66 ; i++)
    {
        LoRa.print(gpssentence[i]);
    }
    LoRa.print(F(", "));
    LoRa.print(pressure);
    LoRa.print(F(", "));
    LoRa.print(inTemp);
    LoRa.print(F(", "));
    LoRa.print(OZval);
    LoRa.print(F(", "));
    LoRa.print(uvIntensity);
    LoRa.print(F(", "));
    LoRa.print(temp);
    LoRa.print(F(", "));
    LoRa.println(humidity); 
    
  
  LoRa.endPacket();
}



// Send a byte array of UBX protocol to the GPS
void sendUBX(uint8_t *MSG, uint8_t len) {
  for(int i=0; i<len; i++) {
    GPS.write(MSG[i]);
    Serial.print(MSG[i], HEX);
  }
  GPS.println();
}
 
 
// Calculate expected UBX ACK packet and parse UBX response from GPS
boolean getUBX_ACK(uint8_t *MSG) {
  uint8_t b;
  uint8_t ackByteID = 0;
  uint8_t ackPacket[10];
  unsigned long startTime = millis();
  Serial.print(F(" * Reading ACK response: "));
 
  // Construct the expected ACK packet    
  ackPacket[0] = 0xB5;  // header
  ackPacket[1] = 0x62;  // header
  ackPacket[2] = 0x05;  // class
  ackPacket[3] = 0x01;  // id
  ackPacket[4] = 0x02;  // length
  ackPacket[5] = 0x00;
  ackPacket[6] = MSG[2];  // ACK class
  ackPacket[7] = MSG[3];  // ACK id
  ackPacket[8] = 0;   // CK_A
  ackPacket[9] = 0;   // CK_B
 
  // Calculate the checksums
  for (uint8_t i=2; i<8; i++) {
    ackPacket[8] = ackPacket[8] + ackPacket[i];
    ackPacket[9] = ackPacket[9] + ackPacket[8];
  }
 
  while (1) {
 
    // Test for success
    if (ackByteID > 9) {
      // All packets in order!
      Serial.println(F(" (SUCCESS!)"));
      return true;
    }
 
    // Timeout if no valid response in 3 seconds
    if (millis() - startTime > 3000) { 
      Serial.println(F(" (FAILED!)"));
      return false;
    }
 
    // Make sure data is available to read
    if (GPS.available()) {
      b = GPS.read();
 
      // Check that bytes arrive in sequence as per expected ACK packet
      if (b == ackPacket[ackByteID]) { 
        ackByteID++;
        Serial.print(b, HEX);
      } 
      else {
        ackByteID = 0;  // Reset and look again, invalid order
      }
 
    }
  }
}

Have fun reading it all :slight_smile:

So you reckon it might work if I add this line after I'm done with the SD?

SPI.transfer(0XFF);

I have had a chance to try this, my LoRa receivers do log tracker telemtry to an SD card, and I have never had a problem with the combination of the two.

Indeed the SD card does hang onto MISO and a ;

SPI.transfer(0XFF);

Does release it and the cards MISO output goes high Z.

Writing or reading to the LoRa device is a two byte process, first write the register address across SPI and then do another byte transfer which is a read or write.

As the first byte is a write the resultant clocks clear the SD card MISO output before the LoRa device puts a byte out (for a read) over its own MISO.