I a mworking on the Arduino DUE with 2 MCP3208 and I am having some trouble.
Setup: On the SPI bus there are two MCP2308 ADCs and one SD card reader (on a tft shield). The CS pins are controlled by a MCP23017.
The card reader works, so the chip select circuit seems to be correct.
I am reading strange values on the ADCs:
if I connect 5V on ch0, I read about 4096 on ch0 AND ch1.
5V on ch1 -> ~4096 on ch2 AND ch3
5V on ch2 -> ~4096 on ch4 AND ch5
5V on ch3 -> ~4096 on ch6 AND ch7
5V on ch4 to ch7 : nothing
I am using this code:
uint16_t readADC_I(int channel)
{
uint16_t output;
//Channel must be from 0 to 7
//Shift bits to match datasheet for MCP3208
byte channelBits = channel | 0x00;
channelBits = channelBits<<5;
//Select chip by pulling down
MCP23017.digitalWrite(3, LOW); // first MCP2308
MCP23017.digitalWrite(4, HIGH); // second MCP2308
MCP23017.digitalWrite(5, HIGH); // SD card reader
//send start bit and bit to specify single or differential mode (single mode chosen here)
SPI.transfer(B00000110);
//Read in MSB
byte msb = SPI.transfer(channelBits);
//Read in LSB
byte lsb = SPI.transfer(0x00);
MCP23017.digitalWrite(3, HIGH);
//Don't care about the first 4 bits of MSB
msb = msb & B00001111;
//Combine to make 12 bit value
output = msb<<8 | lsb;
return output;
}
Any ideas what could cause this? What should I look closer at?
Seems to me to be software related. Is there a difference between UNO and DUE concerning the SPI bus? I have tried different SPI clock dividers, but it did not work.
Since this function is very important for my application I would appreciate any help.
EDIT: All channels should be in single-ended mode.
First, the code you based your code on is not complying with the datasheet, especially if you are using a Due. The Due has an 84MHz clock speed and uses 3.3v I/O. If that IC is powered with 3.3 volts, the max clock speed is 1MHz. You are trying to run it with a 4MHz clock (default).
You must set the clock divider to 84 for a 1MHz SPI clock on the Due.
I am now running the MCP3208 at 3.3V, it sill doens't work.
What's wrong about reading channel 0 single-ended? I want to read all channels single-ended to measure 8 voltages. I should have mentioned this in my first post.
I recommend getting one 3208 working on channel 0 first. Then add the second unit once you have the first unit working. Have you tried that?
edit: The way you are sending the first byte, you will only read 4 channels. The last 0 in this transfer is the MSB for the channel number. It will always be 0, so only channels 0 to 3 will be read.
SPI.transfer(B00000110);
I would try this with only one ADC using D3 as the slave select.
#include <SPI.h>
void setup() {
// Note I use 115200 baud
Serial.begin(115200);
// set ADC slave select HIGH
pinMode(3,OUTPUT);
digitalWrite(3,HIGH);
SPI.begin();
// set SPI to 1MHz clock on Due
SPI.setClockDivider(84);
}
void loop() {
for(byte i = 0; i < 8; i++) {
int thisADC = checkADC(i);
Serial.print("channel ");
Serial.print(i);
Serial.print(": ");
Serial.println(thisADC);
delay(500);
}
}
int checkADC(byte channel) {
// enable ADC SPI
digitalWrite(3,LOW);
// compute 16 bit value for channel and shift into position
int tInt = (channel + 24) << 6;
// transfer the high byte
SPI.transfer(highByte(tInt));
// transfer the low byte and get high 4 bits
byte hiRes = SPI.transfer(lowByte(tInt));
// get the low 8 bits
byte lowRes = SPI.transfer(0);
// disable ADC SPI
digitalWrite(3,HIGH);
// combine both bytes into an integer
int intResult = (hiRes << 8) | lowRes;
return(intResult);
}
Then use your original code and replace only the part that computes the channel. I checked this and it appears to place the bits correctly for each of the 8 channels. The "+ 24" is adding the start bit and the single-ended bit.
// compute 16 bit value for channel and shift into position
int tInt = (channel + 24) << 6;
// transfer the high byte
SPI.transfer(highByte(tInt));
// transfer the low byte and get high 4 bits
byte hiRes = SPI.transfer(lowByte(tInt));
The result below is exactly what I would expect if you are not computing the channel address correctly. If bit 0 of the first byte is zero, and you are shifting the channel number left 5 bit positions for the second byte instead of the required 6 bit shift left.
I am reading strange values on the ADCs:
if I connect 5V on ch0, I read about 4096 on ch0 AND ch1.
5V on ch1 -> ~4096 on ch2 AND ch3
5V on ch2 -> ~4096 on ch4 AND ch5
5V on ch3 -> ~4096 on ch6 AND ch7
5V on ch4 to ch7 : nothing
Yes! It works fine, thank you so much! Made my day and saved my project
Here's the code that works for me (if anyone else has the same problem):
uint16_t readADC_I(int channel)
{
uint16_t output;
// enable ADC SPI
//Select chip by pulling down CS
MCP23017_II.digitalWrite(3, LOW);
// compute 16 bit value for channel and shift into position
int tInt = (channel + 24) << 6;
// transfer the high byte
SPI.transfer(highByte(tInt));
// transfer the low byte and get high 4 bits
byte hiRes = SPI.transfer(lowByte(tInt));
// get the low 8 bits
byte lowRes = SPI.transfer(0);
// disable ADC SPI
MCP23017_II.digitalWrite(3, HIGH);
hiRes = hiRes & B00001111;
//Combine to make 12 bit value
int intResult = hiRes << 8 | lowRes;
return intResult;
}