Trying to convert WaveHC to work with USART

And not having much luck. :frowning:

I’ve converted the code, but the SD init function keeps returning a fail condition:

/* Arduino WaveHC Library
 * Copyright (C) 2008 by William Greiman
 *  
 * This file is part of the Arduino WaveHC Library
 *  
 * This Library is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This Library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 
 * You should have received a copy of the GNU General Public License
 * along with the Arduino WaveHC Library.  If not, see
 * <http://www.gnu.org/licenses/>.
 */
#if ARDUINO < 100
#include <WProgram.h>
#else  // ARDUINO < 100
#include <Arduino.h>
#endif  // ARDUINO < 100
#include <SdReader.h>
#include <WavePinDefs.h>
//------------------------------------------------------------------------------
// inline SPI functions

/** Send a byte to the card */
inline void spiSend(uint8_t b) {UDR0 = b;} //{UDR0 = b; while(!(UCSR0A & (1 << TXC0)));} //inline void spiSend(uint8_t b) {SPDR = b; while(!(SPSR & (1 << SPIF)));}

/** Receive a byte from the card */
inline uint8_t spiRec(void) {spiSend(0XFF); return UDR0;} //inline uint8_t spiRec(void) {spiSend(0XFF); return SPDR;}


/** Set Slave Select high */
inline void spiSSHigh(void) {
  digitalWrite(SS, HIGH);
  // insure SD data out is high Z
  spiSend(0XFF);
}

/** Set Slave Select low */
inline void spiSSLow(void) {digitalWrite(SS, LOW);}


//------------------------------------------------------------------------------
// card status

#define R1_READY_STATE 	   0 	   /** status for card in the ready state */
#define R1_IDLE_STATE  	   1    /** status for card in the idle state */
#define DATA_START_BLOCK      0XFE /** start data token for read or write */
#define DATA_RES_MASK         0X1F /** mask for data response tokens after a write block operation */
#define DATA_RES_ACCEPTED     0X05 /** write data accepted token */
#define DATA_RES_CRC_ERROR    0X0B /** write data crc error token */
#define DATA_RES_WRITE_ERROR  0X0D /** write data programming error token */


//------------------------------------------------------------------------------
// send command to card
uint8_t SdReader::cardCommand(uint8_t cmd, uint32_t arg) {
  uint8_t r1;
  
  // end read if in partialBlockRead mode
  readEnd();
  
  // select card
  spiSSLow();
  
  // wait up to 300 ms if busy
  waitNotBusy(300);
  
  // send command
  spiSend(cmd | 0x40);
  
  // send argument
  for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
  
  // send CRC
  uint8_t crc = 0XFF;
  if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0
  if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA
  spiSend(crc);
  
  // wait for response
  for (uint8_t retry = 0; ((r1 = spiRec()) & 0X80) && retry != 0XFF; retry++);

  return r1;

}

//------------------------------------------------------------------------------
/**
 * Determine the size of an SD flash memory card.
 * \return The number of 512 byte data blocks in the card
 */ 
uint32_t SdReader::cardSize(void) {
  csd_t csd;

  if (!readCSD(csd)) return false;

  if (csd.v1.csd_ver == 0) {

    uint8_t read_bl_len = csd.v1.read_bl_len;
    uint16_t c_size = (csd.v1.c_size_high << 10)
                      | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
    uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
                          | csd.v1.c_size_mult_low;
    return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);

  }
  else if (csd.v2.csd_ver == 1) {

    uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
                      | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
    return (c_size + 1) << 10;

  }
  else {

    error(SD_CARD_ERROR_BAD_CSD);
    return 0;

  }
}

//------------------------------------------------------------------------------
/**
 * Initialize a SD flash memory card.
 *
 * \param[in] slow If \a slow is false (zero) the SPI bus will
 * be initialize at a speed of 8 Mhz.  If \a slow is true (nonzero)
 * the SPI bus will be initialize a speed of 4 Mhz. This may be helpful
 * for some SD cards with Version 1.0 of the Adafruit Wave Shield.
 *
 * \return The value one, true, is returned for success and
 * the value zero, false, is returned for failure. 
 *
 */  
uint8_t SdReader::init(uint8_t slow) {
  uint8_t ocr[4];
  uint8_t r;
  
  pinMode(SS, OUTPUT); 
  digitalWrite(SS, HIGH);
  pinMode(MOSI, OUTPUT);
  pinMode(MISO, INPUT);
  pinMode(SCK, OUTPUT);
  
#if SPI_INIT_SLOW

  // Enable SPI, Master, clock rate f_osc/128
  //SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);

UBRR0 = 0; // Baud rate must be set to 0 for initialization.
DDRB |= 1; // Set the data direction of port B0, the xck pin for the SD card.
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 = 63; // Set clock rate to f_osc/128
	
#else  

  // Enable SPI, Master, clock rate f_osc/64
  //SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1);

UBRR0 = 0; // Baud rate must be set to 0 for initialization.
DDRB |= 1; // Set the data direction of port B0, the xck pin for the SD card.
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

#endif 
  
  // must supply min of 74 clock cycles with CS high.
  for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
  
  // next two lines prevent re-init hang by cards that were in partial read
  spiSSLow();
  for (uint16_t i = 0; i <= 512; i++) spiRec();
  
  // command to go idle in SPI mode
  for (uint8_t retry = 0; ; retry++) {
    if ((r = cardCommand(CMD0, 0)) ==  R1_IDLE_STATE) break;
    if (retry == 10) {
      error(SD_CARD_ERROR_CMD0, r);
      return false;
    }
  }
  // check SD version
  r = cardCommand(CMD8, 0x1AA);
  if (r == R1_IDLE_STATE) {
    for(uint8_t i = 0; i < 4; i++) {
      r = spiRec();
    }
    if (r != 0XAA) {
      error(SD_CARD_ERROR_CMD8_ECHO, r);
      return false;
    }
    type(SD_CARD_TYPE_SD2);
  }
  else if (r & R1_ILLEGAL_COMMAND) {
    type(SD_CARD_TYPE_SD1);
  }
  else {
    error(SD_CARD_ERROR_CMD8, r);
  }
  // initialize card and send host supports SDHC if SD2
  for (uint16_t t0 = millis();;) {
    cardCommand(CMD55, 0);
    r = cardCommand(ACMD41, type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0);
    if (r == R1_READY_STATE) break;
    
    // timeout after 2 seconds
    if (((uint16_t)millis() - t0) > 2000) {
      error(SD_CARD_ERROR_ACMD41);
      return false;
    }
  }
  // if SD2 read OCR register to check for SDHC card
  if (type() == SD_CARD_TYPE_SD2) {
    if(cardCommand(CMD58, 0)) {
      error(SD_CARD_ERROR_CMD58);
      return false;
    }
    if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
    
    // discard rest of ocr
    for (uint8_t i = 0; i < 3; i++) spiRec();
  }

  // use max SPI frequency unless slow is true
 	 // SPCR &= ~((1 << SPR1) | (1 << SPR0)); // f_OSC/4
  	 //if (!slow) SPSR |= (1 << SPI2X); // Doubled Clock Frequency: f_OSC/2
  
	if (!slow) { UBRR0 = 0; } else { UBRR0 = 1; }

	spiSSHigh();

  return true;
}

I’m also not sure I got all the checks for transmit/receive right since SPI only has the one flag but the USART has both transmit and receive. (In most cases transmit I think does not need to wait because the USART has a buffer, but there is one case in there where it deselects the SD card pin and so I waited for that transmit to end before allowing it to continue.)

Second half of code:

//------------------------------------------------------------------------------
/**
 * Read part of a 512 byte block from a SD card.
 *  
 * \param[in] block Logical block to be read.
 * \param[in] offset Number of bytes to skip at start of block
 * \param[out] dst Pointer to the location that will receive the data. 
 * \param[in] count Number of bytes to read
 * \return The value one, true, is returned for success and
 * the value zero, false, is returned for failure.      
 */
uint8_t SdReader::readData(uint32_t block,
                           uint16_t offset, uint8_t *dst, uint16_t count) {
  if (count == 0) return true;
  if ((count + offset) > 512) {
    return false;
  }
  if (!inBlock_ || block != block_ || offset < offset_) {
    block_ = block;
    
    // use address if not SDHC card
    if (type()!= SD_CARD_TYPE_SDHC) block <<= 9;
    if (cardCommand(CMD17, block)) {
      error(SD_CARD_ERROR_CMD17);
      return false;
    }
    if (!waitStartBlock()) {
      return false;
    }
    offset_ = 0;
    inBlock_ = 1;
  }
  
  // start first SPI transfer
  UDR0 = 0xFF; //SPDR = 0XFF;
  
  // skip data before offset
  for (;offset_ < offset; offset_++) {
    //while(!(SPSR & (1 << SPIF))); // Wait until transfer complete before transmitting next bit.
    UDR0 = 0xFF; //SPDR = 0XFF;
  }
  
  // transfer data
  uint16_t n = count - 1;
  for (uint16_t i = 0; i < n; i++) {
    while(!(UCSR0A & (1 << RXC0)));  //while(!(SPSR & (1 << SPIF))); // Wait until transfer complete before reading next bit.
   dst[i] = UDR0; //SPDR; // Act of reading data clears transfer bit.
    UDR0 = 0xFF; // SPDR = 0XFF;
  }
  
  // wait for last byte
  while(!(UCSR0A & (1 << RXC0))); //while(!(SPSR & (1 << SPIF))); // Wait until transfer complete before reading next bit.
  dst[n] = UDR0; // SPDR;
  offset_ += count;
  if (!partialBlockRead_ || offset_ >= 512) readEnd();
  return true;
}
//------------------------------------------------------------------------------
/** Skip remaining data in a block when in partial block read mode. */
void SdReader::readEnd(void) {
  if (inBlock_) {
    // skip data and crc
    UDR0 = 0xff; //SPDR = 0XFF;
    while (offset_++ < 513) {
      // while(!(SPSR & (1 << SPIF))); // Wait until transfer complete before transmitting next bit.
      UDR0 = 0xff; //SPDR = 0XFF;
    }
    // wait for last crc byte
    while(!(UCSR0A & (1 << TXC0))); //while(!(SPSR & (1 << SPIF))); // Wait until transmit buffer is empty.
    spiSSHigh();
    inBlock_ = 0;
  }
}
//------------------------------------------------------------------------------
/** read CID or CSR register */
uint8_t SdReader::readRegister(uint8_t cmd, uint8_t *dst) {
  if (cardCommand(cmd, 0)) {
    error(SD_CARD_ERROR_READ_REG);
    return false;
  }
  if(!waitStartBlock()) return false;
  
  //transfer data
  for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec();
  
  spiRec();// get first crc byte
  spiRec();// get second crc byte
  
  spiSSHigh();
  return true;
}
//------------------------------------------------------------------------------
// wait for card to go not busy
uint8_t SdReader::waitNotBusy(uint16_t timeoutMillis) {
  uint16_t t0 = millis();
  while (spiRec() != 0XFF) {
    if (((uint16_t)millis() - t0) > timeoutMillis) return false;
  }
  return true;
}
//------------------------------------------------------------------------------
/** Wait for start block token */
uint8_t SdReader::waitStartBlock(void) {
  uint8_t r;
  uint16_t t0 = millis();
  while ((r = spiRec()) == 0XFF) {
    if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
      error(SD_CARD_ERROR_READ_TIMEOUT);
      return false;
    }
  }
  if (r == DATA_START_BLOCK) return true;
  error(SD_CARD_ERROR_READ, r);
  return false;
}

I’m at my wits end here. I’ve looked at others examples and my code seems to match. The SD lib’s logging example works in software mode with the SD card so I know the pins are connected properly.

Here’s my latest changes to try to get this to work. Please let me know if you see something wrong here:

#define XCK0_DDR DDRB 
#define XCK0 1<<0 //PB0 

/** Send a byte to the card */
inline void spiSend(uint8_t b) {while(!(UCSR0A & (1 << UDRE0))); UDR0 = b;}  // {UDR0 = b; while(!(UCSR0A & (1 << TXC0)));} 		//inline void spiSend(uint8_t b) {SPDR = b; while(!(SPSR & (1 << SPIF)));}

/** Receive a byte from the card */
inline uint8_t spiRec(void) {while(!(UCSR0A & (1 << UDRE0))); UDR0 = 0; while(!(UCSR0A & (1 << RXC1))); return UDR0;} 			// {spiSend(0XFF); return UDR0;} //inline uint8_t spiRec(void) {spiSend(0XFF); return SPDR;}

//------------------------------------------------------------------------------
/**
 * Initialize a SD flash memory card.
 *
 * \param[in] slow If \a slow is false (zero) the SPI bus will
 * be initialize at a speed of 8 Mhz.  If \a slow is true (nonzero)
 * the SPI bus will be initialize a speed of 4 Mhz. This may be helpful
 * for some SD cards with Version 1.0 of the Adafruit Wave Shield.
 *
 * \return The value one, true, is returned for success and
 * the value zero, false, is returned for failure. 
 *
 */  
uint8_t SdReader::init(uint8_t slow) {
  uint8_t ocr[4];
  uint8_t r;
  
  pinMode(SS, OUTPUT); 
  digitalWrite(SS, HIGH);
  pinMode(MOSI, OUTPUT);
  pinMode(MISO, INPUT);
  pinMode(SCK, OUTPUT);
  
#if SPI_INIT_SLOW

  // Enable SPI, Master, clock rate f_osc/128
  //SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);

UBRR0 = 0; 						// Baud rate must be set to 0 for initialization.
XCK0_DDR |= (1<<XCK0); // DDRB |= 1; 						// Set the data direction of port B0, the xck pin for the SD card.
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 = 63; 						// Set clock rate to f_osc/128
	
#else  

  // Enable SPI, Master, clock rate f_osc/64
  //SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1);

UBRR0 = 0; 						// Baud rate must be set to 0 for initialization.
XCK0_DDR |= (1<<XCK0); // DDRB |= 1; 						// Set the data direction of port B0, the xck pin for the SD card.
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

#endif 
  
/*
    UBRR0 = 0;
    XCK0_DDR |= (1<<XCK0);
    UCSR0C = (3<<UMSEL00)|mode;  ?????
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
    UBRR0 = speed; 
*/



  // must supply min of 74 clock cycles with CS high.
  for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); // I guess because this sends 8 bits, that this is 80 clock cycles?
  
  // next two lines prevent re-init hang by cards that were in partial read
  spiSSLow();
  for (uint16_t i = 0; i <= 512; i++) spiRec();
  
  // command to go idle in SPI mode
  for (uint8_t retry = 0; ; retry++) {
    if ((r = cardCommand(CMD0, 0)) ==  R1_IDLE_STATE) break;
    if (retry == 10) {
      error(SD_CARD_ERROR_CMD0, r);
      return false;
    }
  }

   return true;
}

I’ve removed most of the code from the initialization function to test one bit of it at a time. But even with only the above it still returns false.

As far as I can see the USART init code looks right.

You didn’t reset the UCPHAn bit in UCSR0C, is that the phase you want?

Also you have LSB first, is that OK?


Rob

As far as I know the phase bit is correct. I left those bits at 0 like the SPI was set.

I don’t think I have LSB first, I’m not setting the UDORD bit and the datasheet says:

• Bit 2 – UDORDn: Data Order
When set to one the LSB of the data word is transmitted first. When set to zero the MSB of the
data word is transmitted first.

I think I may have just gotten the card to initialize properly though.

I changed the receive line here:

/** Send a byte to the card */
inline void spiSend(uint8_t b) {while(!(UCSR0A & (1 << UDRE0))); UDR0 = b;}  		// {UDR0 = b; while(!(UCSR0A & (1 << TXC0)));} 		//inline void spiSend(uint8_t b) {SPDR = b; while(!(SPSR & (1 << SPIF)));}

/** Receive a byte from the card */
inline uint8_t spiRec(void) {spiSend(0XFF); while(!(UCSR0A & (1 << RXC0))); return UDR0;}   // {while(!(UCSR0A & (1 << UDRE0))); UDR0 = 0; while(!(UCSR0A & (1 << RXC0))); return UDR0;} 			// {spiSend(0XFF); return UDR0;} //inline uint8_t spiRec(void) {spiSend(0XFF); return SPDR;}

You can see the previous version commented out. I was sending 0 instead of 0xFF to get the card to reply. I don’t know if that makes a difference but my LED is blinking fast and that indicates the init didn’t fail.

Btw, I’m having to debug this stupid thing without a serial monitor because I stupidly did not include an FTDI port because I intended the firmwate to be updated via the SD card and the ISP was just there to get the bootloader on. I thought I could do serial over ISP. :frowning:

Anyway I am going to see now if I can get the card to do anything else. I may have gotten over the first bump. I’m hoping the remainder will be easier.

Just uncommented the rest of that init function and it still seems to be succeeding. Now for the rest...

UDORDn defaults to 1 at power up and you don't set it to 0 so that's LSB first.

UCPHAn also default to 1 which is not what one usually expects, that's why I mentioned it.


Rob

UDORDn defaults to 1 at power up and you don’t set it to 0 so that’s LSB first.

It does default to 1, but I am setting the USR0C register like so:

UCSR0C = (1 << UMSEL01) | (1 << UMSEL00);

The result of that should be UCSR0C = 11000000.

Yes, sorry. I read it as |=.

So I don't get my board then :)


Rob

"UCPHAn also default to 1 which is not what one usually expects, that's why I mentioned it."

I will look into this.

[edit]

Oh that's in the same register, so that's reset to 0 as well.

noob derail question:

What is/does converting the WaveHC lib over to USART do?

I have a WaveHC shield board I use... for some custom projects.. so the title grabbed my attention.

Is this have to do with having more than one device on SPI buss now while being able to play audio? (sample the SD card constantly...etc)

sorry to 'dumb down' the thread.. haha.. (but I'll never know unless I ask)

thanks

-xl

The reason I am trying to use the WaveHC lib over USART is because I designed a board with an Atmega1284P which has an SD card, a DAC, and a place to attach TLC5947 LED drivers. All of these things need to either be connected to an SPI bus, or have the SPI protocol bit-banged over other pins.

The reason I didn't put them all on the standard SPI bus is because SD cards are slow to wake up when you try to talk to them and in order to transfer data fast you have to transfer it in 512 byte chunks and then read the audio data or what have you from a buffer as needed. This means the SD card wouldn't play nice with a DAC and an LED driver competing for attention. I talked to the guy who made the WaveHC lib a while back and there's just no way around this.

So, rather than bit bang the DAC and LED drivers, I decided to put them on their own hardware SPI bus and put the SD card on a USART configured to run in SPI mode. But I didn't know that all the registers are different and it needs to be accessed in a different manner.

And, since it's too late to swap my SD card over to the SPI bus and put the DAC and the LEDs on those USART pins (which would have required changing a lot less code, and could have just been bit-banged), I've got no choice but to update the SD card stuff I need to use, like WaveHC's SD card code, to work with a USART instead.

yes.. I remeber that thread (it was my thread that i started on the WaveHC lib.. when I too had a board with the DAC on the SPI bus, and couldnt get any audio working..etc..etc)

thanks for the explanation! :)

-xl

So for future reference, the USART works in SPI mode with the above code? It was the data sent to the SD that was the problem?

Can you post a working version just for the record?


Rob

It seems to work, but some bits of the lib are still acting up. I still haven't gotten it to the point where I can play sounds. The lib doesn't use the transfer functions everywhere in it so I probably messed up some other bits here and there. Once I clean the code up and have it all working I'll share it. It's a mess right now though. I have a ton of lines in there for blinking LEDs cause I didn't have a serial debugger I could use but I solved that this evening as well and now have that running on USART1 with a new bootloader. Thank god. :-)

Just some random notes. I don't know if my musings at the end are accurate:

RXCn: USART Receive Complete This flag bit is set when there are unread data in the receive buffer and cleared when the receive buffer is empty

TXCn: USART Transmit Complete This flag bit is set when the entire frame in the Transmit Shift Register has been shifted out and there are no new data currently present in the transmit buffer (UDRn).

UDREn: USART Data Register Empty The UDREn Flag indicates if the transmit buffer (UDRn) is ready to receive new data. If UDREn is one, the buffer is empty, and therefore ready to be written.

Using TXCn in the spiSend function would make it wait until the whole transmit buffer was empty before it would try to put new data into it. Using UDREn instead just checks to see if the data has been moved from the UDREn register into the transmit buffer. Presumably data is not moved from UDREn until there is room in the transmit buffer for it, so there should be no need to check TXCn, except perhaps, when changing the state of the chip select pin on the SD card. In that case, data which hasn't yet been transmitted could be lost.

Hm, using this for SPI send gives card init fail:

{UDR0 = b; while(!(UCSR0A & (1 << TXC0)));}

And using this hangs:

{while(!(UCSR0A & (1 << TXC0))); UDR0 = b;}

Using this works:

{while(!(UCSR0A & (1 << UDRE0))); UDR0 = b;}

But the original code was this:

{SPDR = b; while(!(SPSR & (1 << SPIF)));}

The first one would seem like the best one to use until I was sure I had everything working because in theory it would send one byte at a time and wait until the byte send was complete, like the original code did. But it doesn’t work, and I don’t know why. Or perhaps it does work and the one I am using is hiding a problem because it’s buffered?

The second one, I’m not sure why it hangs. I guess maybe the bit is set to 0 somewhere and if nothing is sent after that it will never get set to 1 again.

The third one I believe waits until the data register is empty and ready to receive new data, then the new byte it put into the register and at some point is moved to the buffer, and then to the SD card. With that one I cannot be sure the SD card has gotten the data before I move on to the next command.

I am not sure how to resolve this.

Hm, I may have found the answer in another thread. The TXCn bit is SET when the transmit buffer is empty. This is opposite the behavior of RXCn. Also, unlike RXCn, it is never cleared unless you explicitly clear it yourself. (Or you are using an interrupt to read it.)

Something else I’ve just learned is that you have to clear it by writing a 1 to the bit. This seems nonsensical, but apparently with bits that are reset by interrupts this is done because it prevents a race condition that could result from reading the register first so you can set the one bit without altering the others. I’ll just chalk up how the processor does this to magic, and that writing a 1 in these special cases results in a 0 appearing.

http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_intbits

With that said, I’ve just tried this version of the code, and it seems to work as well as the other version. And probably better because the other version was only checking to see if it was okay to push a new byte into the buffer, not that the buffer was empty. But it could be improved because this version like SPI would not make use of the transmit buffer and instead would just put in one byte at a time and wait for it to go out. But for now I need to be sure my code works. Optimization can come later.

inline void spiSend(uint8_t b) {UCSR0A = (1 << TXC0); UDR0 = b; while(!(UCSR0A & (1 << TXC0)));} // I believe this version will clear the transmit complete flag before transmitting the byte, then check to make sure it finished transmitting.  Though this is not as efficient as it might be, because we're not making use of the buffer.

Well, here’s where I’m currently stuck. I keep getting No valid FAT partition errors, and I assume it is because the code in these functions is not working properly.

//------------------------------------------------------------------------------
/**
 * Read part of a 512 byte block from a SD card.
 *  
 * \param[in] block Logical block to be read.
 * \param[in] offset Number of bytes to skip at start of block
 * \param[out] dst Pointer to the location that will receive the data. 
 * \param[in] count Number of bytes to read
 * \return The value one, true, is returned for success and
 * the value zero, false, is returned for failure.      
 */
uint8_t SdReader::readData(uint32_t block,
                           uint16_t offset, uint8_t *dst, uint16_t count) {

	Serial1.println(F("SdReader::readData"));

  if (count == 0) return true;

  if ((count + offset) > 512) {
	Serial1.println(F("SdReader::readData -> (count + offset) > 512"));
    return false;
  }

  if (!inBlock_ || block != block_ || offset < offset_) {

    block_ = block;
    
    // use address if not SDHC card
    if (type()!= SD_CARD_TYPE_SDHC) block <<= 9;

    if (cardCommand(CMD17, block)) {
      error(SD_CARD_ERROR_CMD17);
      return false;
    }

    if (!waitStartBlock()) {
      return false;
    }

    offset_ = 0;
    inBlock_ = 1;

  }
  

/*

inline void spiSend(uint8_t b) {UCSR0A = (1 << TXC0); UDR0 = b; while(!(UCSR0A & (1 << TXC0)));} 
inline uint8_t spiRec(void) {spiSend(0XFF); while(!(UCSR0A & (1 << RXC0))); return UDR0;} 

*/


  // start first SPI transfer
	//SPDR = 0XFF;
	spiSend(0xFF); // spiSend sends a byte them waits till it transfers before exiting, so I should be able to use it here.  	

  // skip data before offset (I think what this is doing is telling the SD card to send bytes back, and ignoring them.)
  for (;offset_ < offset; offset_++) {
	
	//while(!(SPSR & (1 << SPIF)));  // Wait until transfer complete before transmitting next bit. 
	//SPDR = 0XFF;
	
	spiSend(0xFF);
    
  }
  

	// I'm confused about what is going on above, and whether a byte will be received as it should be below.


  // transfer data
  uint16_t n = count - 1;
  for (uint16_t i = 0; i < n; i++) {

	//while(!(SPSR & (1 << SPIF))); // Wait until transfer complete.  I believe this is waiting until the last byte from the last loop is sent?
	//dst[i] = SPDR; // Read data.  Act of reading data clears transfer bit. (Not sure why that's important.)
	//SPDR = 0XFF; // Transmit 0xFF

	while(!(UCSR0A & (1 << RXC0)));
	dst[i] = UDR0;
	UDR0 = 0xFF; // It may not be necessary to check to make sure the transfer completed her because we wait for a reply.

  }
  
  // wait for last byte

	//while(!(SPSR & (1 << SPIF))); // Wait until transfer complete before reading next bit.
	// dst[n] = SPDR;

	 while(!(UCSR0A & (1 << RXC0)));   
	dst[n] = UDR0; 

  offset_ += count;
  if (!partialBlockRead_ || offset_ >= 512) readEnd();
  return true;

}


//------------------------------------------------------------------------------
/** Skip remaining data in a block when in partial block read mode. */
void SdReader::readEnd(void) {

	Serial1.println(F("SdReader::readEnd"));

  if (inBlock_) {
    // skip data and crc

		//SPDR = 0XFF;
		// while(!(SPSR & (1 << SPIF))); // Wait until transfer complete before transmitting next bit.

		spiSend(0xFF);	     

	while (offset_++ < 513) {

      	// while(!(SPSR & (1 << SPIF))); // Wait until transfer complete before transmitting next bit.
		//SPDR = 0XFF;

     		 spiSend(0xFF);

	}

    // wait for last crc byte
	
		//while(!(SPSR & (1 << SPIF))); // Wait until transmit buffer is empty.

		// Since spiSend() does that, I don't think I need to do anything here.
  		
    spiSSHigh();
    inBlock_ = 0;

  }
}