Post Go back to editing

AD5686 Signal Generation with DAQ - Reg.

Hello, 

I am working with Raspberry pi3b which is connected to AD5686 via SPI communication. It is connected to the Chip select 1. I am trying to generate a sine wave using the DAC commanded by the raspberry pi in the frequency range of about 1000Hz to 10000Hz, But I am not getting exact sine wave. The quantization delay is too high such that for higher frequencies like 10000Hz I get only 4 or five steps for one sine wave. I have also tried with different clock frequencies up to 49Mhz. But there is no use. Only lower frequencies like 300 or 400Hz were able to be achieved Because the sampling frequency is so much higher than the sine repetition  frequency. I will attach two samples of code which I have used. Please someone help me with this.

import spidev
import RPi.GPIO as GPIO
import time
import math

# Define GPIO pins
SYNC_PIN = 7
RESET_PIN = 22
POWER_PIN = 13

# Define SPI settings
spi = spidev.SpiDev()
spi.open(0, 1)  # SPI bus 0, device 1
spi.mode = 0b10
spi.max_speed_hz = 40000000  # 1 MHz

# Setup GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(SYNC_PIN, GPIO.OUT)
GPIO.setup(RESET_PIN, GPIO.OUT)
GPIO.setup(POWER_PIN, GPIO.OUT)

def power_up():
    GPIO.output(POWER_PIN, GPIO.HIGH)

def power_down():
    GPIO.output(POWER_PIN, GPIO.LOW)

def reset():
    GPIO.output(RESET_PIN, GPIO.LOW)
    time.sleep(0.00004)  # Minimum of 40 ns
    GPIO.output(RESET_PIN, GPIO.HIGH)

def write_and_update_dac_channel(channel, data):
    # Convert data to an integer
    data = int(data)

    # Construct the 24-bit command word for writing to and updating DAC channel
    command_word = (0b0011 << 20) | (channel << 16) | data

    # Send the command word over SPI
    GPIO.output(SYNC_PIN, GPIO.LOW)
    spi.xfer2([command_word >> 16, (command_word >> 8) & 0xFF, command_word & 0xFF])
    GPIO.output(SYNC_PIN, GPIO.HIGH)

def generate_sine_wave():
    SINE_DC_OFFSET = 32768
    SINE_AMPLITUDE = 32767

    SINE_WAVE_STEPS = 100
    STEP_DELAY_MICROS = 8.13

    sineWave = [0] * SINE_WAVE_STEPS

    for i in range(SINE_WAVE_STEPS):
        sineWave[i] = SINE_DC_OFFSET + SINE_AMPLITUDE * math.sin(i * 2 * math.pi / SINE_WAVE_STEPS)

    i = 0
    while True:
        write_and_update_dac_channel(0b0001, sineWave[i])
        i = (i + 1) % SINE_WAVE_STEPS
        #time.sleep(STEP_DELAY_MICROS / 1000000)  # Convert to seconds

def main():
    power_up()
    reset()  # Reset the DAC initially

    try:
        generate_sine_wave()
    except KeyboardInterrupt:
        power_down()
        GPIO.cleanup()

if __name__ == "__main__":
    main()

import spidev
import RPi.GPIO as GPIO
import time
import math

# Define GPIO pins
SYNC_PIN = 7
RESET_PIN = 22
POWER_PIN = 13

# Define SPI settings
spi = spidev.SpiDev()
spi.open(0, 1)  # SPI bus 0, device 1
spi.mode = 0b10
spi.max_speed_hz = 40000000  # 1 MHz

def setup():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(SYNC_PIN, GPIO.OUT)
    GPIO.setup(RESET_PIN, GPIO.OUT)
    GPIO.setup(POWER_PIN, GPIO.OUT)

def power_up():
    GPIO.output(POWER_PIN, GPIO.HIGH)

def power_down():
    GPIO.output(POWER_PIN, GPIO.LOW)

def reset():
    GPIO.output(RESET_PIN, GPIO.LOW)
    time.sleep(0.00004)  # Minimum of 40 ns
    GPIO.output(RESET_PIN, GPIO.HIGH)

def write_and_update_dac_channel(channel, data):
    # Construct the 24-bit command word for writing to and updating DAC channel
    command_word = (0b0011 << 20) | (channel << 16) | data

    # Send the command word over SPI
    GPIO.output(SYNC_PIN, GPIO.LOW)
    spi.xfer2([command_word >> 16, (command_word >> 8) & 0xFF, command_word & 0xFF])
    GPIO.output(SYNC_PIN, GPIO.HIGH)

def generate_sine_wave(min_value, max_value, frequency, phase_shift):
    num_samples = 10000  # 50 seconds duration
    for i in range(360):
        # Calculate the sine wave value between 0 and 1
        sine_value = (math.sin(2 * math.pi * i))

        # Scale the sine value to the range between min_value and max_value
        scaled_value = sine_value * (max_value - min_value)

        # Shift the scaled value to the range between min_value and max_value
        shifted_value = scaled_value + min_value

        # Convert the sine value to 16-bit DAC input code
        input_code = int(shifted_value)

        # Write to and update DAC Channel A with the input code
        write_and_update_dac_channel(0b0001, input_code)
        time.sleep(0.001)

def main():
    setup()
    power_up()
    reset()  # Reset the DAC initially

    try:
        while True:
            generate_sine_wave(min_value=32768, max_value=65535, frequency=1230, phase_shift=0)
    except KeyboardInterrupt:
        power_down()
        GPIO.cleanup()

if __name__ == "__main__":
    main()


Thread Notes

  • Hi  

    Can you send a scope capture of one SPI transaction you send to the DAC? I'm assuming that the code doesn't maximize the update rate of the DAC. Which based on the datasheet, t9 spec, could be max. 1.1M updates/sec (ups)

    Best regards,

    Ian

  • Dear Ian,

    These are the scope captures of one SPI transaction. We have only a two channel oscilloscope so I have captured only the SCLK and MOSI. I have also captured time between two successive transactions. Please check them.

    SCLK and MOSI of one SPI transaction

    time between two successive transaction is measured as 300ns

    Regards Guardian BM

  • Hi  

    If we assume that the last plot is accurate, I think that the time between transactions is ~22us not 300ns. That means, at best you are updating the DAC at a rate of 45K ups. which actually correlates to what you are getting, 4 or 5 samples for 10k Hz target sinewave output. 

    You need to check your SPI driver and have some way to adjust the time delay of 22 us for each DAC update. That is the limiting factor to what output frequency are you able to generate at the DAC outputs. 

    Best regards,

    Ian

  • I have checked the spidev documentation the clock can be maximum 50Mhz which i have set and even I have declared the sine values outside the loop so that the calculation doesn't take much time and used the write and update dac directly method but still I'm getting around 20us delay. Can you please cross check the code?

  • Hi, 

    I think the issue lies with how you control the SYNC pin. GPIO functions tend to have long latency. You can have the fastest SCLK available but still get low update rate results because of SYNC. I'm not an expert in coding but what I could advise is to have some sort of PWM or timing function for SYNC instead of the GPIO. You may want to check raspberry pi forums on how to set this up.