SPI, geting started, troubleshoot and debug

I am trying to get a USB drive working with SPI. I have this thing: http://www.vinculum.com/prd_vdip1.html
I get some data but it is not really usefull. As if the ascii codes are shifted. With some trial and error I think I have got the settings for the SPCR register.
According to the datasheet: http://www.vinculum.com/documents/datasheets/DS_VDIP1.pdf page 9, some bits should be send to start with reading. But as far as I understand it you use the SPDR register for reading and writing. So, I think I making a mistake by writing the bits to the SPDR register and immediately afterwards reading the SPDR register:

char spi_transfer(volatile char data)
{
  SPDR = data;
  while (!(SPSR & (1<<SPIF)))     
  {
  };
  return SPDR;                    
}
char read_register(char data)
{
  char in_byte;
  digitalWrite(SLAVESELECT, HIGH);
   spi_transfer(B11000000);
  in_byte = spi_transfer(data);
  digitalWrite(SLAVESELECT, LOW); 
  return in_byte;
}

What I want to know is how to proceed. How do you get code for SPI working? Is there some strategy? I have an acceleration sensor working with SPI, but that’s only with someone else’s code. Since this device speaks SPI a little bit different I have some trouble to get it working.

But as far as I understand it you use the SPDR register for reading and writing. So, I think I making a mistake by writing the bits to the SPDR register and immediately afterwards reading the SPDR register:

this bothered me, too, but I think you’re doing it correctly. If I understand SPI correctly you’re just clocking data through a serial shift register, so simultaneously shifting old data out and new data in is valid.

Here is some extremely ugly and unfinished (but nevertheless working) code to talk to a DS1722 temperature sensor via SPI.

#define DATAOUT 11 //MOSI
#define DATAIN  12 //MISO 
#define SPICLOCK  13 //sck
#define SLAVESELECT 10 //ss

#define DS1722_SELECT HIGH
#define DS1722_DESELECT LOW

#define DS1722_CONFIG_BYTE 0x8E
#define CONFIG_REG_READ 0x00
#define CONFIG_REG_WRITE 0x80
#define TEMP_ADDR_HI 0x02
#define TEMP_ADDR_LOW 0x01

byte clr;
byte temperature[2];

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

void setup()
{
  byte n;
  byte config = 0xAB;
  Serial.begin(9600);

  temperature[0]=0x12;
  temperature[1]=0x34;

  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK, OUTPUT);
  pinMode(SLAVESELECT, OUTPUT);
  digitalWrite(SLAVESELECT, DS1722_DESELECT); //disable device
  // SPCR = 01010000
  //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
  //sample on leading edge of clk,system clock/4 rate (fastest)
//  SPCR = (1<<SPE)|(1<<MSTR);
//  SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL);
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA);
  clr=SPSR;
  clr=SPDR;
  delay(10);

  // read config byte
  digitalWrite(SLAVESELECT, DS1722_SELECT);
  spi_transfer(CONFIG_REG_READ);
  config = spi_transfer(0xFF);
  digitalWrite(SLAVESELECT, DS1722_DESELECT);
  delay(100);
  Serial.print(config, HEX);
  Serial.print('\n', BYTE);

  // write config byte to the configuration register
  digitalWrite(SLAVESELECT, DS1722_SELECT);
  spi_transfer(CONFIG_REG_WRITE);
  spi_transfer(DS1722_CONFIG_BYTE);
  digitalWrite(SLAVESELECT, DS1722_DESELECT);
  delay(100);

  // read config byte
  digitalWrite(SLAVESELECT, DS1722_SELECT);
  spi_transfer(CONFIG_REG_READ);
  config = spi_transfer(0xFF);
  digitalWrite(SLAVESELECT, DS1722_DESELECT);
  delay(100);

  Serial.print(config, HEX);
  Serial.print('\n', BYTE);

  delay(1000);
}

void loop()
{
  // write config byte to the configuration register
  digitalWrite(SLAVESELECT, DS1722_SELECT);
  spi_transfer(CONFIG_REG_WRITE);
  spi_transfer(DS1722_CONFIG_BYTE);
  digitalWrite(SLAVESELECT, DS1722_DESELECT);

  delay(1400);

  digitalWrite(SLAVESELECT,DS1722_SELECT);
  spi_transfer(TEMP_ADDR_HI);
  temperature[0] = spi_transfer(0x00);
  digitalWrite(SLAVESELECT, DS1722_DESELECT); //release chip, signal end transfer
  delay(25); // just because....
  digitalWrite(SLAVESELECT,DS1722_SELECT);
  spi_transfer(TEMP_ADDR_LOW);
  temperature[1] = spi_transfer(0x00);
  digitalWrite(SLAVESELECT, DS1722_DESELECT); //release chip, signal end transfer

  Serial.print(temperature[0], HEX);
  Serial.print(' ',BYTE);
  Serial.print(temperature[1], HEX);
  Serial.print('\n',BYTE);

  delay(2000);
}

Also note the SPI gotcha of the clock phase and polarity (CPOL and CPHA) settings. This gives you four different “modes” possible, and they may be different depending on the manufacturer’s interpretation of the standard. See the commented out lines of code to see some of the combinations.

-j

Also note the SPI gotcha of the clock phase and polarity (CPOL and CPHA) settings. This gives you four different "modes" possible, and they may be different depending on the manufacturer's interpretation of the standard. See the commented out lines of code to see some of the combinations.

I figured these settings out. But, because of the strange data I tried the other settings too. But this didn't help.

I just looked at the data sheet and it appears this thing doesn't use neat 8-bit chunks. If I read it correctly a read cycle consists of a 3 bit write followed immediately by a 9 bit read, and a write cycle is an 11 bit write followed by a single bit read. I may be off by one bit, as I'm counting that inital high of SDO as one bit, and I read this really fast.

If this is the case, the example code from the tutorials which I used (and apparently so did you) won't work here, because it's transferring bytes. I suspect you;ll need a read function that sends the appropriate setup bits, followed by the 8 data bits (probably passed into the function) followed by a read to get the status bit. The companion write function would follow similarly.

I'd have to spend some time with both the peripheral data sheet and the Atmel data sheet before I could try to tell you how to do this.

I was looking at this device yesterday for a datalogger application, so I'm very curious to see how it works out.

-j

I figured it out! :smiley:

I just looked at the data sheet and it appears this thing doesn’t use neat 8-bit chunks. If I read it correctly a read cycle consists of a 3 bit write followed immediately by a 9 bit read, and a write cycle is an 11 bit write followed by a single bit read. I may be off by one bit, as I’m counting that inital high of SDO as one bit, and I read this really fast.

If you remember the datasheet, it starts with sending 3bits, actually 11, then 0. But what they don’t show are the 0’s before these bits. So, I tried starting with B11000000, but it should be B00000110. (without knowing the datasheet this looks like nonsens I guess)
So, I still have nothing worth mentioning at the moment. But I am quite excited that I got something working.

Ah, so you're sending a whole byte (which is easier) with leading 0s and the last three setting up the transfer, then sending the data byte?

Good information. I'm still eyeballing this device as well as DOSonChip. Your feedback helps me out.

-j

Ah, so you're sending a whole byte (which is easier) with leading 0s and the last three setting up the transfer, then sending the data byte?

Yep, pretty easy, once you have figured it out.

Good information. I'm still eyeballing this device as well as DOSonChip. Your feedback helps me out.

If I can give you some advice: skip the dosonchip. I have it but I can't get it to work. I gave up and bought the VDIP1. With the VDIP1 you can you have two USB ports and you can attach whatever you want to it. One port can even be used as a USB host.