EDIT, 25 May 2014: SOLVED - big thanks to SurferTim! - SEE REPLY 3 BELOW FOR FINAL CODE (Solved: Need Help getting my SPI-controlled digital pot to write to its EEPROM - #4 by panther3001 - Networking, Protocols, and Devices - Arduino Forum)
Original post:
Hello, thanks in advance for any assistance you can provide.
I am using a MAX5481 1024-step digital potentiometer, with internal Non-volatile (EEPROM) memory, to store the wiper position. This way, during reboot or reset, the pot will automatically go to the wiper position stored in EEPROM.
Datasheet here: http://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf
I have successfully been able to command the device to go to a desired wiper setting, but I have spent many hours now trying to store this command into its EEPROM, and then test that it worked successfully, to no avail. It appears to be NOT storing the command into its EEPROM even when I am commanding it to do so, so that's where I need your help please.
The SPI commands are defined on pgs. 14-16, and I have very carefully studied the datasheet and set up my communication according to its specs.
-I am not 100% sure about SPI mode, however, but it appears to be SPI_MODE0. I am using the default clock speed of 4MHz, and the device supports up to 7MHz.
My code is as follows:
-It uses the Serial Monitor to receive commands. Set your Serial Monitor baud rate to 115200, and set the end of line character to "newline."
-Type an integer from 0-1023 to set the wiper. - This WORKS!
-Type "t" to turn on the EEPROM store mode, so that it also writes the next integer command to the digital pot's EEPROM. - This appears to not be working.
-Type "f" to turn off the EEPROM store mode, so that when you type the next integer command it only moves the wiper, but does not get stored into EEPROM. - this appears to work.
-Tyep "c" to command the value in EEPROM to get written to the wiper. - this appears NOT to work.
Any help is GREATLY appreciated. Thanks!
/*
write_to_MAX5481
-Code to command this 10-bit digital potentiometer
By Gabriel Staples
http://electricrcaircraftguy.blogspot.com/
23 May 2014
Circuit:
Pin Name Connect to what?
1 VDD +5V (Important: connect a 0.1uF [or larger] ceramic capacitor from VDD to GND, as close to the device as possible) [I'm using a 1uF multi-layer ceramic cap]
2 GND GND/0V
3 CS (SS) Any Arduino pin, let's use D9
4 SCK Arduino pin D13
5 MOSI Arduino pin D11
6 SPI/UD +5V to select SPI mode
7 X
8 X
9 X
10 L GND/0V; this is the LOW side of the voltage divider
11 W Vout; this is the wiper on the potentiometer
12 H +5V; this is the HIGH side of the voltage divider
13 X
14 VSS GND/0V (make sure to tie this to GND)
*/
#include <SPI.h>
//Global Variables
const uint8_t slaveSelectPin = 9; //SPI Slave Select pin
float VDD_measured = 4.4; //measured supply voltage to the device
void setup()
{
Serial.begin(115200);
//set the Slave Select pin as an output
pinMode(slaveSelectPin,OUTPUT);
//initialize SPI
SPI.begin();
SPI.setDataMode(SPI_MODE0); //I think this is the correct mode
// SPI.setDataMode(SPI_MODE2); //test mode
// SPI.setBitOrder(MSBFIRST); //this is correct; the LSBFIRST bit order definitely does NOT work--it scrambles the commands (I checked)
Serial.println("Enter your desired command (0-1023) as an int, with end of line char on. \nType just a \"c\" to copy the EEPROM val to the wiper. ");
}
void loop()
{
static boolean writeEEPROM = false;
if (Serial.available()>0)
{
if (Serial.peek()=='c')
{
Serial.println("copying EEPROM value to wiper register");
Serial.read(); //read in the 'c'
Serial.read(); //read in the '\n'
copy_EEPROM_to_wiper;
}
else if (Serial.peek()=='t')
{
Serial.println("writeEEPROM = true");
Serial.read(); //read in the 't'
Serial.read(); //read in the '\n'
writeEEPROM = true;
}
else if (Serial.peek()=='f')
{
Serial.println("writeEEPROM = false");
Serial.read(); //read in the 'f'
Serial.read(); //read in the '\n'
writeEEPROM = false;
}
else //the first char coming in is NOT a 'c', 't', or 'f', so it must be the wiper command
{
unsigned int command = Serial.parseInt();
if (Serial.read()=='\n') //read in the last char & ensure it is an end-of-line char
{
command = constrain(command,0,1023);
float V_out_calculated = command/1023.0*VDD_measured;
//print data
Serial.print("command = "); Serial.println(command);
Serial.print("V_out_calculated = "); Serial.println(V_out_calculated);
digitalPotWrite(command, writeEEPROM);
}
}
} //end of if serial is available
} //end of loop()
void digitalPotWrite(unsigned int command, boolean writeEEPROM)
{
//local constants
const byte WRITE_WIPER = 0x00; //command to write to the wiper register only
const byte WRITE_EEPROM = 0x20; //command to copy the wiper register into the non-volatile memory (EEPROM) of the digital pot
const byte COPY_EEPROM_TO_WIPER = 0x30; //command to copy the EEPROM value to the wiper register
//command the new wiper setting (requires sending 3 bytes)
digitalWrite(slaveSelectPin,LOW); //set the SS pin low to select the chip
SPI.transfer(WRITE_WIPER); //Byte 1: the command byte
SPI.transfer(highByte(command<<6)); //Byte 2: the upper 8 bits of the 10-bit command: (D9.D8.D7.D6.D5.D4.D3.D2)
SPI.transfer(lowByte(command<<6)); //Byte 3: the lower 2 bits of the 10-bit command, with 6 zeros to the right of them: (D1.D0.x.x.x.x.x.x)
digitalWrite(slaveSelectPin,HIGH); //set the SS pin high to "latch the data into the appropriate control register" (see datasheet pg. 14)
//copy the wiper register into the non-volatile memory (EEPROM) of the digital pot, if commanded (requires sending only 1 byte)
if (writeEEPROM)
{
Serial.println("writing to EEPROM");
delay(10); //wait a short time for the previous command to get properly set
digitalWrite(slaveSelectPin,LOW); //set the SS pin low to select the chip
SPI.transfer(WRITE_EEPROM); //Byte 1: the command byte
digitalWrite(slaveSelectPin,HIGH); //set the SS pin high to "latch the data into the appropriate control register" (see datasheet pg. 14 & 16)
delay(13); //wait 13ms (see datasheet pg. 16 under the paragraph titled "Copy Wiper Register to NV Register"--they require a 12ms wait time, so I'll wait 13ms to be sure)
Serial.println("done writing to EEPROM");
}
}
//copy the value stored in the EEPROM to the wiper register, to command the wiper to go there
void copy_EEPROM_to_wiper()
{
const byte COPY_EEPROM_TO_WIPER = 0x30; //command to copy the EEPROM value to the wiper register
digitalWrite(slaveSelectPin,LOW); //set the SS pin low to select the chip
SPI.transfer(COPY_EEPROM_TO_WIPER); //Byte 1: the command byte
digitalWrite(slaveSelectPin,HIGH); //set the SS pin high to "latch the data into the appropriate control register" (see datasheet pg. 14 & 16)
}