Shop OBEX P1 Docs P2 Docs Learn Events
Smart Pin DAC — Parallax Forums

Smart Pin DAC

CON
            
    oscmode = $010c3f04               'standard stuff
    freq    = 160_000_000

pub main     | pMode, outVal, period, thePin
    clkset(oscmode, freq)
    thePin := 41
    pMode := %0000_0000_000_10100_00000000_01_00010_0     'Random dither
'    pMode := %0000_0000_000_10100_00000000_01_00011_0     'PWM dither
    period := 32768                      
    outVal := 16384                 
    asm
       dirl     thePin
       wrpin    pMode,     thePin
       wxpin    period,    thePin
       wypin    outVal,    thePin
       dirh     thePin
    endasm 
    repeat 

I have tried various values of period and outVal but my Propscope fails to trigger. If I turn the trigger off the Propscope measures -9 to 19 mVolts. I tried a simple program to toggle the pin at 1000 hz and the Propscope picked it up fine. I don't know what I am missing.

John Abshier

Comments

  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2019-04-19 18:56
    Try shifting your data value to wypin up by 16 bits left into the msbs. (can't sleep, I will look at it again to see what's wrong).
    You need immediate values since period and outVal etc are global variables only. (I think)

    This is a simple DAC function in TAQOZ.
    pub DAC ( bits -- )		%101_000_0000000_01_00011 WRPIN |< WXPIN ;
    pub V ( volts*1000 --- )	16 << 3300 U/ WYPIN ;
    

    So the first line is equivalent to WYPIN ##%101_000_0000000_01_00011,#thePin and also WXPIN ##1<<12,#thePin.

    Setup:
    32 PIN 12 DAC
    

    To set pin to 1.850V
    1.850 V
    
  • ozpropdevozpropdev Posts: 2,791
    edited 2019-04-20 01:10
    Your code should be using '#' for immediate values. Peter's on to it :)
    dirl     #thePin
           wrpin    ##pMode,     #thePin
           wxpin    ##period,    #thePin
           wypin    ##outVal,    #thePin
           dirh    #thePin
    
  • ozpropdev wrote: »
    Your code should be using '#' for immediate values. Peter's on to it :)
    dirl     #thePin
           wrpin    ##pMode,     #thePin
           wxpin    ##period,    #thePin
           wypin    ##outVal,    #thePin
           dirh    #thePin
    

    No, that's not it: pMode, period, outVal, and thePin are all variables, i.e. registers, so putting "#" in front of them will definitely not do what you want -- it'll cause the address of the variables to be used rather than their values.

    I don't know off-hand what's wrong, and don't have my P2 handy, but the values for period and outVal look wrong to me. I think generally there should be something in the upper 16 bits, but the sample code above has 0 there.
  • Ah, I'm looking at the code from a Pnut pasm perspective(That's all I use).
  • From Propeller 2 Documentation v32.pdf
    %00010 and DAC_MODE = DAC 16-bit with pseudo-random dither
    This mode overrides P[7:0] to feed the pin’s 8-bit DAC with pseudo-randomly-dithered data on every clock. P[12:10] must be
    set to %101 to configure the low-level pin for DAC output.
    X[15:0] establishes the sample period in clock cycles.
    Y[15:0] establishes the DAC output value which gets captured at each sample period and used for its duration.
    

    I will be out of town the next 2 1/2 days and unable to test but will follow the forum.

    John Abshier
  • Here is a program where I tried to use the P value to set the DAC level. But still no joy.
    CON
                
        oscmode = $010c3f04               'standard stuff
        freq    = 160_000_000
    
    pub main     | pMode, outVal, period, thePin
        clkset(oscmode, freq)
        thePin := 41
        '         AAAA BBBB FFF PPPPP PPPPPPPP TT MMMMM
        pMode := %0000_0000_000_10100_01000000_00_00000_0     
        asm
           dirl     thePin
           wrpin    pMode,     thePin
           dirh     thePin
        endasm 
        
        repeat 
        
    {       dirb[thePin] := 1           ' code to test Propscope comment out the above assymbler code 
           !outb[thePin] 
           waitcnt(cnt + clkfreq / 1_000_000)}
    

    John Abshier
  • This is the mode I use: %101_000_0000000_01_00011_0

    Read the section in the doco about these modes when using the DAC.
  • evanhevanh Posts: 15,091
    edited 2019-04-20 04:56
    Here is a program where I tried to use the P value to set the DAC level. But still no joy.
    '         AAAA BBBB FFF PPPPP PPPPPPPP TT MMMMM
        pMode := %0000_0000_000_10100_01000000_00_00000_0     
        asm
           dirl     thePin
           wrpin    pMode,     thePin
           dirh     thePin
        endasm 
    
    That works for me. Here's my pure pasm version and a screenshot from the scope.
  • evanhevanh Posts: 15,091
    edited 2019-04-20 05:01
    Here's a cleaner version that doesn't repeatedly disable the pin
    _main
    		dirl	pin
    		wrpin	pincfg, pin
    		dirh	pin
    _loop
    		waitx	sec
    		getrnd	count
    		setbyte	pincfg, count, #1
    
    		wrpin	pincfg, pin
    		jmp	#_loop
    
    
  • Evanh, this is what I think your program does, but I am not an assembly guy. It looks like you are looping 4 times per second. But the scope trace looks like 2 loops per second. Output is to pin 0. Each time through the loop you replace the last byte of pincfg with a random byte to set the DAC level. Did I read your code correctly?

    John Abshier
  • evanhevanh Posts: 15,091
    Oops, good catch, that's buggy code. In my rush to shorten the size of my default working environment I deleted one line I shouldn't have. It shouldn't be working like that.

    The ORGH should be ORGH $400.
  • You don't use DIRH for dithered dac mode. Smartpin modes take over the function of OUTx and DIRx
    registers and may give them alternate uses. Both dithered DAC modes are smartpin modes.

    Raw DAC mode (not dithered) is not a smartpin mode so will require DIRH as I understand it. The MMMMM
    bits have to be non-zero for smartpin operation.

    I think that's right. Certainly my code using dither modes doesn't touch DIRx or OUTx
  • Mark_T wrote: »
    You don't use DIRH for dithered dac mode. Smartpin modes take over the function of OUTx and DIRx
    registers and may give them alternate uses. Both dithered DAC modes are smartpin modes.

    Raw DAC mode (not dithered) is not a smartpin mode so will require DIRH as I understand it. The MMMMM
    bits have to be non-zero for smartpin operation.

    I think that's right. Certainly my code using dither modes doesn't touch DIRx or OUTx, just uses WRPIN and WYPIN

  • Mark T, could you please post your code?

    John Abshier
  • evanhevanh Posts: 15,091
    edited 2019-04-21 21:29
    In my examples the first DIRH is needed to first enable pin drive. Repeated DIRL/DIRH combos will repeatedly disable/enable the pin drive.

    Mark might be correct when using %TT = 01. This basically forces DIRH for that pin. When in a DAC mode the OUT becomes an ADC enable.

    Err, reading the docs, %TT = 01 in DAC mode means config for SETDACS operation:
    	for smart pin mode off (%MMMMM = %00000):
    
    		DIR enables output
    
    		for non-DAC_MODE:
    			0x = OUT drives output
    			1x = OTHER drives output
    
    		for DAC_MODE:
    			00 = OUT enables ADC, P[7:0] sets DAC level
    			01 = OUT enables ADC, P[3:0] selects cog DAC channel
    			10 = OUT drives BIT_DAC, drives two levels, P[7:0] sets DAC high level, #0 is low level
    			11 = OTHER drives BIT_DAC, drives two levels, P[7:0] sets DAC high level, #0 is low level
    
    

    And some additional info from the pad_io_modes
    	%101_VV_DDDDDDDD = DAC_MODE (%TT = 00 and %MMMMM = 00000), 8-bit flash
    		OUT enables PinA ADC (ADC config %011), sysclocked bitstream on IN
    		DIR enables PinA DAC output
    		%VV = PinA drive config
    			00: 990 ohm, 3.3 volt range
    			01: 600 ohm, 2.0 volt range
    			10: 123.75 ohm, 3.3 volt range
    			11: 75 ohm, 2.0 volt range
    		%DDDDDDDD = DAC level
    
    		for %TT = %01 and %MMMMM = %00000, %101_VV_xxxxSSSS = COG_DAC mode
    			%SSSS = Cog/streamer select: sets DAC level (registered?)
    
    
  • Mark_TMark_T Posts: 1,981
    edited 2019-04-22 15:57
    Mark T, could you please post your code?

    John Abshier
    con
      pin = 56
      freq = 160_000_000
      mode = $010c3f04
      delay = freq / 100000
    
      prng = %0000_0000_000_10100_00000000_01_00001_0
      dither = %0000_0000_000_10100_00000000_01_00010_0    ' remember to wypin
      dither_pwm = %0000_0000_000_10100_00000000_01_00011_0    ' remember to wypin
      dac  = %0000_0000_000_10100_00000000_00_00000_0
    
    dat
        org
    
        ' set up clock
        hubset #0
        hubset ##mode  ' initialize oscillator
        waitx ##20_000_000/100 ' wait for it to settle down
        hubset ##mode + %11   ' enable it 
    
        mov    val, #0
        wrpin   ##dither_pwm, #48
        wxpin   #0, #48
    
        ' now loop forever blinking the pin
        rep @done, #0
        drvnot #pin
    
        waitx ##delay
        add   val, #1
        and   val, #$FF
        mov   t, val
        xor   t, #$E7
        shl   t, #8
        wypin t, #48
    done
    
    val	long	0
    t       long    0
    

    An old test file, the loop is generating a somewhat random step function using add, xor I think, in pwm dither mode
    (I think the wxpin is unnecessary)
  • I am getting really frustrated. Mart T's code produces a repeating stairstep output. I just want a fixed output value, say 1/2 voltage. I set val to 128 and commented out the code that changes the value written with wypin. Result is 29 to 49 milliVolts. I was expecting 3.3/2 volts. Here is the modified code. Changed lines have ***********
    mov    val, #128  '#0                        ******************
        wrpin   ##dither_pwm, #48
        wxpin   #0, #48
    
        ' now loop forever blinking the pin
        rep @done, #0
        drvnot #pin
    
        waitx ##delay
    '    add   val, #1                             *********************
    '    and   val, #$FF                           *********************
        mov   t, val
    '    xor   t, #$E7                             *********************
    '    shl   t, #8                               *********************
        wypin t, #48
    done
    

    John Abshier
  • Hi John,

    For what you want, just set WRPIN to set the static DAC level. wypin isn't required and may be causing issues
    nxtdac		mov	i, j
    		shl	i,#8
    		or	i, pinmode	'overlay DAC pin command
    		wrpin	i,p		'set pin to DAC output mode
    		drvh	p		'output high 
    		
    		call	#pulsevm
    
    		add	j,#1
    		cmp	j,#256 wcz
    	if_ne	jmp	#nxtdac
    

    in the code above 'j' is the static level 0 to 255
    pinmode starts as
    pinmode		long	%0000_0000_000_10100_00000000_00_00000_0 + dacnum<<16	'DAC3 75R
    

    Note that if you output 128 you'll get around 1.65 or 1.0 volts depending on which dac you're using

    Full working code we used for stepping through multiple dacs and every pin attached. The pulsevm sends a pulse to the multimeter to take a reading
  • Tubular, you gave me the essential magic piece of information that I needed. Thanks very much. I was doing a dirh and what I needed was a drvh. My goal was to write a simple analog to the Arduino AnalogWrite function. I now have an 8 bit (0-255) version working and tested for modes 00: 990 ohm, 3.3 volt range and 01: 600 ohm, 2.0 volt range. Modes 10: 123.75 ohm, 3.3 volt range and 11: 75 ohm, 2.0 volt range didn't work, but I don't care. I think I have the 16 bit random dither mode working, but need to test. Ultimate goal is a simple to use library that would make and Arduino user comfortable with switching to a Prop2.

    John Abshier
  • Looking back at your early code John, that should have worked ok. Other than the DIRL that shouldn't be required, I'm not sure why it wouldn't have worked. Suggest trying another pin and double checking the basics . The other weird thing is that Evanh's scope shot shows a moving output

    Were you calling that pasm repeatedly on a tight loop? Or just once (just once should be fine)


  • Ah yeah nasty, I didn't pick that up when looking back at your code, either.

    Sounds like a worthy project, hope the remainder goes smoothly
  • evanhevanh Posts: 15,091
    My scope screenshot was for my extended example code that explicitly added the changing levels as a demo. Just to show the program was working and able to set the level.

    I thought the looping/stepping nature was obvious and wouldn't cause confusion. John even correctly described it and identified a bug I had.

  • evanhevanh Posts: 15,091
    Here's a commented version
    _main
    		dirl	pin
    		wrpin	pincfg, pin		initial DAC level set
    		dirh	pin
    loop
    		waitx	sec			'puase for half second
    		getrnd	count			'get a random number as next DAC level
    		setbyte	pincfg, count, #1	'insert 8 bits of DAC level into pincfg data
    
    		wrpin	pincfg, pin		'update DAC level
    		jmp	#loop			'repeat from pause
    
    
  • evanhevanh Posts: 15,091
    edited 2019-04-23 01:21
    John,
    The way to make the OUT bit control the DAC level is to use what's called BIT_DAC mode. I'm guessing you may have accidentally done this already. There is mention of this in the main doc and here's the pad_io_modes write up continuing from earlier posting. Full write up - https://forums.parallax.com/discussion/comment/1452036/#Comment_1452036
    		for %MMMMM >= %00100 or (%TT = %1x and %MMMMM = %00000) = BIT_DAC mode
    			OUT sets DAC level (clocked?, ADC disabled?, IN = ?)
    				0: 0 = GIO level
    				1: %DDDDDDDD
    

    An example would be:
    pin		long	0
    pincfg		long	%0000_0000_000_10100_00000000_10_00000_0  + 128 <<8	'128 is the preset
    
    
    _main
    		drvl	pin			'start with a low OUT
    		wrpin	pincfg, pin		'config the preset DAC level
    		dirh	pin
    loop
    		waitx	sec			'pause for half second
    		outnot	pin			'toggle between 0 volt and preset DAC level
    		jmp	#loop			'repeat from pause
    
    
Sign In or Register to comment.