I want to control a digital potentiometer (MCP4131-103) from my photon, but while I’ve found a few libraries (this one looks quite promising), I’m not sure how to wire it up and what pins to use.
I’m also planning to use an I2C display at the same time - is it possible to run both together?
I2C is very easy to wire - connect the SDA/SCL/GND pins of the two devices, with a pull-up (10K) resistor to 3V3 on both SDA/SCL and you are good to go.
I2C uses device addresses, so as long as the display and digital pot do not share an address, you should be good to go.
The MCP4131 uses SPI and not I2C. You will need to connect one of the Photon SPI ports to the device. Are you using a breakout board for the MCP4131 and if so, which one?
You are using 10 as CS but have it wired to A2 (which would be 12) - we usually advise to use the pin labels instead of anonymous pin numbers for exactly such reasons.
Can you measure the voltage at P0W?
You could even have a jumper wire to A0 and analogRead(A0) to see whether there is any change at all (I’d remove the LED for that).
Might I enquire why you are not using the library to drive this IC via SPI?
Not sure which version of the MCP4131 you have - some are 7 bit and some 8 bit control of the potentiometer. That means for 7bit the maximum value you can send it is 7Fh.
I would take a look at this library for Arduino and you will see what you need to be doing in trying to drive it.
For example; CS is active low so when you use the chip you digitalWrite(A2, LOW); to enable the MCP4131 on the SPI bus and after you have written you set digitalWrite(A2, HIGH); This also means setup() should contain digitalWrite(A2, HIGH); to disable the chip not LOW as you have. Pin A2 is the default CS pin for SPI bus.
Also, I would be using SPI.beginTransaction(); where you set the SPI bus speed and other settings and SPI.endTransaction();
Reading A0 ranges from 2044-2047 - not too sure if that’s a significant change or not.
Don’t have my multimeter on me at the mo, but hooking up the LED to P0A has the LED shining bright, and P0B doesn’t light it up at all, which is what I’d expect. If it’s helpful, I can grab my multimeter some time tomorrow and get some more accurate figures
Had a few issues porting the library to Spark, and the guide I followed seemed to fit the use case perfectly. I’ve added in the begin and end transaction, and logic to manage enabling/disabling the chip, but no luck - cheers for the feedback though
The datasheet says the 4131 is 7-bit (129 steps) - I’ve got the 10k version
That indicates that the pot is set - and stuck - at the center position.
However, it's no surprise that the LED does not come on for half the range (and possibly more) as you need at least 1.2V for a red LED to even start switching through and you are dividing the 3.3V supply via the internal voltage divider plus the external current limiter.
BTW, the chip only accepts up to 10MHz SPI speed, try setting a lower speed.
Like everyone else and being required to stay in I thought I would have a go at porting to Particle this device driver. I don’t have a MCP4131 so can’t test this code.
// Acknowledgement to original author Written by: Derek Duncan 04/03/2018 MIT licence
// Modified for Particle by Armor/W Steen 29/03/20
//
#include "MCP4131.h"
// constructor and initialiser for MCP4131 object
MCP4131::MCP4131(uint16_t slavePin)
{
slaveSelectPin = slavePin;
}
// Begin the SPI comms and initalise the CS pin to disabled
void MCP4131::begin()
{
pinMode(slaveSelectPin, OUTPUT);
disableChip();
SPI.begin();
}
// Read the current value of the potentiometer (0-127)
byte MCP4131::readWiper()
{
return sendCommand(ADDRESS_WIPER0, COMMAND_READ, 255);
}
// Send potentiometer setting (0-127)
void MCP4131::writeWiper(byte wiperValue)
{
sendCommand(ADDRESS_WIPER0, COMMAND_WRITE, wiperValue);
}
// sendCommand address and command with no return
void MCP4131::sendCommand(byte address, char command)
{
SPI.beginTransaction(__SPISettings(250000, MSBFIRST, SPI_MODE0)); // Adjust SPI settings to fit MCP4131
enableChip(); // take the CS/SS pin low to select the chip
byte msb = (address << 4) | ((command << 2) | COMMAND_MASK);
SPI.transfer(msb);
disableChip(); // take the CS/SS pin high to de-select the chip
SPI.endTransaction(); // Stop using the SPI bus to allow other chips to use SPI
}
// Overloaded sendCommand address, command and data returns byte
byte MCP4131::sendCommand(byte address, char command, byte data)
{
SPI.beginTransaction(__SPISettings(250000, MSBFIRST, SPI_MODE0)); // Adjust SPI settings to fit MCP4131
enableChip(); // take the CS/SS pin low to select the chip
byte msb = (address << 4) | ((command << 2) | COMMAND_MASK);
SPI.transfer(msb);
byte result = SPI.transfer(data);
disableChip(); // take the CS/SS pin high to de-select the chip
SPI.endTransaction(); // Stop using the SPI bus to allow other chips to use SPI
return result; // Return byte result from 2nd transfer
}
// -1 to Wiper value down to minimum 0
void MCP4131::decrementWiper()
{
sendCommand(ADDRESS_WIPER0, COMMAND_DECREMENT);
}
// +1 to Wiper value up to maximum 127
void MCP4131::incrementWiper()
{
sendCommand(ADDRESS_WIPER0, COMMAND_INCREMENT);
}
// Set to LOW to enable
void MCP4131::enableChip()
{
pinResetFast(slaveSelectPin);
}
// Set to HIGH to disable
void MCP4131::disableChip()
{
pinSetFast(slaveSelectPin);
}
Example sketch to test
/*
* Project MCP4131-test
* Description: Example to Use MCP4131 device driver
* Author: W Steen/Armor
* Date: 29/03/20
*/
#include "MCP4131.h"
SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);
MCP4131 pot(A2);
// setup() runs once, when the device is first turned on.
void setup()
{
pot.begin();
}
// loop() runs over and over again, as quickly as it can execute.
void loop()
{
for (byte i = 0; i < 127; i++)
{
pot.writeWiper(i);
delay(100);
}
delay(1000);
for (byte i = 0; i < 127; i++)
{
pot.decrementWiper();
delay(100);
}
delay(1000);
}
Thanks so much for putting this together - with nothing else to do I’ve also been working on this quite solidly getting nowhere - unfortunately, I tried it out with the chip, but still no joy.
I’ve gone ahead and removed the LED, and instead just hooked it up to A0 and read that, values are still stuck on 2046ish. I’ve switched out all the jumper cables but that didn’t help either.
I’ve gone ahead and ordered a couple more ICs, just in case I’ve somehow managed to fry the current one.
Here’s a couple of pics of the setup IRL, I’ve double checked it against the datasheet but as far as I can tell it’s all wired up right - may have made a glaring mistake, though
From the driver I supplied earlier - I think that the SPI bus speed was set much lower - 250KHz. Have you tried that? __SPISettings(250000, MSBFIRST, SPI_MODE0)
Also, variable a is an integer, doesn’t need double precision.
I have just done a dig in the parts tray and found a MCP4162-103 - an 8bit rheostat version of the one you have. I will have a go this evening using the library and see if I can get it to work.
For testing I'd take things a bit slower (e.g. 500ms instead of 10ms) and also use Serial.println(a) to see the variance of the reading - with a Particle.variable() you are not very likely to catch more than 2 of your 128 readings
Just for nit-picking, I'd not use the blue jumper wire for 3v3 to P0A and orange as GND to P0B.
In one distracted moment one might just go with the colours without double checking and off goes the magic smoke