SD card not working unless I enable pullup on MISO. Is this okay?

Shematic:
http://mightymicrocontroller.com/Mighty-schematic-full.png

Hey guys,

For the last week I've been pulling my hair out over this issue with my SD card. It works with my firmware if I burn it directly, but with the code in my bootloader which reads the firmware from the SD card, the SD card refuses to respond when sent CMD 0. Or more specifically, it hangs in the wait_ready() loop before it even sends the command, never getting the 0xFF byte that indicates that it's okay to start sending it commands.

I've compared the code line by line with the code in the firmware that works, and the only difference I can find is that the code in the working version just gives up after a while if the card refuses to send the 0xFF bytes it's looking for to indicate it is ready. I haven't quite figured out what it does after that, but I would assume that it doesn't simply ignore the failure. (the SD card code in the firmware is that which came with the WaveHC lib)

The thing is, as soon as I enable the pullup on MISO, everything works great. The bootloader searches for new firmware, it loads it, and the firmware runs.

But I'm concerned that pulling that MISO pin up to 5V is going to damage the 3.3V SD card. It is through a 50K resistor though, so maybe it's okay?

Anyway, here's the relevant functions in the bootloader. Maybe someone can at least spot where I've gone wrong?

static
void power_on (void)
{
	
	// Set CS pin to output
		SD_CS_BLOCK |= (1<<SD_CS_PIN);
		
	// Set CS high	 	
	 	DESELECT();		

	// Set MOSI pin to output
		DDR_MOSI |= (1<<DD_MOSI);
		
	// Set MISO pullup high?
		//DDRD  &= ~(1<<0);	
		PORTD |=  (1<<0); 
	
	UBRR0 = 0; // Baud rate must be set to 0 for initialization.
	 
	DDR_SCK |= (1<<DD_SCK); // Set XCK pin as output.
	
	UCSR0C = (1 << UMSEL01) | (1 << UMSEL00); // Put USART in MSPI mode.  And set SPI data mode to 0. 
	UCSR0B = (1 << RXEN0) | (1 << TXEN0); // Enable transmitter and receiver

	UBRR0 = 31; // Set clock rate to f_osc/64 for initialization sequence.
	
	//_delay_ms(10); // wait 10 ms
	
	for (uint8_t n = 0; n<10; n++) rcvr_spi(); 	/* 80 dummy clocks */
		
	// prevent re-init hang by cards that were in partial read
	//	SELECT();
	//	for (uint16_t i = 0; i <= 512; i++) rcvr_spi();	

}
#define rcvr_spi() xmit_spi(0xFF)
#define rcvr_spi_m(dst) UDR0 = 0xFF; while(!(UCSR0A & (1 << RXC0))); *(dst) = UDR0

inline BYTE xmit_spi(BYTE dat) {UDR0 = dat; while(!(UCSR0A & (1 << RXC0))); return UDR0;}
static
BYTE wait_ready (void)
{
	uint8_t res;
	
	rcvr_spi();
		
	do {
		//SELECT();
		res = rcvr_spi();
		//DESELECT();
		//FLASH_LED_PORT ^= 1<<FLASH_LED_PIN; _delay_ms(25); // Gets here
	} while (res != 0xFF);
	
	return res;
}

The code hangs in that while loop when the booloader tries to send CMD 0 to the card. CMD 0 calls wait_ready() before it executes, and that's where it hangs.
Unless I have that pullup enabled. Then everything works fine.

What level shifting circuitry do you have connected between the 5V microcontroller and the 3.3V SD card?

Oh, sorry I posted the wrong part of the schematic. I've updated the link above.

Here's the full schematic for my board:
http://mightymicrocontroller.com/Mighty-schematic-full.png

Some SDcards set miso (and others) open collector during the init sequence, so people indicate problems w/o a pullup (I've seen somewhere 30% cards need pullups). The internal 50k pullup (to +5V) is weak so the card's clamping diodes at the inputs will probably survive (will pass the current to the card's 3V3 thus limit input voltage to 3V3+Vfd). You may connect for example a schottky diode from miso (anode) to the card's 3V3 (cathode) to be on safe side.. Do not turn atmega's miso input to output - this may destroy the sdcard..

pito:
Some SDcards set miso (and others) open collector during the init sequence, so people indicate problems w/o a pullup (I've seen somewhere 30% cards need pullups). The internal 50k pullup (to +5V) is weak so the card's clamping diodes at the inputs will probably survive (will pass the current to the card's 3V3 thus limit input voltage to 3V3+Vfd).

So do you suppose I could enable the 50K pullup during the init sequence, and then disable it from that point on? Would that even be worthwhile, from the standpoint of trying to protect that diode? Which portion is considered the init sequence? Everything in power_on() up to and including the 80 dummy clocks perhaps?

I guess I can try it and see what happens...

Or you may simply put a 10k pullup from miso (at sdcard's side) to 3V3 and do not enable the pullup in atmega. That is probably the best approach.. Atmega is fine with 3V3 input when powered from 5V.

pito:
Or you may simply put a 10k pullup from miso (at sdcard's side) to 3V3 and do not enable the pullup in atmega. That is probably the best approach.. Atmega is fine with 3V3 input when powered from 5V.

I've got a couple hundred boards already manufactured and I'd rather not have to apply yet another patch to them if I don't have to. I already had to turn the serial port USART1 into a third data bus for my leds because you can't stop sending data to the LED drivers in the middle of an update and that was forcing me to skip samples on the DAC resulting in static. :confused:

I've got a couple hundred boards already manufactured

There is always a 3rd option: "do nothing". Enable the internal pullup and that's it. You carry the risk, of course..

So you've got a 74LVC3G34 to level shift the 5V signals from the atmega to 3.3V for the SD card, however you haven't done any level shifting the other way round. This means that the high level signal voltage from the SD card to the atmega input is marginal. The pullup resistor will increase the high level input voltage to approximately 4V (the voltage at which the protection diode in the SD card conducts, and that probably explains why it fixes the problem.

You would be well advised to include a level-shifting circuit between the SD card and the atmega MISO pin. One simple option is a small signal diode (e.g. 1N4148), cathode to SD card output, anode to MISO pin, along with a pullup resistor of around 10K between MISO and +5V. This will still result some current flowing into the SD card pin protection diode. If you want to reduce that current, replace the diode by the base and emitter of PNP transistor with its collector connected to ground.

dc42:
Could I use the internal pullup rather than adding another resistor? If not, why not?

scswift:
dc42:
Could I use the internal pullup rather than adding another resistor? If not, why not?

Yes, you could.

Well I seem to have gotten it working without the need for the pullup. I changed the wait_ready function to be like so:

static
BYTE wait_ready (void)
{
	uint8_t res, n = 0;
	
	rcvr_spi();
		
	do {
		res = rcvr_spi();
		//FLASH_LED_PORT ^= 1<<FLASH_LED_PIN; _delay_ms(25); // Gets here
	} while ((res != 0xFF) && (n++ < 255));
	
	return res;
}

With that simple change it now seems to work. In fact, it works with n < 10, and probably even lower than that, but I did 255 just to be safe.

The idea here is that when the card is first powered up but before CMD 0 is issued, and possibly certain other init commands, the MISO pin may be in an open collector state. In that state I'll never read 0xFF for ready cause I guess the pin is floating? Anyway, this acts as a timeout and assumes the card is ready if it doesn't get 0xFF after a bunch of reads.

And it's working for me now. My firmware loaded fine.

Another thing which lends credence to the idea of this pin floating during init is that I found I could in fact enable that pullup only during the init sequence and then turn it off and the card would continue to work fine. But since I don't know that that pullup won't fry the card, this timeout solution is better.