Post Go back to editing

Cant get the potentiometer to work

Thread Summary

The user is experiencing issues with the AD5292 digital potentiometer where the wiper position does not change despite correct data being written. The final answer suggests verifying that the SCLK is low during the SYNC falling edge, as per the timing diagrams and Table 14 in the datasheet. The user confirmed the SCLK is low during the SYNC falling edge but still sees a constant logic high voltage on the output. Additional troubleshooting steps include sharing scope shots of the serial interface.
AI Generated Content
Category: Hardware
Product Number: AD5292

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?