I'm trying to use the Due to process data from 10 inductance to digital converters (TI LDC1000, datasheet http://www.ti.com/lit/ds/symlink/ldc1000.pdf) but am having trouble establishing SPI communication with the LDC circuit board.
From what I can tell with an oscilloscope, SCLK is working correctly (two groups of 8 clock cycles) but both the transmitted and received bytes are on the MOSI line. Nothing is coming through on the MISO line, no matter where I probe on the LDCs or which one I select. The CS encoder is acting correctly - active low for the LDC selected. I've triple checked my wiring (see attached schematic - the 10 LDCs and the external encoder are on a custom PCB), so I'm sure that it's a software issue by now. I've searched all over for anyone trying to use this many SPI devices with an Arduino and have come up with nothing: my SPI code is fairly basic, so I'm not sure what could be going wrong.
I'm not using the built in SS pins because I have so many devices. Doing SS/CS manually with digital pins and an encoder seemed like the way to go.
Any advice? Thanks for any help!
#include <SPI.h>
const byte PROXIMITY_MSB = 0x22; //most significant byte
const byte PROXIMITY_LSB = 0x21; //least signficnat byte
const byte READ = 0b10000000; // read command
const byte WRITE = 0b01111111; // write command
const int CS0 = 42;
const int CS1 = 43;
const int CS2 = 44;
const int CS3 = 45;
void setup() {
Serial.begin(9600);
SPI.begin();
SPI.setClockDivider(255);
SPI.setBitOrder(MSBFIRST);
// SPI.setDataMode(SPI_MODE0);
pinMode(CS0, OUTPUT);
pinMode(CS1, OUTPUT);
pinMode(CS2, OUTPUT);
pinMode(CS3, OUTPUT);
delay(100);
}
void chipSelect(int chip) {
for (int i = 0; i <4 ; i++) {
if (bitRead(chip, i)==1) {
digitalWrite(45-i, HIGH);
}
else {
digitalWrite(45-i, LOW);
}
}
}
void loop() {
//iterate through 10 LDCs
//for(int i = 0; i < 10; i++){
//choose LDC 8 for now
int prox_msb = readRegister(PROXIMITY_MSB, 8);
Serial.println(prox_msb);
delay(100);
//data processing code omitted - it's commented out right now anyway
}
}
//Read a register
unsigned int readRegister(byte thisRegister, int device ) {
byte result = 0; // result to return
byte toSend = READ | thisRegister ;
Serial.print(toSend, BIN);
Serial.print(" ");
//select the device:
chipSelect(device);
// send the device the register
SPI.transfer(toSend);
// send a value of 0 to read the first byte returned
result = SPI.transfer(0);
// set chip select to 15 to de-select:
chipSelect(15);
return(result);
}
You try to be smart in the ChipSelect function, but please don't do that. Aim for being straightforward.
Activate and deactivate the chip select every time you use a device. You have to make them all inactive during startup.
unsigned int readRegister(byte thisRegister, int device ) {
...
//select the device:
digitalWrite (pinCS[device], LOW);
...
// de-select chip select:
chipSelect (pinCS[device], HIGH);
...
}
is that I have 10 devices - controlling one pin isn't enough to select one of them because of my decoder (if I only had four devices, I'd use pins directly). I have to change all four bits in order to specify a different device - the decoder takes in the 4 bit input and spits out which of the 10 devices has its CS pin activated. I'd eliminate the decoder, but my PCB is already designed and built. Is there a better way to handle CS given that I'm using a decoder?
Thanks for the advice about initializing all of the CS lines to inactive - I didn't think to do that.
It is hard to answer your question without knowing the hardware.
You have a 4 to 16 decoder ? connected to CS0 to CS3 ?
Okay, now I understand the '15' to disable and the bitRead.
Does your decoder have 16 inverted outputs ? The chip select is active low.
And this decoder does not have a clock or latch ? That is not a problem, the outputs can be temporary low during selecting the proper chip-select I hope.
I still would like to use a function that enables and disables a chipselect. The 'chipSelect' function should translate it for your hardware.
// function chipSelect
// chip: 0 to 15 (only 0 to 9 is actually used)
// select: true for active, false for deactivate
void chipSelect(int chip, boolean select)
{
if (select == false)
{
// deselect it by selecting decoder output 15
for (int i=0; i<4; i++)
chipSelect (pinCS[i], HIGH);
}
else
{
for (int i = 0; i <4 ; i++)
{
// this section depends on the hardware decoder, so I'm not sure.
if (bitRead(chip, i)==1)
chipSelect (pinCS[i], HIGH);
else
digitalWrite (pinCS[i], LOW);
}
}
}
Can you remove the "setClockDivider" ?
What did you connect to TBCLK ?
I don't know the SPI.setDataMode, I can look into that once more if you want to.
Thanks for the function! I don't understand why there needs to be a boolean input - it makes the code easier to read/understand, but doesn't seem to change the functionality. Chip Select seems like it's working correctly from what I've seen on an oscilloscope- it's MOSI and MISO that are both transmitting on the same Arduino pin.
The 4 to 16 decoder has 16 inverted outputs. The schematic of the board is attached.
The person that asked on the TI forums was asking if SPI communication is possible: the LDC1000 seems to use standard SPI (according to the people I've asked at my school), so I'm pretty sure the problem is on the Arduino's end.
I can remove the SetClockDivider - I used it to slow down the SPI so I could see the signals on an oscilloscope. I still don't receive any data when SetClockDivider is removed. TBCLK is set using a 8MHz crystal oscillator on the PCB.
I have no idea what's going on - SPI is supposed to be easy
You can keep the SetClockDivider, but I wanted to reduce things as much a possible.
Sorry for staring too long at your sketch too long
I think the sketch is not the problem.
And I assume you see the TBCLK actually being 8MHz ?
And the logic chips all work at 3.3V ? Normally they won't do that.
You 74LVC125 is for 3.3V, but I as far as I can tell, not the SN74LS42D.
How do use the SPI interface on the Due ? With the 6-pin header ?
The MISO on the Due is the input, connected to the SDO on the LDC1000 which is output. That's good.
You want to be able to invert that signal with a pin ? That makes it more complex.
The transmitted data by the Due is on the MOSI line, that's good.
But your MISO data is also on the MOSI line ?
I can't find anything in the schematic or in your posts that could explain it.
At this moment I still have too many questions and you have too much complexity.
Perhaps you should try a minimal setup. Just one LDC1000, directly connected to the Due.
I'm thinking in the direction : shortcut between wires, logic chip not powered, wrong SPI pins, bad connector. Things like that.
Kilendra,
Did you ever get this figured out? I'm looking to use SPI to communicate with multiple arduinos but was not considering using a decoder. Any additional information you have would be very helpful.
Thanks,
Scott
Nothing is coming through on the MISO line, no matter where I probe on the LDCs or which one I select.
Have you tried a test setup with just one LCD and no multiplexed SS?
If that works add the multiplexing to the test setup with the single know-good LCD in place.
Once that works, add the rest of the LCDs.