Problems reading a register value with SPI

Hello,

I have a Duemilanova board and am working on getting an SPI device to work with it. After a week of thinking that the device was faulty, I discovered that there is no clock signal on pin 13. I am seeing the SlaveSelect pin go high and low when instructed to, but there is no signal on the clock pin. I am wondering if I am missing something. Here is the code:

#include <SPI.h>

#define SLAVESELECT 10
#define SPICLOCK 13
#define DATAOUT 11 //MOSI
#define DATAIN 12 //MISO
#define UBLB(a,b) ( ( (a) << 8) | (b) )
#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )

void setup()
{
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK, OUTPUT);
  pinMode(SLAVESELECT, OUTPUT);
  digitalWrite(SLAVESELECT, HIGH);
  SPCR = B01010011; //
  clr=SPSR; // SPi Status Register
  clr=SPDR; // SPi Data Register
  delay(10);
  Serial.begin(115200);
  delay(500);
}

Am I forgetting to set something or turn some setting on? I took the code directly from the Apress Beginning Arduino book. I am using a Oscilloscope to verify the pin signals. Any thoughts on how to troubleshoot this?

Jay

The SPI clock only occurs when you are sending/receiving data. Are you?

You should try the included SPI library instead of direct register manipulation. If that still fails then you might have a hardware fault.

#include <SPI.h>

// set pin 10 as the slave select
const int slaveSelectPin = 10;

void setup() {
  // set the slaveSelectPin as an output:
  pinMode (slaveSelectPin, OUTPUT);
  // initialize SPI:
  SPI.begin(); 
}

void loop() {
   byte received =  SPI.transaction(0x00);
}

You don't need to call these
#define SPICLOCK 13
#define DATAOUT 11 //MOSI
#define DATAIN 12 //MISO

pinMode(DATAOUT, OUTPUT);
pinMode(DATAIN, INPUT);
pinMode(SPICLOCK, OUTPUT);

this takes care of them
#include <SPI.h>

Don't you also need
spi.begin()
and then
spi.transfer(data_byte) commands?

http://www.arduino.cc/playground/Code/Spi

You will see a burst of high-speed clock as the byte gets shifted out.
Nick Gammon has a page with scope captures showing this.
I have also posted (quite recently) code showing transfers needed for talking to MAX7219, if you want to see concrete examples.

Ok, so things are working better now. Here is the modified code:

#include <SPI.h>

// set pin 10 as the slave select
const int slaveSelectPin = 10;

void setup() {
  Serial.begin(115200);
  // set the slaveSelectPin as an output:
  pinMode (slaveSelectPin, OUTPUT);
  // initialize SPI:
  SPI.begin(); 
}

void loop() {
   byte received =  SPI.transfer(0x00);
   Serial.print("Register 0x00:0x");
   Serial.println(received,HEX);
   digitalWrite(slaveSelectPin, LOW);
   SPI.transfer(0x00);
   SPI.transfer(0xFF);
   digitalWrite(slaveSelectPin, HIGH);
   received =  SPI.transfer(0x00);
   Serial.print("Register 0x00:0x");
   Serial.println(received,HEX);
}

I see clock now on pin 13, with data on pin 12. Problem now is my device (CC1101 RF Board) doesn't want to accept the write process. Register 0x00 starts with 0x00 value, and after I try and write 0xFF to that register, it doesn't take.

Read the datasheet for the device you are programming.

Address 0x00 is the IOCFG2 register. I don't think 0xFF is a valid value for that register. Perhaps that is the reason the write didn't work.

Changed to writing 0x02 which is a valid value for that register. Still same result.

I also tried to add some delay(s) in there (other posts on the forum suggested that). I also have an RFM22B RF board that uses SPI and I get the same results with that board. I also tried a different Arduino board. Just trying to eliminate any possible hardware failures from the equation.

More work done today:

I have 2 setups: an RFM22B module hooked to a Arduino Duemilanova board, and a CC1101 hooked to a Arduino Uno board.

Running the RFM22B setup I get the following output. (0x0B = IOCFG2 which is a R/W register, default value 0x01)

Register 0x0B:0x1
Register 0x0B:0xFF
Register 0x0B:0xFF

Running the CC1101 setup I get the following output. (0x00 = IOCFG2 also R/W, default value 0x29)

Register 0x0B:0x0
Register 0x0B:0xF
Register 0x0B:0xF

void setup() {
  Serial.begin(115200);
  // set the slaveSelectPin as an output:
  pinMode (slaveSelectPin, OUTPUT);
  // initialize SPI:
  SPI.begin(); 
}

void loop() {
   byte received =  SPI.transfer(0x00); //0x0B for RFM22B
   Serial.print("Register 0x00:0x");
   Serial.println(received,HEX);
   digitalWrite(slaveSelectPin, LOW);  
   delay(1000);
   byte received2 =  SPI.transfer(0x00); //0x0B for RFM22B
   Serial.print("Register 0x00:0x");
   Serial.println(received2,HEX);
}

This seems really odd. I can't get consistent results. I am quite frustrated that I can't seem to get the simplest of tasks (reading a value from a register) to work at all.

This is the clock and SI lines

One more thing. I am not using any resistors in the 4 SPI lines. It goes directly from the board to the Arduino. I have read a lot on the topic of SPI and there really isn't any consistency in the use of pullup resistors on these lines. Could that be causing problems?

For the CC1101, at least, you are supposed to send the command to read a register and then do another transaction to read the result (the chip can't return data until it knows what register you want to read:

const int slaveSelectPin = 10;

void setup() {
  Serial.begin(115200);
  // set the slaveSelectPin as an output:
  pinMode (slaveSelectPin, OUTPUT);
  // initialize SPI:
  SPI.begin(); 
}

void loop() {
   byte result;

   // Begin a read or write cycle
   digitalWrtite(slaveSelectPin, LOW);  Enable the slave

   // Send the command to read register 0
   SPI.transfer(0x00);

   // Now read a byte from the chip.  THE VALUE WE SEND MAKES NO DIFFERENCE WHEN READING.
   // We just need to generate 8 clock pulses and sample the MISO line to get the data.
   //  Sending a byte will generate the clock pulses
   result = SPI.transfer(0x42); 

   //  Register read operation complete
   digitalWrite(slaveSelectPin, HIGH);  

   Serial.print("Register 0 contains 0x");
   Serial.println(result,HEX);

   delay(1000);
}

Actually, I got it to work just now. I added a 10k resister to the CSN line. Now I get very consistent results. When I write a value to a register, it actually reads back what I expect to be there! W00t!

Thanks for all the help! Now if I can just get the carrier detect to work......:slight_smile: