Reading register values from SPI

I am attempting to read a resonant inductive distance sensor with a CAM204 chip. I previously tried to get the sensor to work directly with the arduino, and found that I should be using SPI through this post http://forum.arduino.cc/index.php?topic=277186.0

I am currently using the SPI functionality, by hooking the sensor to the Cam204 chip and that to the arduino uno. My problem is that I am not getting any value back via the SPI.transfer() method when i try to read the register.

Attached is my code. I am sending 2 bytes through SPI for the read command and address(opcode RESA) to be read, setting SS low, and attempting to read the register, setting SS high, and returning that value.

Have I forgotten a step? Any thoughts on how to troubleshoot this?
Thank you.

CAM204 datasheet: http://cambridgeic.com/images/downloads/033-0003_0010_(CAM204).pdf

riSensor.ino (1.88 KB)

The address of the RESA register for Sensor 1 is 0x102. You are using address 0x002 which is the system SYSIO register.

You also seem to be trying to read the sensor without first setting the GO bit in SCW and waiting a suitable interval. You are also apparently supposed to read the SCW and PTEF registers before reading the Result register. See section 13 of the datasheet for how to use the chip.

Thank you for the insight. I have read the necessary registers and bits I want to turn on, but I am still confused about how to send these through SPI.

johnwasser: The address of the RESA register for Sensor 1 is 0x102. You are using address 0x002 which is the system SYSIO register.

I am currently sending one byte followed by another because the SPI.transfer() only accepts one byte at a time. How do you send a register and with the bits you want turned on, when each register is a 4bit mode followed by a 12 bit address? For example for the SCW is 0x100 for sensor 1. I want to write-read this register and activate the GO bit(which is the lsb of the SCW register). So would i send firstByte = 0b11110001, and then secondByte = 00000001? I could not find a forum or tutorial on this topic, but a link to one may be equally helpful.

Section 11 covers the basic Read and Write instructions. The top four bits of the first byte are 0000 (0x0) for Read and 1111 (0xF) for Write. The high four bits of the register address go in the low four bits of the first address byte, just after the Read or Write bits. The low eight bits of the register address go in the second address byte. After that you read or write two bytes for each consecutive register you want to read or write.

To write the Sensor 1 SCW register:

digitalWrite(SS, LOW);
SPI.transfer(0xF1);  // Write, Sensor 1...
SPI.transfer(0x00);  // ... Sensor Control Word register
SPI.transfer(0x00);  // High Byte 0
SPI.transfer(0x01);  // Low Byte: Set the GO bit
digitalWrite(SS, HIGH);

To Read the Sensor 1 RESA register:

digitalWrite(SS, LOW);
SPI.transfer(0xF1);  // Read, Sensor 1...
SPI.transfer(0x02);  // ... RESA register
highByteA = SPI.transfer(0x00);  // Read High Byte of RESA
lowByteA = SPI.transfer(0x00);  // Read Low Byte of RESA
highByteB = SPI.transfer(0x00);  // Read High Byte of RESB
lowByteB = SPI.transfer(0x00);  // Read Low Byte of RESB
.
.
.
digitalWrite(SS, HIGH);

The datasheet says that you are supposed to put in a SEVEN SECOND delay between the address and the Read or Write data. I expect that is a typo and they really meant seven MICROseconds. Hopefully the time it takes for library calls witll be sufficient. If not, add "delayMicroseconds(7);" between the address and data transfers.

1 Like

I have gotten the CTU board to successfully talk to the arduino, and I am reading a valid output for the chip via the ctuid register. Although, I am running into timing problems that make my output for the position sensor indiscernible. I am attempting to have a repeated single-shot measurement. I have added various delays which have been little help. I have also looked at the option to use sample indicators or going for a continuous output but I do not think these options are necessary for the purpose of the project. I am only getting a new and valid output from the SCW register intermittently (shown as 110000 as second byte), and I am getting a value from the RESA register that seems to be repeated continuously which I cant find the cause of.

Is there a timing delay that I am not taking into account?
Secondly, What is this strange repeating output?

Code and Output Attached

rssMeasureRiSensor.ino (4.81 KB)

It seems I've solved my own problem. By changing the SPI setClockDivider from 16 to 32. I am not sure why this fixed the problem but everything now works as expected. Thanks!

Still running into a problem with reading the results register. It in the data sheet it says that when I read the RESA register I should be receiving a value somewhere between -32768 and +32768. The values I am reading are vastly beyond that. There are two bytes that need to be read and combined to get the full result for CtuReportedPositionI16 in the register. I am currently achieving this by the following code.

digitalWrite(SS, LOW);
  SPI.transfer(0xF1);    // RESA register (result A, and desired output) 
  SPI.transfer(0x02);    //read mode on sensor 1, part of address to be read
  delayMicroseconds(7); 
  int highByteAA = SPI.transfer(0x00);  // Read High Byte of RESA  
  delayMicroseconds(20);
  int lowByteAB = SPI.transfer(0x00);  // Read Low Byte of RESA  
  digitalWrite(SS, HIGH);  
  delayMicroseconds(200);
  
  long serialData = 0;
  if (highByteAA < 0) {
    serialData = highByteAA * 1000 - lowByteAB;   
  }
  else {
    serialData = highByteAA * 1000 + lowByteAB;
  }
  Serial.print(serialData);

Am I defining the variables incorrectly, how do I get the true CtuReportedPosition as my output?

You are not combining the bytes correctly. Try something like

unsigned char highByteA = SPI.transfer(0x00);  // Read High Byte of RESA
unsigned char lowByteA = SPI.transfer(0x00);  // Read Low Byte of RESA
unsigned int RESAval = (highByteA <<8 ) || (lowByteA);

Implementing that code resulted in a read out of 1, no matter where I shifted the sensor. Should I be implementing the word, word(), or byte declarations to combine the bytes instead?

Sorry for the typo - I accidentally typed a logical OR, rather than a bitwise OR. Should read:

unsigned char highByteA = SPI.transfer(0x00);  // Read High Byte of RESA
unsigned char lowByteA = SPI.transfer(0x00);  // Read Low Byte of RESA
unsigned int RESAval = (highByteA << 8 ) | (lowByteA);