From Python to silicon
 

This is an old revision of the document!


"""                                                                            
 dac_sdx1000_hd.py
 First-order Sigma Delta DAC with variable bit-width
 
 MyHDL implementation by George Pantazopoulos http://www.gammaburst.net   
 Nov 2006
"""
from myhdl import *
from math import log, ceil
 
# ----------------------------------------------------------------------------
 
def dac_sdx1000(clk_i, rst_i, pcm_i, pdm_o):
    """
    GJP Enterprises SDX1000 
    Multiplatform First-order Sigma Delta DAC core with variable bit width.
 
    Tested successfully on a Xilinx Spartan3 FPGA.
 
    Inputs:
    clk_i   clock (The faster, the better!)
    rst_i   active high reset
    pcm_i   digital PCM value to convert to PDM stream (adjustable width)
 
    Outputs:
    pdm_o   Pulse-density modulated bitstream. Range [0,1]
 
    To complete the DAC, an external RC analog low-pass filter at the output 
    is usually needed.
    See XAPP154 for more information.
 
    Sources:
    http://www.beis.de/Elektronik/DeltaSigma/DeltaSigma.html
    Xilinx Application Note XAPP154.
    """
 
    __author__    = "George Pantazopoulos http://www.gammaburst.net"
    __version__   = "1.0.1"
    __revision__  = ""
    __date__      = "13 Nov 2006"    
 
    RES = len(pcm_i)
 
    DREF_NEG =  0
    DREF_POS =  (2**RES)-1
 
    MIN = -2**(RES-1)
    MAX = +2**(RES-1)
 
    diff_o  = Signal(intbv(0, min=4*MIN, max=4*MAX))
    adder_o = Signal(intbv(0, min=4*MIN, max=4*MAX))
    reg_o   = Signal(intbv(0, min=4*MIN, max=4*MAX))
    comp_o  = Signal(bool(0))
    ddc_o   = Signal(intbv(0, min=4*MIN, max=4*MAX))
 
    # Difference block ("Delta")
    @always_comb
    def Difference():
        diff_o.next = pcm_i - ddc_o
 
    # The adder and register blocks comprise the integrator ("Sigma")
    # Adder block
    @always_comb
    def Adder():
        adder_o.next = diff_o + reg_o
 
    # Register block
    @always(clk_i.posedge)
    def Reg():
        if rst_i:
            reg_o.next = 0
        else:
            reg_o.next = adder_o
 
    # Comparator block
    @always_comb
    def Comparator():
        if reg_o > 0: 
            comp_o.next = 1
        else:
            comp_o.next = 0
 
    # 1-bit Digital-digital conveter
    # Creates a signed value from the comparator output
    @always_comb
    def DDC():
 
        if comp_o:
            ddc_o.next = DREF_POS
        else:
            ddc_o.next = DREF_NEG
 
    # Bitstream output
    @always(clk_i.posedge)
    def BitStreamOut():
        if rst_i:
            pdm_o.next = 0
        else:
            pdm_o.next = comp_o
 
    return instances()
 
# ----------------------------------------------------------------------------
 
def ToneOsc(clk_i, rst_i, freq_i, pcm_o, ACCUM_WIDTH=24):
    """
    Phase-Accumulating tone oscillator
    """
    OUTPUT_WIDTH = len(pcm_o)
 
    # Phase Accumulator
    accum = Signal(intbv(0)[ACCUM_WIDTH:])
 
    # At each clock, increment the accumulator by the value of freq_i
    @always(clk_i.posedge)
    def accumDrive():
        if rst_i:
            accum.next = 0
        else:
            accum.next = (accum + freq_i) % 2**ACCUM_WIDTH
 
    # Take the top N significant bits of the accumulator as the PCM output
    @always_comb
    def pcmOut():
        pcm_o.next = accum[ACCUM_WIDTH:ACCUM_WIDTH-OUTPUT_WIDTH]
 
    return instances()
 
# ----------------------------------------------------------------------------
 
def top(clk, pdm_o, CLK_HZ):
    """
    Test Harness for Sigma-Delta DAC
    """
 
    OUTPUT_FREQ_HZ = 440
    ACCUM_WIDTH = 24
 
    # Compute some constants
    ONE_HZ_FVAL = CLK_HZ / float(2**ACCUM_WIDTH)
    FVAL = int(ceil(440 * ONE_HZ_FVAL))
 
    print "CLK_HZ = ", CLK_HZ
    print "OUTPUT_FREQ_HZ = ", OUTPUT_FREQ_HZ
    print "FVAL = ", FVAL
 
    pcm_audio = Signal(intbv(0)[8:])
 
    OSC = ToneOsc(clk_i=clk,
                  rst_i=False,
                  freq_i=FVAL,
                  pcm_o = pcm_audio,
                  ACCUM_WIDTH=24)
 
    DAC = dac_sdx1000(clk_i=clk, rst_i=False, pcm_i=pcm_audio, pdm_o=pdm_o)
 
    return instances()
 
# ----------------------------------------------------------------------------
 
CLK_HZ = 16000000
 
clk   = Signal(bool(0))
pdm_o = Signal(bool(0))
 
toVerilog.name = "dac_sigma_delta"
toVerilog(top, clk, pdm_o, CLK_HZ)
 
# ----------------------------------------------------------------------------
def bench_static():
    """
    Static value test
    """
 
    DAC_RES = 8
 
    clk   = Signal(bool(0))
    dat_i = Signal(intbv(0, min=0, max=2**DAC_RES))
    pdm_o = Signal(bool(0))
 
    @always(delay(10))
    def clkgen():
        clk.next = not clk
 
    dac_inst = dac_sdx1000(clk_i=clk, 
                           rst_i=False, 
                           pcm_i=dat_i, 
                           pdm_o=pdm_o)
 
    RUN_STEPS = 64
 
    # dac input values (relative to full scale)
 
    relv = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
    dac_values = list()
 
    for v in relv:
 
        dac_code = int(v * 2**DAC_RES)
 
        if dac_code == 2**DAC_RES:
            dac_code = 2**DAC_RES-1
        elif dac_code > 2**DAC_RES:
            raise Exception
 
        dac_values.append(dac_code)
 
    @instance
    def stimulus():
 
        for dac_value in dac_values:
            for i in range(RUN_STEPS):
 
                yield clk.negedge
                dat_i.next = dac_value
                yield clk.posedge
 
        raise StopSimulation
 
    @instance
    def monitor():
        print "DAC_RES   = ", DAC_RES
        print "RUN_STEPS = ", RUN_STEPS
 
        for dac_value in dac_values:
 
            pdm_accum = 0
            pdm_avg   = 0.0
 
            for i in range(RUN_STEPS):
                yield clk.posedge
                pdm_accum += pdm_o
                #print pdm_o
 
            pdm_avg = float(pdm_accum) / float(RUN_STEPS)
            print "dac_value = %s, pdm_avg = %s" % (dac_value, pdm_avg)
 
    return clkgen, dac_inst, stimulus, monitor
 
# ----------------------------------------------------------------------------
 
def test_static():
    sim = Simulation(bench_static())
    sim.run()
 
if __name__ == '__main__':
    test_static()
 
projects/sdx1000.1163503708.txt.gz · Last modified: 2006/11/13 23:00 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki