Porting UNO project to MEGA, SD/Ethernet hardware issue.

I have a project that works on the UNO.

From bottom to top (Edited order after second post):

UNO R3
Arduino SD/Ethernet
Arduino GSM Shield
MAX 31855 K-Type Thermocouple Shield (ch4-7)

I am now porting this to the MEGA.

I have jumped pins 11->51, 12->50, 13->52 for the SD/Ethernet/Thermocouple SPI, and 2->69 for the GSM RX. When plugging them in all together, the thermocouple readings are garbage.

I have plugged them all in separately, they work fine. I have plugged in the GSM and the SD/Ethernet, they work fine. I have plugged in the GSM and the Thermocouple, they work fine. I have plugged in the SD/Ethernet and Thermocouple, I get garbage thermocouple readings. The SD still works fine when they both are plugged in.

Okay. I plugged all three in and turned off all calls to the ethernet and SD library, and commented out all code having to do with the SD/Ethernet shield. The Thermocouple STILL gets garbage readings.

Okay. Now again, without the SD/Ethernet libraries being used, I can get the data to fluctuate between garbage and no data by messing with the output pins. In my UNO code I define and turn high both the SD and Ethernet SS pins.

pinMode(4, OUTPUT); //SD card chip select
pinMode(10, OUTPUT); //Ethernet chip select
digitalWrite(4, HIGH); // SD Card not active
digitalWrite(10, HIGH); // Ethernet not active

The SD/Ethernet website says I must also turn on pin 53 as an output.

http://arduino.cc/en/Main/ArduinoEthernetShield

On the Mega, the hardware SS pin, 53, is not used to select either the W5100 or the SD card, but it must be kept as an output or the SPI interface won't work.

So currently I'm using:

pinMode(4, OUTPUT); //SD card chip select
pinMode(10, OUTPUT); //Ethernet chip select
pinMode(53, OUTPUT);
digitalWrite(4, HIGH); // SD Card not active
digitalWrite(10, HIGH); // Ethernet not active

But this doesn't work. I've tried many variations of those three pins but no luck.

So in conclusion, all shields work separately and together on the UNO. Every shield works on the MEGA by itself. However, anytime the Thermocouple Shield and SD/Ethernet shield, which both happen to use SPI are plugged in together, the Thermocouple shield doesn't work. Any suggestions? I will share any other information if needed.

The ethernet shield with the w5100 and the ICSP socket on the bottom doesn't have anything connected to D11 to D13. The SPI data/clock lines are on the ICSP connector only.

edit: Which thermocouple shield are you using? A link to that hardware might help.

It's a small library.

//File Name: PlayingWithFusion_MAX31855-1CH.cpp

#include "PlayingWithFusion_MAX31855_1CH.h"

PWFusion_MAX31855_TC::PWFusion_MAX31855_TC(int8_t CSx)
{
  // Function to initialize thermocouple channel, load private variables
  _cs = CSx;
  
  // immediately pull CS pin high to avoid conflicts on SPI bus
  digitalWrite(_cs, HIGH);
}

void PWFusion_MAX31855_TC::MAX31855_update(struct var_max31855 *tc_ptr)
{
  // Function to unpack and store MAX31855 data
  uint32_t full_read;
  full_read = spiread_32bits();	// all data is packed into 4 8-bit registers

  int16_t temp_i16;
  uint8_t temp_u8;

  // un-pack chip fault status
  if(full_read & 0x00010000)
  {
	  temp_u8 = (uint8_t)(full_read & 0x00000007);
	  tc_ptr->status = temp_u8;
	  // leave external (thermocouple) temp channel unchanged
  }
  else
  {
	  // make sure faults are cleared
	  tc_ptr->status = 0;

	  // un-pack TC temp data
	  temp_i16 = (int16_t)(full_read >> 18);
	  if(0x2000 & temp_i16)			// negative value
	  {
		  temp_i16 &= 0x1FFF;		// save only first 13 bits of data
		  temp_i16 |= 0x8000;		// add on sign bit
	  }
	  else							// positive value
	  {
		  temp_i16 &= 0x1FFF;		// no sign, save only first 13 (pos val)
	  }
	  tc_ptr->value = temp_i16;		// save TC temp. Note: int16 with 2 bits of
	  									// resolution (2^-2 = 0.25 deg C per bit)
  }

  // un-pack MAX31855 internal temp data
  temp_i16 = (int16_t)(full_read >> 4);
  if(0x0800 & temp_i16)				// negative value
  {
	  temp_i16 &= 0x07FF;			// save only first 11 bits of data
	  temp_i16 |= 0x8000;			// add on sign bit
  }
  else								// positive value
  {
	  temp_i16 &= 0x07FF;			// no sign, save only first 11 (pos val)
  }
  tc_ptr->ref_jcn_temp = temp_i16;	// save TC temp. Note: int16 with 4 bits of
	  									// resolution (2^-8 = 0.0625 deg C per bit)
}

uint32_t PWFusion_MAX31855_TC::spiread_32bits(void)
{
  // Function to read 32 bits of SPI data
  uint8_t i;
  uint32_t four_bytes = 0;
  
  digitalWrite(_cs, LOW);	// set CS low
  _delay_ms(1);			// allow state transistion time
  
  four_bytes |= SPI.transfer(0x00);		// read 1st byte
  four_bytes <<= 8;						// shift data 1 byte left
  four_bytes |= SPI.transfer(0x00);		// read 2nd byte
  four_bytes <<= 8;						// shift data 1 byte left
  four_bytes |= SPI.transfer(0x00);		// read 3rd byte
  four_bytes <<= 8;						// shift data 1 byte left
  four_bytes |= SPI.transfer(0x00);		// read 4th byte
  
  digitalWrite(_cs, HIGH);	// set CS high before leaving
  return four_bytes;
}
//File Name: PlayingWithFusion_MAX31855_1CH.h

#ifndef PWF_MAX31855_1_h
#define PWF_MAX31855_1_h

#include "Arduino.h"			// use "WProgram.h" for IDE <1.0
#include "avr/pgmspace.h"
#include "util/delay.h"
#include "stdlib.h"
#include "PlayingWithFusion_MAX31855_STRUCT.h"
#include "SPI.h"

class PWFusion_MAX31855_TC
{
 public:
  PWFusion_MAX31855_TC(int8_t CSx);
  void SPIbus_Init(void);
  void MAX31855_update(struct var_max31855 *tc_ptr);

 private:
  int8_t _cs;
  uint32_t spiread_32bits(void);
};

#endif
//File Name: PlayingWithFusion_MAX31855-1CH.h

#ifndef PWF_MAX31855_STRUCT_H
#define PWF_MAX31855_STRUCT_H

#include "avr/pgmspace.h"

struct var_max31855{
    int16_t  value;			// TC temperature, 0.25 dec C/bit w/ sign
    int16_t  ref_jcn_temp;	// temp of chip ref jcn, 0.0625 deg C/bit +sign
    uint8_t  status;		// TC status - valid/invalid + fault reason
};


#endif /* PWF_MAX31855_STRUCT_H */

It uses pins 12 and 13 for MISO and SCLK.

For the SD/Ethernet shield, I'm using SDFat and the included Ethernet libraries (although not right now, they're both commented out).

I unplugged the jumpers and you're right, they aren't needed for the SD/Ethernet. It works without them. It is using the ICSP connector..which makes me realize I messed up my order as described earlier.

From bottom to top (actual order):

UNO R3 (or MEGA)
Arduino SD/Ethernet
Arduino GSM Shield
MAX 31855 K-Type Thermocouple Shield (ch4-7)

So from what I understand, just putting power to the SD/Ethernet shield means it's interfering with the Thermocouple's use of the SPI, something that doesn't appear to happen when on the UNO.

Simplifed code I'm running when all libraries are active.

void setup()
{
  
  Serial.begin(9600);
 
  // initalize the chip select pins
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(8, OUTPUT);  //jumped from pin 4
  pinMode(9, OUTPUT);  //jumped from pin 3
  pinMode(4, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(53, OUTPUT);
  digitalWrite(4, HIGH);  // SD Card not active
  digitalWrite(10, HIGH); // Ethernet not active

 if (!sd.begin(4, SPI_HALF_SPEED)) sd.initErrorHalt();  
  
  SPI.begin();                        // begin SPI

}

void loop()
{
delay(1000);
SPI.setDataMode(SPI_MODE1);
collectTemps();
delay(1000);
useSD(); //sets SPI_MODE0 when it runs.
}

Something else I don't understand...

If I bend pins 12 and 13 on the thermocouple shield so they are only connected to the jumpers for 50 and 52, the thermocouple doesn't work when by itself on the MEGA. When I bend the pins back and let the shield connect to pins 12 and 13 on the MEGA, it works, as long as the jumpers for 50 and 52 are on.

I thought pins 12 and 13 weren't doing anything, but apparently they are? Hmm...

On an Uno, SPI begin() sets the default SPI slave select (D10) to OUTPUT and HIGH to set the SPI bus to master mode. This disables the w5100 SPI by "accident" as I call it.

On a Mega, SPI begin() sets the default SPI slave select (D53) to OUTPUT and HIGH to set the SPI bus to master mode, but this does not disable the w5100 SPI. D10 is left as an input (floating). This causes problems if not corrected.

You must disable all SPI slave selects before initializing any other SPI device. I see you have disabled the w5100 and SD SPI buses, but not the thermocouple slave select. That will probably cause a fail on the SD.begin() call.

Be careful when jumpering and bending pins. Insure you don't break a connection on a required pin, or make a connection to a conflicting pin on another shield.

edit: Some libraries do not use the hardware SPI, but a software version. If your thermocouple library uses a software version, that would explain the requirement to use D11-D13. I haven't checked that library.

The thermocouple uses four slave selects (3, 4, 5, and 6). I have 3 and 4 jumped to 8 and 9, so it uses 5, 6, 8, and 9. I declare them all as an output but do not set them to HIGH. So, I will try setting pins 5, 6, 8, and 9 to HIGH as well as pins 4 and 10 before I use SPI.begin(). Will have feedback on that in about 8 hours when I return home.

Do I need to do anything with pin 53? I declare it as an output, but do not set it to HIGH.

The thermocouple library uses the standard SPI library that references the variables from pins_arduino.h. I've confirmed that it is referencing the MEGA version of this file; I've printed the SS, SLK, MISO, and MOSI to serial and it is using the 50-53 pins.

Set all SPI slave selects on all devices to OUTPUT and HIGH. You need not do that to D53 (default hardware slave select). SPI.begin() will do that for you.

Do I need to do anything with pin 53? I declare it as an output, but do not set it to HIGH.

First, AVR is strange about SPI. SS is not the default slave select as SurferTim says. It is the AVR slave select when the AVR is in slave mode. In master mode SPI will only work if SS is in output mode or is held high in input mode. This is a quirk of AVR SPI and all AVR SPI libraries setup SS correctly.

So if none of your devices are connected to SS don't do anything with SS. You do need to be aware SS is special and not use it as an input when you are using AVR SPI in master mode. Many programs set pin 10 to output mode but leave it low. These programs work on Uno but fail on Mega even if the device on pin 10 has pullups. So let the SPI library handle SS.

You must hold slave select high for all real hardware devices that are not being initialized. You can do this with pull-ups or by putting each slave select in output mode and set it high for each device. Don't depend on the quirks of SS. Just disable all SPI devices that are not being initialize whether their slave select pin is SS or some other pin.

It is too bad that the Ethernet shield does not have pullups on slave select pins. I suspect the "accident" that it works OK on Uno contributed. At any rate many days have been lost to the W5100 interfering with the SD on Mega.

fat16lib is correct. Please accept my apology and change "default slave select" to "hardware slave select" in my post above.

Well I got it working..it was a bad pin header on the thermocouple shield, pin 12. When putting the headers on I must have gotten some solder to seep in and mess up the connection. So it worked on the UNO because I wasn't using the jumpers on that header, and I must have gotten lucky when I tested the shield alone.

I used a hand drill with a miniature drill bit, size #69 and broke up some of the solder. The jumper went down just a tiny bit farther than it used to and it worked.

Thanks again for the help. I set all four of the thermocouple select pins to HIGH, and removed calls to pin 53.