Reading 16 bits of data via SPI

I have been trying to read 3D magnetic data from a Sparkfun MicroMag3 magnetic sensor. I am working on building a tilt adjusted compass to go on my 15x80 binoculars. I was able to get an 8 bit read from a LIS3LV02DQ accelerometer running in one evening. But I am a now stumped how to get 2 bytes back from my MicroMag3 instead of a single byte returned from my accelerometer.

The MicroMag3 documentation lists 6 easy (?) steps.

  1. Bring SlaveSelect low (Pin 4)
  2. Pulse the RESET (Pin 6) high and back to low. You must RESET the chip for every reading
  3. Send 8 bits on the MOSI line (Pin 3). The MicroMag3 then executes the command. (Note: I use the SPDR = 0x01 statement to send a command to the sensor. 0x01 is the command for measuring the X axis.)
  4. The chip makes the measurement. We just wait.
  5. The chip DRDY (Pin 5) is set high to indicate data ready
  6. In response to the next 16 SCKL pulses, data is shifted out the MISO (Pin 2) line.
    Repeat as desired.

Step 6 has me stumped. I modified the code from my accelerometer project but did not have a lot of luck with the MicroMag3. I am receiving some data back from the sensor that changes slowly when I rotate and tilt the sensor. It returns the same value if I leave it on the table, so it appears to be doing something. I have a guess I am getting the first byte back.

I need two specific pieces of advice:

  1. I used the idiom:

while (!(SPSR & (1<<SPIF)))
{};
return SPDR; // received data appears in the SPDR register

to check to see if the data was ready. Should I read the READY pin directly and ignore the ATMega SPI registers?

  1. How can I send 1 byte and get back 2 bytes? It looks like I am getting one byte back. I can not modify SPDR because it a a physical register on the ATMega chip.

Jim Kraemer
AD5UY

The SPI data register is only 8 bits wide so to recieve 16 bits you have to read two bytes and combine the result-

byte spi_transfer(volatile byte data)
{
SPDR = data; // Start the transmission
while (!(SPSR & (1<<SPIF))); // Wait the end of the transmission
{
};
return SPDR; // return the received byte
}

spi_transfer(0x01); // send command to sensor
int xAxisValue;
xAxisValue = spi_transfer(0x00); // read the 1st byte
xAxisValue <<= 8; // shift the byte to the high 8 bits
xAxisValue |= spi_transfer(0x00); // read the 2nd byte and OR to the low 8 bits of xAxisValue

Hope this helps-

Thanks! I had not understood that I would use "spi_transfer(0x00)" twice to get back additional input without having to send another SPI command byte. I will give that a try tomorrow.

Jim