[SOLVED] MAX5494 10k Digipot and SPI - Resolution/taps issues

The guy who got me into Arduino once said; "Arduino is super easy". Hmm, right... :confused:

Anyway. I'm struggling with SPI and a MAX5494 dual-ch 10k DigiPot. I'm all set-up correctly hardware-wise, can change the resistance of the digipot, but not getting the 10bit resolution at all. More like 10-12 steps (taps?) most. Can one (preferably an Arduino expert, unlike myself lol) look at the code below and datasheet and let me know if I'm doing this correctly. Not entirely sure if I need to send out 8bits or 24, how to shift this correctly, manufacturer is not helping, yadada, I'm completely stuck. HELP!

First time programming SPI on Arduino for me, all up for learning new tricks. So thanks in advance guys.

MAX5494 Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX5494-MAX5499.pdf

#include <SPI.h>
const int CSpin = 10;

void setup() {
  pinMode(CSpin, OUTPUT);
  SPI.begin();
}

void loop() {
  //DEBUG
  digipot4_writeReg(0x01, 512); //512 should bring me at mid 5.00 Ohms... instead it sends it to higher 6.8
  delay(1000);
}

//*******Having a hard time with this method below*******
void digipot4_writeReg(uint8_t Reg, uint16_t value) {
    uint8_t wReg[ 3 ];
    wReg[0] = Reg;
    wReg[1] = value >> 2;
    wReg[2] = value << 6;
    digitalWrite(CSpin, LOW);
    delay(100);
    SPI.transfer(wReg,3);
    delay(100);
    digitalWrite(CSpin, HIGH);
}

From reading the datasheet, as soon as cs goes low, the unit starts to clock data in. In your code the cs is sent low and then it comes to complete stop for 100mS. Possibly your unit is clocking in data for those 100mS, that's a 10th of a second; a long time in computer terms.

I'd not even use a delay after sending the cs low.

Then the SPI port is written to and cs is held low for another 100mS, during which the unit is trying to clock in data.

I'd eliminate delay till after the cspin has been sent high, if I was to use a delay.

When I split the uint16_t to 2 8 bit uint8_t's I use:

  // split 16 bit into 2 8 bits
  rx[0] = workingValue & 0xFF; // low byte
  workingValue = workingValue >> 8;
  rx[1] = workingValue & 0xFF;

.

from the datasheet:
Capture.PNG

so based on that 10 bit is 1024 levels so for a 10k pot that means just under 10 ohms per bit

so maybe something like this may work for you (untested):

#include <SPI.h>
const uint8_t CSpin = 10;

void setup() {
  SPI.begin();
  pinMode(CSpin, OUTPUT);
}

void loop() {
  for (uint16_t i=0; i<1024; ++i){
 update_digipot(0x01, i); 
 delay(1000);
  }
}


void update_digipot(uint8_t Reg, uint16_t value) {
 union { 
 uint16_t val; 
 uint8_t bytes[2];
 } in;
 
 in.val = value<<6; //as per datasheet
 
    digitalWrite(CSpin, LOW);
 
 //Write Wiper Register.  0x01: wiper1, 0x02: wiper2
    SPI.transfer(reg);
 
 //send upper value byte
 SPI.transfer(byte[1]);
 
 //send lower value byte
 SPI.transfer(byte[0]);
 
    digitalWrite(CSpin, HIGH);
}

hope that helps

Capture.PNG

Also, to write a register you need to 24 bits and a write register command to your device. The device may be expecting the whole transaction, from cs going low, 12mS.

hope that helps

I'm not sure how. Looks a bunch of disjointed code.

You define a struct, and create an instance of it. You set one of three values, and then never use the instance. Instead, you send values from some undefined array.

Care to try again? Perhaps popping to compile button before posting. 8)

@Idahowalker - thanks a bunch, appreciated. I'm looking at your suggestions and will need to figure out what they mean 1st. Might have to give 'Byte Array' code training in tomorrow along w/ 24 coffees instead of 24bits :wink: Wish I'd be strong in c/cpp.. thing is... ah, nevermind lol PS: I've whacked out the delay completely and getting completely different values on the Ohm Meter so you possibly fixed a major impediment the code had. You suggest I give it 12ms delay after the CS goes low?

@sherzaad - thanks as much, very cool. I've tried to give your code a go but got an error I'm not familiar with, would you know what it needs to spark? I like the value ramping loop you provided, I should of thought about that myself.

GTC:
@Idahowalker - thanks a bunch, appreciated.
I've whacked out the delay completely and getting completely different values on the Ohm Meter so you possibly fixed a major impediment the code had. You suggest I give it 12ms delay after the CS goes low?

I am backing away from the need for a delay on sending data to the device.

Fair enough on omitting the delay after LOW and before HIGH.

I'm getting annoyed by trying to learn this, just found the reference!
https://blog.reigndesign.com/blog/controlling-a-10-bit-digital-potentiometer-via-spi-with-arduino/

I've also sent out an second support email to "Maxim Integrated Products" out in Sunnyvale, CA, and see if they can provide a sample lib or method to effectively make their IC work. I'll update this thread if they do.

I'll give this another few hours, day-max; if this doesn't work I need to ditch this MAX5494 and go for another manufacturer.

((Hrrrrr, pcb, shipping, ICs, passive SMDs, proto... man of man))

In a meantime, I have stopped what I'm doing now and looked at my emails (I know, sad revelation loll). Surprisingly "Maxim Int Products" have replied to my yesterday's inquiry with the following, impressive support!!! (my sincere apologies; its all written in etalian, to me it is anyway :confused: I'll have a rest and look at this when in good shape and see if I can make any sense out of the information below.

*********(Maxim comm):
Unfortunately we don't have any ready-to-go Arduino libraries, but you should be able to get it working with the standard Arduino SPI library pretty easily. It looks like SPI mode 0 (CPOL=0, CPHA=0), and 24 bits per SPI transmission, using the format in Table 2 on page 14 of the datasheet. Bits 1-2, 5-6, and 19-24 are always going to be zero, while bits 3-4 are the command, 7-8 are the control register, and the rest are data to write (if any).

If you want a layer of abstraction rather than some arbitrary SPI transmissions in your code, you could probably implement some writeWiper, writeNV, copyWiper, and copyNV functions that fix bits 1-6 (0 0 C1 C0 0 0) and take the control register and data to write as arguments, appending those onto the preset data. It doesn't look like we have any examples of this, but the datasheet has some diagrams of what the different communications need to look like on pages 14-15, so I'd refer to those.


As a note, you can use char arrays or uint8_t arrays instead of binary arrays. I think it is best to use uint8_t.

I use the ESP32 API so my code will be of no help to you. I recommend opening a new project and adding the cpp and h files of an existing library to use as a SPI guide.

Also, their data sheet is really helpful.

GTC:
@Idahowalker - thanks a bunch, appreciated. I'm looking at your suggestions and will need to figure out what they mean 1st. Might have to give 'Byte Array' code training in tomorrow along w/ 24 coffees instead of 24bits :wink: Wish I'd be strong in c/cpp.. thing is... ah, nevermind lol PS: I've whacked out the delay completely and getting completely different values on the Ohm Meter so you possibly fixed a major impediment the code had. You suggest I give it 12ms delay after the CS goes low?

@sherzaad - thanks as much, very cool. I've tried to give your code a go but got an error I'm not familiar with, would you know what it needs to spark? I like the value ramping loop you provided, I should of thought about that myself.

apologies. made a couple of silly mistakes in the code I posted. :blush:

this is how it should be:

#include <SPI.h>
const uint8_t CSpin = 10;

void setup() {
  SPI.begin();
  pinMode(CSpin, OUTPUT);
}

void loop() {
  for (uint16_t i = 0; i < 1024; ++i) {
    update_digipot(0x01, i);
    delay(1000);
  }
}


void update_digipot(uint8_t reg, uint16_t value) {
  union {
    uint16_t val;
    uint8_t bytes[2];
  } in;

  in.val = value << 6; //as per datasheet

  digitalWrite(CSpin, LOW);

  //Write Wiper Register.  0x01: wiper1, 0x02: wiper2
  SPI.transfer(reg);

  //send upper value byte
  SPI.transfer(in.bytes[1]);

  //send lower value byte
  SPI.transfer(in.bytes[0]);

  digitalWrite(CSpin, HIGH);
}

its compiles (was not in a position to compile-check earlier...). hopefully you can execute it and see if it controls the chip as intended

This actually does work, Sherzaad!!! Wow, much appreciated buddy, I was really pulling my hair out yesterday with this SPI bit order/shifting thingy. I promise I'll carry out proper training on the subject and get up to speed with SPI comm... something somehow lacking greatly in my case lol

Here goes a screen grab of the resolution of the MAX5494. Really works great and does what I want it to do. Kudos man and thanks.

Low: =>> +5V
Wiper: =>> A0
High: =>> GND