0

I'm making a midi controller with the Arduino uno. It contains approximately 50 analog inputs with potentiometers. I have enough MCP3008 adc's here but I have no idea how I connect 2 or more adc's to the Arduino so that I can read 50. How do you stack adc's?

  • 4
    Also asked at: forum.arduino.cc/index.php?topic=569402 If you're going to do that then please be considerate enough to add links to the other places you cross posted. This will let us avoid wasting time due to duplicate effort and also help others who have the same questions and find your post to discover all the relevant information. – per1234 Sep 19 '18 at 22:47
  • 2
    why would you use potentiometers? ..... digital encoders would make so much more sense – jsotola Sep 20 '18 at 0:58
1

These ADC's use the SPI protocol. Luckily the Arduino has one onboard.

With each ADC you get 8 channels (thus inputs). Since you need more than one SPI device (ADC in your case).

With SPI you can chain multiple SPI devices to your SPI port of the Arduino. To select which is active you use the Chip/Slave select signal. This is a separate GPIO you can define yourself. Read more about SPI to read details.

For 50 inputs you need 50 / 8, rounded up is 7 ADCs. This means also 7 CS pins. Thus in total you need 3 (for SPI) + 7 = 10 pins. I hope you have that many left.

About 'stacking', just put the ADC's on a breadboard and wire them according to the SPI protocol.

See also Arduino Reference SPI

  • 1
    Note that with a large number of devices on a SPI bus like this you may need to reduce the communication speed or include a line driver to overcome the increased capacitance on the bus. – Majenko Sep 20 '18 at 0:40
  • 1
    Reduced speed will be built in due to the max clock speed of 3.6 MHz with the MCP3008 - thus SPI clock speed of 2 MHz with a 16 MHz Arduino. – CrossRoads Sep 20 '18 at 15:03
0

With SPI the SCK, MISO, MOSI are connected in parallel to all devices. The device with the active low Chip Select pin is the one that receives a command and then sends data, the others ignore what is happening. You can also load data into a shift register to create the chip selects, thus only 4 pins are needed: SCK (13), MISO (12), MOSI (11), to all the devices, and use D10, the SS pin, as the latch pin (SRCK) into a 74HC595 for the 7 chip selects out to the MCP3008s.

The code to loop can be pretty simple.

for (pin = 0; pin <7; pin = pin +1){
  digitalWrite (csPin[pin], LOW); // select a device
  SPI.transfer(startByte); // send out start byte
  upperBits[pin + address] = SPI.transfer(addressByte [address]); // send out address, read in D9, D8
  lowerBits[pin + address] = SPI.transfer(0);  // send out don't care read in D7-D0
  digitalWrite (csPin [pin), HIGH); // deselect a device

  digitalWrite (csPin[pin], LOW); // select a device
  SPI.transfer(startByte); // send out start byte
  upperBits[pin + address+1] = SPI.transfer(addressByte [address+1]); // send out address, read in D9, D8
  lowerBits[pin + address+1] = SPI.transfer(0);  // send out don't care read in D7-D0
  digitalWrite (csPin [pin), HIGH); // deselect a device

  digitalWrite (csPin[pin], LOW); // select a device
  SPI.transfer(startByte); // send out start byte
  upperBits[pin + address+2] = SPI.transfer(addressByte [address+2]); // send out address, read in D9, D8
  lowerBits[pin + address+2] = SPI.transfer(0);  // send out don't care read in D7-D0
  digitalWrite (csPin [pin), HIGH); // deselect a device

  digitalWrite (csPin[pin], LOW); // select a device
  SPI.transfer(startByte); // send out start byte
  upperBits[pin + address+3] = SPI.transfer(addressByte [address+3]); // send out address, read in D9, D8
  lowerBits[pin + address+3] = SPI.transfer(0);  // send out don't care read in D7-D0
  digitalWrite (csPin [pin), HIGH); // deselect a device

  digitalWrite (csPin[pin], LOW); // select a device
  SPI.transfer(startByte); // send out start byte
  upperBits[pin + address+4] = SPI.transfer(addressByte [address+4]); // send out address, read in D9, D8
  lowerBits[pin + address+4] = SPI.transfer(0);  // send out don't care read in D7-D0
  digitalWrite (csPin [pin), HIGH); // deselect a device

  digitalWrite (csPin[pin], LOW); // select a device
  SPI.transfer(startByte); // send out start byte
  upperBits[pin + address+5] = SPI.transfer(addressByte [address+5]); // send out address, read in D9, D8
  lowerBits[pin + address+5] = SPI.transfer(0);  // send out don't care read in D7-D0
  digitalWrite (csPin [pin), HIGH); // deselect a device

  digitalWrite (csPin[pin], LOW); // select a device
  SPI.transfer(startByte); // send out start byte
  upperBits[pin + address+6] = SPI.transfer(addressByte [address+6]); // send out address, read in D9, D8
  lowerBits[pin + address+6] = SPI.transfer(0);  // send out don't care read in D7-D0
  digitalWrite (csPin [pin), HIGH); // deselect a device

  digitalWrite (csPin[pin], LOW); // select a device
  SPI.transfer(startByte); // send out start byte
  upperBits[pin + address+7] = SPI.transfer(addressByte [address+7]); // send out address, read in D9, D8
  lowerBits[pin + address+7] = SPI.transfer(0);  // send out don't care read in D7-D0
  digitalWrite (csPin [pin), HIGH); // deselect a device

}

The end result are two 56 byte arrays, upperBits[] and lowerBits[], combine a byte from each for a reading per channel.

I do have a lot of duplicate code there that could likely be reduced to a loop within a loop to remove the redundancy.

'address' could come from an array also, as the data needs to be 0b10000000, 0b10010000, 0b10100000, 0b10110000, 0b11000000, 0b11010000, 0b11100000, 0b11110000

or start with address = 0x80 and add 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70

That code has to integrate to drive the shift register, which I forgot about, so instead of

digitalWrite (csPin[pin], LOW);
and
digitalWrite (csPin[pin], HIGH);

you'd have

digitalWrite (shiftRegisterLatch, LOW); // first MCP3008 CS low
SPI.transfer(0b11111110);
digitalWrite (shiftRegisterLatch, HIGH); //first MCP3008 CS low
// read from ADC0 on first MCP3008 using SPI.transfers above
digitalWrite (shiftRegisterLatch, LOW); // first MCP3008 CS high
SPI.transfer(0b11111111);
digitalWrite (shiftRegisterLatch, HIGH); //first MCP3008 CS high

Repeat for channels ADC1 to ADC7

Then go to the next device:

digitalWrite (shiftRegisterLatch, LOW); // 2nd MCP3008 CS low
SPI.transfer(0b11111101);
digitalWrite (shiftRegisterLatch, HIGH); //2nd MCP3008 CS low
// read from ADC0 on second MCP3008 using SPI.transfers above
digitalWrite (shiftRegisterLatch, LOW); // 2nd MCP3008 CS high
SPI.transfer(0b11111111);
digitalWrite (shiftRegisterLatch, HIGH); //2nd MCP3008 CS high

So the data could be in an array as well: 0b11111110, 0b11111101, 0b11111011, 0b11110111, 0b11101111, 0b11011111, 0b10111111, with 0b11111111 to turn off CS

I'd be using direct port manipulation as well instead of digitalWrite() to speed up latching data into the shift register.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.