I am using the ad5292 to try and automate a calibration process but i have been struggling to obtain the desired changes.
Below is a simple schematic of how my circuits look like, for the capacitors i used the suggested values in the datasheet.
At power up i manually plug the power lines to follow the suggested power up sequence.

I am using 125kHz as clock frequency.
Below is also reported my code. I am reading the change of voltage at pin4 of the ad5292 with an oscilloscope, but it just wont change.
#include <msp430.h>
#include <msp430g2553.h>
#include <stdio.h>
#include <stdbool.h>
// Variable to store potentiometer wiper level
unsigned int potLevel;
// Define alternate names for chip select (CS) lines
#define CS_POT1 BIT3 // P1.3 will be used as the chip select line for Potentiometer 1
#define MAX_WIPER_POSITION 1023 // Maximum for AD5292 (10-bit device)
// Bit definitions for Control Register
#define BIT_C0_ENABLE_20TP (1 << 0) // Bit 0
#define BIT_C1_RDAC_WRITE_PROTECT (1 << 1) // Bit 1
#define BIT_C2_PERFORMANCE_ENABLE (1 << 2) // Bit 2
#define BIT_C3_20TP_SUCCESS (1 << 3) // Bit 3
void clockConfig()
{
// Configure the CPU clock (MCLK) and the Sub-Main Clock (SMCLK)
// Set the DCO (Digitally Controlled Oscillator) to run at 1 MHz
// Using factory-calibrated constants for 1 MHz operation
BCSCTL1 = CALBC1_1MHZ; // Set basic clock system control for 1 MHz --- this is the register that set source basic frequency, set it using a calibration constant
DCOCTL = CALDCO_1MHZ; // Set DCO control register for 1 MHz ---- this is the digital clock register, independent from the the other clocks, set it software
// Set clock dividers for SMCLK and MCLK
// SMCLK = DCO / 8 (125 kHz), MCLK = DCO (1 MHz)
BCSCTL2 = DIVS_3 + DIVM_0; // DIVS_3 sets SMCLK divider to 8, DIVM_0 sets MCLK divider to 1 --- this register sets the dividers for all the clocks, there are different constants in the library for each clock that is how i set dividers for different clocks
}
void pinConfig()
{
// Configure USCI (SPI) pins on Port 1
P1SEL |= BIT5 + BIT6 + BIT7; // Set P1.5 (SCLK), P1.6 (MOSI), P1.7 (MISO)
P1SEL2 |= BIT5 + BIT6 + BIT7; // Set for USCI (SPI) mode
// Configure chip select (CS) pins for two potentiometers
P1DIR |= CS_POT1; // Set P1.3 as output for chip select line
P1OUT |= CS_POT1; // Set CS lines high (inactive state)
// Configure RESET pin
P1DIR |= BIT0; // Set P1.0 as output (for RESET)
P1OUT |= BIT0; // Set RESET high (inactive)
// Configure RDY pin
P1DIR &= ~BIT1; // Set P1.1 as input (RDY)
P1REN |= BIT1; // Enable pull-up resistor on P1.1
P1OUT |= BIT1; // Set P1.1 high (enable pull-up resistor) (inactive state)
// Note: VSS, VDD, EXT_CAP, VLOGIC, and GND pins do not need to be configured in code.
}
// Configure the USCI module for SPI communication - USCI (universal serial communication interface)
void spiConfig()
{
// Put USCI state machine in reset mode to configure it
UCB0CTL1 = UCSWRST; // Enable software reset to allow configuration -- Enabled. USCI logic held in reset state.
// Configure SPI control register
// UCCKPH = Clock phase select
// UCCKPL = Clock polarity select - low when idle
// UCMSB = MSB first select. Controls the direction of the receive and transmit shift register. Data is transmitted MSB (Most Significant Bit) first
// UCMST = Master mode select -- Set as SPI master
// UCMODE = USCI mode. The UCMODEx bits select the synchronous mode when UCSYNC = 1. 00b = 3-pin SPI 01b = 4-pin SPI with UCxSTE active high: slave enabled when UCxSTE = 1 10b = 4-pin SPI with UCxSTE active low: slave enabled when UCxSTE = 0 11b = I2C mode. I am uisng 3 wire beacuse I have to handle multiple slaves and it is the best way since 4 wire only gives advantage if you want to automatically control only 1 slave.
// UCSYNC = Synchronous mode enable. Must be 1 for SPI mode. --- Synchronous mode (SPI)
UCB0CTL0 |= UCCKPH + UCMSB + UCMST + UCMODE_0 + UCSYNC; // Set up 3-wire SPI in master mode with high clock polarity --- each of these are a single bit in the UCB0CTL0 register
// Select clock source for USCI (SCLK), use SMCLK as the clock source
UCB0CTL1 |= UCSSEL_2; // Use SMCLK --- USCI 0 Clock Source: 2
// Set SPI clock speed (baud rate)
// Baud rate is SMCLK divided by UCB0BR0 and UCB0BR1
// Setting both UCB0BR0 and UCB0BR1 to 0 gives full SMCLK speed
UCB0BR0 = 1; // No division, full SMCLK speed ---- The 16-bit value of (UCB0BR0 + UCB0BR1 × 256) forms the pre-scaler value.
UCB0BR1 = 0; // No division, full SMCLK speed ---- I want pre-scaler value to be 1 so UCB0BR0 = 1 and UCB0R1 = 0.
// Release USCI state machine from reset to enable SPI communication
UCB0CTL1 &= ~UCSWRST; // Initialize USCI for SPI communication -- Disabled. USCI reset released for operation.
}
void cycleCS(unsigned char csLine) {
unsigned int command2 = 0x0000; // Command 0 (NOP)
// Assert CS (active low)
P1OUT &= ~csLine; // Set CS low
__delay_cycles(100); // Small delay
// Send second command (Command 0)
while (UCB0STAT & UCBUSY); // Wait until SPI module completes previous transmission
UCB0TXBUF = (command2 >> 8); // Send upper byte of Command 0
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
UCB0TXBUF = (command2 & 0xFF); // Send lower byte of Command 0
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
// Deassert CS
P1OUT |= csLine; // Set CS high
__delay_cycles(100); // Small delay
}
// Function to update wiper position with specified CS line // write to RDAC
void updateWiperPosition(unsigned char csLine, unsigned int newPosition) {
// Send the new position to the RDAC register
unsigned int command1 = 0x0400 | (newPosition & 0x03FF); // Command 1 (0x0400) and new position
// Send the command to update the wiper position
P1OUT &= ~csLine; // Bring CS pin low to initiate communication
while (!(IFG2 & UCB0TXIFG));
UCB0TXBUF = (command1 >> 8); // Send upper byte
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
UCB0TXBUF = (command1 & 0xFF); // Send lower byte
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
while (UCB0STAT & UCBUSY); // Wait until the SPI module completes transmission
P1OUT |= csLine; // Bring CS pin high to complete communication
cycleCS(csLine);
}
// Function to read wiper position with specified CS line
unsigned int readWiperPosition(unsigned char csLine) {
unsigned int wiperPosition = 0;
unsigned int command = 0x0800; // Command 2
// Assert CS (active low)
P1OUT &= ~csLine; // Use the provided CS line
// Send the first 16-bit command
while (!(IFG2 & UCB0TXIFG)); // Wait for TX buffer to be ready
UCB0TXBUF = (command >> 8); // Send upper byte
while (!(IFG2 & UCB0TXIFG)); // Wait for TX buffer to be ready
UCB0TXBUF = (command & 0xFF); // Send lower byte
while (!(IFG2 & UCB0TXIFG)); // Wait for TX buffer to be ready
// Receive the 16-bit wiper position data
UCB0TXBUF = 0x00; // Dummy write to generate clock
while (!(IFG2 & UCB0RXIFG)); // Wait for RX buffer (MSB)
wiperPosition = UCB0RXBUF << 8; // Read upper byte
while (!(IFG2 & UCB0RXIFG)); // Wait for RX buffer (LSB)
wiperPosition |= UCB0RXBUF; // Read lower byte
// Deassert CS
while (UCB0STAT & UCBUSY); // Wait until the SPI module completes transmission
P1OUT |= csLine; // Use the provided CS line
cycleCS(csLine);
return (wiperPosition & 0x03FF); // Return 10-bit RDAC value
}
unsigned int setControlRegister(unsigned char csLine, bool enable20TP, bool rdacProtect, bool calibEnable) {
unsigned int controlReg = 0x1800; // Base command, could be adjusted as needed
// Set bits based on input parameters (true is 1, false is 0)
if (enable20TP) {
controlReg |= BIT_C0_ENABLE_20TP; // Set C0 to 1
}
if (rdacProtect) {
controlReg |= BIT_C1_RDAC_WRITE_PROTECT; // Set C1 to 1
}
if (calibEnable) {
controlReg |= BIT_C2_PERFORMANCE_ENABLE; // Set C2 to 1
}
// Write the control register
P1OUT &= ~csLine; // Bring SYNC/CS pin low
while (!(IFG2 & UCB0TXIFG));
UCB0TXBUF = (controlReg >> 8); // Send upper byte
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
UCB0TXBUF = (controlReg & 0xFF); // Send lower byte
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
while (UCB0STAT & UCBUSY); // Wait until the SPI module completes transmission
P1OUT |= csLine; // Bring SYNC/CS pin high
cycleCS(csLine);
return controlReg; // Optionally return the value of the control register
}
// Function to place the pin in high impedance and minimize power dissipation
void setHighImpedanceMode(unsigned char csLine) {
unsigned int command1 = 0x8001; // First data word
unsigned int command2 = 0x0000; // Command 0 (NOP)
// Begin communication with the chip
P1OUT &= ~csLine; // Bring CS pin low to initiate communication
// Send first command (0x8001)
while (!(IFG2 & UCB0TXIFG)); // Wait for TX buffer to be ready
UCB0TXBUF = (command1 >> 8); // Send upper byte of 0x8001
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
UCB0TXBUF = (command1 & 0xFF); // Send lower byte of 0x8001
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
// Send second command (Command 0)
while (UCB0STAT & UCBUSY); // Wait until SPI module completes previous transmission
UCB0TXBUF = (command2 >> 8); // Send upper byte of Command 0
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
UCB0TXBUF = (command2 & 0xFF); // Send lower byte of Command 0
while (!(IFG2 & UCB0TXIFG)); // Wait for transmission to complete
// End communication with the chip
while (UCB0STAT & UCBUSY); // Wait until SPI module completes all transmissions
cycleCS(csLine);
P1OUT |= csLine; // Bring CS pin high to complete communication
}
void main(void)
{
// Stop the watchdog timer to prevent the system from resetting
WDTCTL = WDTPW + WDTHOLD;
// Configure the system clock to run at 1 MHz (MCLK) and SMCLK at 500 kHz
clockConfig();
// Configure the necessary pins for SPI and chip select lines
pinConfig();
// Initialize the SPI peripheral (USCI module) for communication
spiConfig();
cycleCS(CS_POT1);
setControlRegister(CS_POT1, 1, 1, 0);
// Main program loop
while (1)
{
for( potLevel =0; potLevel < MAX_WIPER_POSITION; potLevel++)
{
//setHighImpedanceMode(CS_POT1);
updateWiperPosition(CS_POT1, potLevel);
__delay_cycles(300);
}
}
}
I see online that many people have had issues with this part, specifically with the wiper position update. Have you been able to identify a solution that might work for my case?