SPI with Digital Potentiometer

Hi !

I'm new in SPI and DigiPot and not very experimented with Arduino (Nano in my case), so I may need some help...

Here is my situation :
I use many digipot AD5235 (Analog Device) in Daisy-Chain. To learn how to use it, I want to change the resistor of only the 1st potentiometer of this chain. But after many research and programming, I can't change anything...

Here is the schema of my assembly : (for the DigiPots, pins WP and PR are connected to 3.3V)

And this is my code :

#include <SPI.h>

const int slaveSelectPin = 10;    // CLK = D13      SDI = D11
int valuePotA = 0x10;
int valuePotB = 0x10;
//const byte NVM_A = B00110000; // Save value in EEMEM digipot A
//const byte NVM_B = B00110001; // Save value in EEMEM digipot B
const byte write_potA = B10110000; // Write sent value to digipot A (Not in EEMEM)
const byte write_potB = B10110001; // Write sent value to digipot B (Not in EEMEM)

void setup() {
  pinMode(slaveSelectPin, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST); 
  Serial.begin(9600);
  Serial.println("com initialised");
}

void loop() {  
 
  ////// SPI ///////
  
  //digitalWrite(slaveSelectPin,LOW);
  //digitalPotWrite(NVM_A, valuePotA[i]);
  //delay(100);
  //digitalPotWrite(NVM_B, valuePotB[i]);
  //delay(100);
  digitalPotWrite(write_potA, valuePotA);
  delay(100);
  digitalPotWrite(write_potB, valuePotB);
  delay(100);
  //digitalWrite(slaveSelectPin, HIGH);
  
  Serial.println("Done"); 
  delay(1000);
}


////// Change resistor's value in Digipot //////
void digitalPotWrite(byte address, int value)
{
  digitalWrite(slaveSelectPin,LOW);
  //delay(100);

  SPI.transfer(address); // 8 bits // Command Byte 0 
  SPI.transfer(B00000000);         // Data Byte 1
  SPI.transfer(value);  // 8 bits  // Data Byte 0
 // delay(100);

  digitalWrite(slaveSelectPin, HIGH);
}

I also checked the MOSI & CLK signals and they don't seem very nice :

So, if you had any advice, view or anything, I'm listening !

before trying to daisy chain, does using one works? are WP and PR tied to Vcc?

this post here gives an example code... not tested personally as don't have the chip.

https://forum.arduino.cc/index.php?topic=356088.0

hope that helps.

sherzaad:
... this post here gives an example code... not tested personally as don't have the chip.

Digital potentiometer AD5235 - SPI - Working example - Programming Questions - Arduino Forum

hope that helps.

re-wrote the code make use of the IDE functions and SPI library (compiles but not tested)

Good Luck!

/*
  In order for this to work proper don't forget to add 2.2kOhm pull up resistors on READY and SDO pins

  Connections

  CLK - CLK
  SDI - MOSI
  SDO - MISO
  CS -  Pin 10
  RDY - Pin 9

  for demo purposes, have the AD5235 A1 and A2 tied to Vcc, B1 and B2 to GND
  with this arrangement, you should be able to monitor W1 and W2 voltage output as the pot resistance changes

*/

//EEMEM No.--Address--EEMEM Content for …
//1     0000    RDAC1
//2     0001    RDAC2
//3     0010    USER1
//4     0011    USER2
//…     …       …
//15    1110    USER13
//16    1111    RAB1 tolerance

//Control Registers
#define CMD__NOTHING  B00000000 //0  - Do nothing
#define CMD_MEM2RDAC  B00010000 //1  - Restore EEMEM (A0) contents to RDAC (A0) register. See Table 16.
#define CMD_RDAC2MEM  B00100000 //2  - Store wiper setting. Store RDAC (A0) setting to EEMEM (A0). See Table 15. - Use a delay of 50ms!!!
#define CMD_USER2MEM  B00110000 //3  - Store contents of Serial Register Data Byte 0 and Serial Register Data Bytes 1 (total 16 bits) to EEMEM (ADDR). See Table 18.- Use a delay of 50ms!!!
#define CMD_DECRE6DB  B01000000 //4  - Decrement by 6 dB. Right-shift contents of RDAC (A0) register, stop at all 0s.
#define CMD_DEALL6DB  B01010000 //5  - Decrement all by 6 dB. Right-shift contents of all RDAC registers, stop at all 0s.
#define CMD_DECR1STP  B01100000 //6  - Decrement contents of RDAC (A0) by 1, stop at all 0s.
#define CMD_DECA1STP  B01110000 //7  - Decrement contents of all RDAC registers by 1, stop at all 0s.
#define CMD_ALL2RDAC  B10000000 //8  - Reset. Refresh all RDACs with their corresponding EEMEM previously stored values. - Use a delay of 30us!!!
#define CMD_GETEMEM   B10010000 //9  - Read contents of EEMEM (ADDR) from SDO output in the next frame. See Table 19. - Use a delay of 30us!!!
#define CMD_GET_RDAC  B10100000 //10 - Read RDAC wiper setting from SDO output in the next frame. See Table 20. - Use a delay of 30us!!!
#define CMD_SET_RDAC  B10110000 //11 - Write contents of Serial Register Data Byte 0 and Serial Register Data Byte 1 (total 10 bits) to RDAC (A0). See Table 14.
#define CMD_INCRE6DB  B11000000 //12 - Increment by 6 dB: Left-shift contents of RDAC (A0),stop at all 1s. See Table 17.
#define CMD_INALL6DB  B11010000 //13 - Increment all by 6 dB. Left-shift contents of all RDAC registers, stop at all 1s.
#define CMD_INCR1STP  B11100000 //14 - Increment contents of RDAC (A0) by 1, stop at all 1s. See Table 15.
#define CMD_IALL1STP  B11000000 //15 - Increment contents of all RDAC registers by 1, stop at all 1s.

#define CS 10
#define RDY 9

#include"SPI.h"

uint8_t myVal = 0;

void setup()
{
  Serial.begin(9600);
  //Setup SPI and start it
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);

  pinMode(RDY, INPUT_PULLUP); //that way you don't need use a external pullup resistor on this pin

  SPI.begin();

  delay(15);
  setWiper(0, 999);
  setWiper(1, 333);
  Serial.print("W1 Value : "); Serial.println(getWiper(0));
  Serial.print("W2 Value : "); Serial.println(getWiper(1));
  stepUpOne(0);
  stepUpOne(1);
  Serial.print("Increase W0 with 1 : "); Serial.println(getWiper(0));
  Serial.print("Increase W1 with 1 : "); Serial.println(getWiper(1));
  stepUpOne(0);
  repeatCMD();
  stepUpOne(1);
  repeatCMD();
  Serial.print("W1 after repeat : "); Serial.println(getWiper(0));
  Serial.print("W2 after repeat : "); Serial.println(getWiper(1));
  stepDownSix(0);
  stepDownSix(1);
  Serial.print("Decrease W0 with 6dB : "); Serial.println(getWiper(0));
  Serial.print("Decrease W1 with 6dB : "); Serial.println(getWiper(1));
  stepDownSix(0);
  repeatCMD();
  stepDownSix(1);
  repeatCMD();
  Serial.print("W1 after repeat -6dB: "); Serial.println(getWiper(0));
  Serial.print("W2 after repeat -6dB: "); Serial.println(getWiper(1));

  SPI.end();

}

void loop()
{
}

void setWiper(uint8_t w, uint16_t value)
{
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD_SET_RDAC + w);
  myVal = SPI.transfer(value >> 8);
  myVal = SPI.transfer(value & 0xFF);
  digitalWrite(CS, HIGH);
}

uint16_t getWiper(uint8_t w)
{
  uint16_t ret;
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD_GET_RDAC + w);
  myVal = SPI.transfer(CMD__NOTHING);
  myVal = SPI.transfer(CMD__NOTHING);
  digitalWrite(CS, HIGH);
  delayMicroseconds(30);
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD__NOTHING); //Discard first byte
  ret = (SPI.transfer(CMD__NOTHING) << 8);
  ret += SPI.transfer(CMD__NOTHING);
  digitalWrite(CS, HIGH);
  return ret;
}

void stepUpOne(uint8_t w)
{
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD_INCR1STP + w);
  myVal = SPI.transfer(CMD__NOTHING);
  myVal = SPI.transfer(CMD__NOTHING);
  digitalWrite(CS, HIGH);
}

void stepDownSix(uint8_t w)
{
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD_DECRE6DB + w);
  myVal = SPI.transfer(CMD__NOTHING);
  myVal = SPI.transfer(CMD__NOTHING);
  digitalWrite(CS, HIGH);
}

void repeatCMD()//See page 21 in manual Another subtle feature of the AD5235 is that a subsequent CS strobe, without clock and data, repeats a previous command
{
  digitalWrite(CS, LOW);
  digitalWrite(CS, HIGH);
}

Yes, I'm trying to use only one for the moment, but doesn't work.
And yes, WP & PR are connected to vcc.

Thank you for the code ! I tried it and the shape of the signals seems to be better ! But still, nothing change in the digipot...

Axli:
Thank you for the code ! I tried it and the shape of the signals seems to be better ! But still, nothing change in the digipot...

just wanna confirm... how do you checking that the digipot values are changing or NOT?

Well, you're right to ask, as I said, I'm new on it and I may not check the right way !
I check with the SDO and with an ohmmeter between pins A et W (1 or 2, according to which potentiometer I want to measure).

Axli:
Well, you're right to ask, as I said, I'm new on it and I may not check the right way !
I check with the SDO and with an ohmmeter between pins A et W (1 or 2, according to which potentiometer I want to measure).

according to the data sheet I'm looking at A and W are on pins 6/7 or 10/11! :o

Capture1.PNG

Capture1.PNG

I'm talking about Pot1 or Pot2 :smiley:
So if I want to test Pot one I use pin 6/7 and pin 10/11 for Pot2.

Axli:
I'm talking about Pot1 or Pot2 :smiley:
So if I want to test Pot one I use pin 6/7 and pin 10/11 for Pot2.

hmmm.... not sure what could be wrong other than wiring then... could you post the schematic of how you wired up your circuit?

Here is the schematic.

CON8 (J7) come from the Arduino NANO, connected to the pins from the code.

the connections look good.... but that is the connection for your daisy chain circuit! am I right to assume that you just disconnected the SDO to the other chips for the single chip testing?

ok. maybe time to go back to the drawing board. if you look at the datasheet (https://www.analog.com/media/en/technical-documentation/data-sheets/AD5235.pdf) have a try of this example:

Capture.PNG

in code it would be something like this (not tested):

/*
   AD5235_NANO SPI connections:
     CLK - CLK
     SDI - MOSI
     SDO - MISO
     SS -  Pin 10
*/

#include <SPI.h>

void setup() {

  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3)); //CLk: 4MHz, MSB first, SPI_MODE3 (CPHA:1, CPOL:1)

  pinMode(SS, OUTPUT); //SS is pin 10
  digitalWrite(SS, HIGH);  // ensure SS stays high for now

  delay(1000); //arbirtrary delay

  //reset all wipers
  digitalWrite(SS, LOW);

  SPI.transfer(0x80); //reset command byte
  SPI.transfer(0x00); //dummy data
  SPI.transfer(0x00); //dummy data

  digitalWrite(SS, HIGH);

  delay(1000); //arbirtrary delay

  uint32_t cmd;

  //update wiper1 value (channel 0):
  cmd = 0x00B00100;

  digitalWrite(SS, LOW);

  SPI.transfer((uint8_t)(cmd >> 16)); //command byte
  SPI.transfer((uint8_t)(cmd >> 8));  //upper data byte
  SPI.transfer((uint8_t) cmd);        //lower data byte

  digitalWrite(SS, HIGH);

  delay(1000); //arbirtrary delay

  //update wiper2 value (channel 1):
  cmd = 0x00B10200;

  digitalWrite(SS, LOW);

  SPI.transfer((uint8_t)(cmd >> 16)); //command byte
  SPI.transfer((uint8_t)(cmd >> 8));  //upper data byte
  SPI.transfer((uint8_t) cmd);        //lower data byte

  digitalWrite(SS, HIGH);

}

void loop() {
  // do nothing

}

do the wiper values change as described in 'Action'?

Capture.PNG

sherzaad:
the connections look good.... but that is the connection for your daisy chain circuit! am I right to assume that you just disconnected the SDO to the other chips for the single chip testing?

Yes.

sherzaad:
ok. maybe time to go back to the drawing board. if you look at the datasheet (https://www.analog.com/media/en/technical-documentation/data-sheets/AD5235.pdf) have a try of this example:

I tried, and still no change. Btw, Pot1 is at 1/2 scale & Pot2 is at 1/4 scale (which is the opposite of what the code suggests, and even if I change the code, nothing change), so I suppose that it's the default value.

I'm starting to wonder if I didn't make a mishandling which destroyed the digipots :s

Axli:
I'm starting to wonder if I didn't make a mishandling which destroyed the digipots :s

I'm beginning to suspect that too. If you got spares, maybe try them... :confused:

Yes, I ordered them, I will try with just one and nothing else in the circuit than an AD5235 and the Arduino and I will see :slight_smile:
Thank you ! I'll send a message after tested it, but don't know when I will receive them ^^'

Hello !

I received my new AD5235 ! So I tested them and it works pretty well with the help of the code you gave me (in the quote below) sherzaad.

It seems the problem I had come from the fact the board were the previous one were installed is supplied in 3.3V.
In the test I did with the new one, I can change the value of the wipers only when supplied with 5V... If it's 3.3V, they just start and take the default value, but can't take the SPI data's.

sherzaad:

/*

In order for this to work proper don't forget to add 2.2kOhm pull up resistors on READY and SDO pins

Connections

CLK - CLK
  SDI - MOSI
  SDO - MISO
  CS -  Pin 10
  RDY - Pin 9

for demo purposes, have the AD5235 A1 and A2 tied to Vcc, B1 and B2 to GND
  with this arrangement, you should be able to monitor W1 and W2 voltage output as the pot resistance changes

*/

//EEMEM No.--Address--EEMEM Content for …
//1    0000    RDAC1
//2    0001    RDAC2
//3    0010    USER1
//4    0011    USER2
//…    …      …
//15    1110    USER13
//16    1111    RAB1 tolerance

//Control Registers
#define CMD__NOTHING  B00000000 //0  - Do nothing
#define CMD_MEM2RDAC  B00010000 //1  - Restore EEMEM (A0) contents to RDAC (A0) register. See Table 16.
#define CMD_RDAC2MEM  B00100000 //2  - Store wiper setting. Store RDAC (A0) setting to EEMEM (A0). See Table 15. - Use a delay of 50ms!!!
#define CMD_USER2MEM  B00110000 //3  - Store contents of Serial Register Data Byte 0 and Serial Register Data Bytes 1 (total 16 bits) to EEMEM (ADDR). See Table 18.- Use a delay of 50ms!!!
#define CMD_DECRE6DB  B01000000 //4  - Decrement by 6 dB. Right-shift contents of RDAC (A0) register, stop at all 0s.
#define CMD_DEALL6DB  B01010000 //5  - Decrement all by 6 dB. Right-shift contents of all RDAC registers, stop at all 0s.
#define CMD_DECR1STP  B01100000 //6  - Decrement contents of RDAC (A0) by 1, stop at all 0s.
#define CMD_DECA1STP  B01110000 //7  - Decrement contents of all RDAC registers by 1, stop at all 0s.
#define CMD_ALL2RDAC  B10000000 //8  - Reset. Refresh all RDACs with their corresponding EEMEM previously stored values. - Use a delay of 30us!!!
#define CMD_GETEMEM  B10010000 //9  - Read contents of EEMEM (ADDR) from SDO output in the next frame. See Table 19. - Use a delay of 30us!!!
#define CMD_GET_RDAC  B10100000 //10 - Read RDAC wiper setting from SDO output in the next frame. See Table 20. - Use a delay of 30us!!!
#define CMD_SET_RDAC  B10110000 //11 - Write contents of Serial Register Data Byte 0 and Serial Register Data Byte 1 (total 10 bits) to RDAC (A0). See Table 14.
#define CMD_INCRE6DB  B11000000 //12 - Increment by 6 dB: Left-shift contents of RDAC (A0),stop at all 1s. See Table 17.
#define CMD_INALL6DB  B11010000 //13 - Increment all by 6 dB. Left-shift contents of all RDAC registers, stop at all 1s.
#define CMD_INCR1STP  B11100000 //14 - Increment contents of RDAC (A0) by 1, stop at all 1s. See Table 15.
#define CMD_IALL1STP  B11000000 //15 - Increment contents of all RDAC registers by 1, stop at all 1s.

#define CS 10
#define RDY 9

#include"SPI.h"

uint8_t myVal = 0;

void setup()
{
  Serial.begin(9600);
  //Setup SPI and start it
  pinMode(CS, OUTPUT);
  digitalWrite(CS, HIGH);

pinMode(RDY, INPUT_PULLUP); //that way you don't need use a external pullup resistor on this pin

SPI.begin();

delay(15);
  setWiper(0, 999);
  setWiper(1, 333);
  Serial.print("W1 Value : "); Serial.println(getWiper(0));
  Serial.print("W2 Value : "); Serial.println(getWiper(1));
  stepUpOne(0);
  stepUpOne(1);
  Serial.print("Increase W0 with 1 : "); Serial.println(getWiper(0));
  Serial.print("Increase W1 with 1 : "); Serial.println(getWiper(1));
  stepUpOne(0);
  repeatCMD();
  stepUpOne(1);
  repeatCMD();
  Serial.print("W1 after repeat : "); Serial.println(getWiper(0));
  Serial.print("W2 after repeat : "); Serial.println(getWiper(1));
  stepDownSix(0);
  stepDownSix(1);
  Serial.print("Decrease W0 with 6dB : "); Serial.println(getWiper(0));
  Serial.print("Decrease W1 with 6dB : "); Serial.println(getWiper(1));
  stepDownSix(0);
  repeatCMD();
  stepDownSix(1);
  repeatCMD();
  Serial.print("W1 after repeat -6dB: "); Serial.println(getWiper(0));
  Serial.print("W2 after repeat -6dB: "); Serial.println(getWiper(1));

SPI.end();

}

void loop()
{
}

void setWiper(uint8_t w, uint16_t value)
{
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD_SET_RDAC + w);
  myVal = SPI.transfer(value >> 8);
  myVal = SPI.transfer(value & 0xFF);
  digitalWrite(CS, HIGH);
}

uint16_t getWiper(uint8_t w)
{
  uint16_t ret;
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD_GET_RDAC + w);
  myVal = SPI.transfer(CMD__NOTHING);
  myVal = SPI.transfer(CMD__NOTHING);
  digitalWrite(CS, HIGH);
  delayMicroseconds(30);
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD__NOTHING); //Discard first byte
  ret = (SPI.transfer(CMD__NOTHING) << 8);
  ret += SPI.transfer(CMD__NOTHING);
  digitalWrite(CS, HIGH);
  return ret;
}

void stepUpOne(uint8_t w)
{
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD_INCR1STP + w);
  myVal = SPI.transfer(CMD__NOTHING);
  myVal = SPI.transfer(CMD__NOTHING);
  digitalWrite(CS, HIGH);
}

void stepDownSix(uint8_t w)
{
  digitalWrite(CS, LOW);
  myVal = SPI.transfer(CMD_DECRE6DB + w);
  myVal = SPI.transfer(CMD__NOTHING);
  myVal = SPI.transfer(CMD__NOTHING);
  digitalWrite(CS, HIGH);
}

void repeatCMD()//See page 21 in manual Another subtle feature of the AD5235 is that a subsequent CS strobe, without clock and data, repeats a previous command
{
  digitalWrite(CS, LOW);
  digitalWrite(CS, HIGH);
}