DAC use with 20M2

Pic8581

New Member
Hi

I am a little bit confused with using the DAC.

The manual shows code like

Code:
'init: 
low DAC_PIN ; make the DAC pin an output
dacsetup %10100000 ; external DAC, supply voltage


main: for b1 = 0 to 31
daclevel b1 ; set DAClevel
pause 1000
next b1
goto main

very straight forward
but I am getting a syntax error that DAC_PIN is not defined.

Code:
symbol DAC_PIN = TXD
does not work either.

Also, how does it work that the TXD pin will be the DAC output? Will it not block the programming
once it is running and outputting voltage?

Thanks for your help - as always!
 

westaust55

Moderator
Try adding the line:
SYMBOL DAC_pin = A.0

Most IO pins have multiple purposes.
Internal hardware and SFR (special function registers) are used to control which function/feature is used or available at each IO pin.
 

neiltechspec

Senior Member
Why bother trying to define it as a symbol ?

With an instruction name of daclevel it's pretty obvious what pin it is pointing at.

I use it as an extra I/O pin on quite a few projects with daclevel 0 & daclevel 31 (obviously with dacsetup %10100000 at the begining).

Neil.
 

hippy

Ex-Staff (retired)
The DAC output pin is fixed in hardware but the pin needs to be set as an output to allow a voltage to be output. On the 20M2 the pin is always an output so a LOW command is not required. For other PICAXE it may be required.

When DAC output and Serial Out share the same pin, enabling DAC output will disable serial output. This is part of the hardware spec of the underlying PICmicro which we have no control over. Any design using DAC output will have to take that into account. It is possible to output serial on other pins but SERTXD and DEBUG have no effect while DAC output is enabled.
 

Pic8581

New Member
Thank you for all the help.
I did not found a mentioning that TXD=A.0. but as neiltechspec mentioned above, maybe it's not even needed.
Definitely a point to improve in the manual.

Hippy, my concern was programming the chip again after enabling the DAC on the TXD pin that is used to program the PIC.
I would think there is some mechanism that it listens to RXD and disables the DAC again. but I wanted to make sure.

Thanks again.
 

westaust55

Moderator
Why bother trying to define it as a symbol ?

With an instruction name of daclevel it's pretty obvious what pin it is pointing at.

I use it as an extra I/O pin on quite a few projects with daclevel 0 & daclevel 31 (obviously with dacsetup %10100000 at the begining).

Neil.
A deviation from the DAC topic but next time as a digital Output just use LOW A.0 and HIGH A.0
Did just that in this project posted over a year ago:
http://www.picaxeforum.co.uk/attachment.php?attachmentid=17775&d=1421970690
http://www.picaxeforum.co.uk/showthread.php?27013-PICAXE-based-Model-Railway-Speedometer-Wagon
 
Last edited:

neiltechspec

Senior Member
No offence intended, but I already knew that, but have used daclevel in long programs..

I just gave daclevel 0 & 31 as an example of no point in trying to define a symbol for it.

Neil.
 

Pic8581

New Member
Thanks a lot

I will try the "no configuration" dacsetup.

Still I am a bit worried about using the TXD as a DAC output. I hope that picaxe has some built in interrupt that will disable the DAC when something arrives at the RXD. I would really hope so.

Thanks again
 

westaust55

Moderator
I hope that picaxe has some built in interrupt that will disable the DAC when something arrives at the RXD. I would really hope so.
Yes there is.

From power up, the PICAXE built-in firmware monitors the SerialIn pin. This must be kept low otherwise the firmware is triggered to be ready for a new program download.
The exception is that when a DISCONNECT or SERRXD command is used, this prevents the PICAXE continuing to monitor the SerialIn pin for a new program download and the pin can then be used as a digital input for some M2 PICAXE parts (not 20M2) - but the pin must be held low until the DISCONENCT command in your BASIC program is executed.
 

Pic8581

New Member
Thank you, I got the DAC running but now I have another issue: It is very non linear.

I'm doing the usual from b1 = 0 to 31 daclevel b1 routine but immediately notice on my scope that this is not a nice ramp.

the values are (measured with a DVM, no load):

1= 0.161
2= 0.318
4= 0.61
8= 0.925 (!)
16 = forgot to write down

Measure without load, double-checked... odd
 

premelec

Senior Member
Manual sez DAC must be buffered - shows capacitor indicating it's not just source R but also likely pulsy nature - put a cmall cap on DAC output and see if that fixes it up...
 

westaust55

Moderator
The PICAXE M2 series DAC output is based on a resistor ladder and switching the tapping point.
See page 240 in datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/41365E.pdf
This is the same as other external DAC chips by microchip that I have previously posted about (in a "Getting started" thread on DAC's).

also from the datasheet:
Due to the limited current drive capability, a buffer must be used on the voltage reference output for external
connections to CVREF. Figure 20-2 shows an example buffering technique
Either an op-amp in unity gain vonfig or an analogue switch type chip such as the 74HC4051/4052/4053 can be used
 

hippy

Ex-Staff (retired)
When we tested DAC output the results seemed quite linear so we would suspect some sort of hardware issue.
 

AllyCat

Senior Member
Hi,

As WA55 says, the DAC is basically a series of resistors with a typical resistance of 160k (32 x 5k ohms) between Gnd and VRef. Thus at the mid point the source resistance is ~40k, so the transfer characteristic will be "linear" only if the load resistance is "very large" compared with 40k (i.e. M ohms). Your measured values suggest that your VRef is about 4.9 volts (but the actual voltage and the value for level 16 would have been nice) and the level 8 value appears about 25% low. So your "DVM" load impedance (did you remember to disconnect the serial interface ?) appears to be about 120k.

Using A.0 for the serial (programming) output pin with a 20M2 is rather an "undocumented" feature (of course it's C.0 with 14 and 8 pin devices). "High" and "Low" commands do work, but certainly with PE5 it could not be used in symbol commands (I haven't tried it in PE6). IIRC, to return to SERTXD output (without a reset) you can/should use DACSETUP OFF.

However, for most applications, why not use a (low-pass filtered) PWM output pin as a superior (10-bit) DAC and avoid all these issues ? ;)

Cheers, Alan.
 

reywas

Member
Hi,

...However, for most applications, why not use a (low-pass filtered) PWM output pin as a superior (10-bit) DAC and avoid all these issues ? ;)

Cheers, Alan.
Can someone point me to a thread or two that discusses using this method? I did a search on "PWM*,DAC*" and didn't find the info I was looking for.

Thanks.
 

AllyCat

Senior Member
Hi,

This code snippet description (and its first linked thread) is perhaps rather more complex than you want or need. ;)

Basically, just choose a suitable PWM pin and use a PWMOUT command. For highest resolution set the period to 255 and duty over the range 0 - 1023. However, a higher frequency PWM can use smaller filter components (use the PWM Wizard for suitable values). For some applications you might not even need a filter (e.g. driving LEDs or some meters), but typically a few kohms from the PWM pin connected onto a few hundred nF to ground may form an adequate low-pass filter.

For more detailed filter design you may need to compromise residual ripple amplitude against slew rate, etc. But also bear in mind that PICaxe Basic can't update the "DAC" much faster than 1 ms (and longer with PWMDUTY) and also the PIC output transistors are not "perfect" switches (i.e. they have some resistance and switching delay, etc.).

Cheers Alan.
 

reywas

Member
Thanks AllyCat.

By "use the PWM Wizard for suitable values", did you mean the filter components or the PWM settings?

I have an electronic speed control that uses a pot (0-5V) to control it's PWM output and I'd like to replace the pot with an output from the PIC, using as few components an possible.
 

AllyCat

Senior Member
Hi,

Yes, use the wizard for the PWM frequency, perhaps around 30 kHz (33us period).

A simple RC filter should be fine. Make the R about 1/4 the value of Pot you'd use. For a motor, a time constant (R*C) of ~10 ms should be fine, so choose the capacitor accordingly. There should be plenty of TC calculators on the web, if you can't do the maths (or get someone do it for you).

The filtered output voltage should "track" the supply rail in exactly the same way as would a pot connected across the same (PICaxe) supply rails. No need for any stabilising/compensation methods.

Cheers, Alan.
 

reywas

Member
Using AlleyCat's suggestions, I implemented a simple R/C low-pass filter, wrote a bit of code and...it's working! Mostly. I have a math logic problem I could use a little help with.

Code:
[color=Black]calc_PWM:[/color]

[color=Blue]if [/color][color=Purple]Spd[/color][color=DarkCyan]>[/color][color=Navy]300 [/color][color=DarkCyan]and [/color][color=Purple]Spd[/color][color=DarkCyan]<[/color][color=Navy]1200 [/color][color=Blue]then                    [/color][color=Green];valid pulse length?
      [/color][color=Purple]Spd [/color][color=DarkCyan]= [/color][color=Purple]Spd [/color][color=DarkCyan]MIN [/color][color=Navy]325 [/color][color=DarkCyan]- [/color][color=Navy]325                   [/color][color=Green];offset by channel min, Spd >= 0
      [/color][color=Purple]NewDuty [/color][color=DarkCyan]= [/color][color=Purple]Spd[/color][color=DarkCyan]/[/color][color=Navy]860 [/color][color=DarkCyan]* [/color][color=Navy]1023                  [/color][color=Green];Spd/chMax * 100% duty(1023)[/color]
[color=Blue]else [/color][color=Purple]w9[/color][color=DarkCyan]=[/color][color=Purple]w9                                      [/color][color=Green];keep previous duty[/color]
[color=Blue]endif

pwmduty C.2[/color][color=Black], [/color][color=Purple]NewDuty                            [/color][color=Green];31250Hz at 100% @ 32MHz[/color]
The NewDuty calculation over-runs the register and my usual divide by 10 method introduces too much rounding error. Could use some guidance here.

Spd = 0 - 860 after offset

Thanks.
 
Last edited:

reywas

Member
Well, after some head scratching I came up with this:

Code:
[color=Purple]NewDuty [/color][color=DarkCyan]= [/color][color=Purple]Spd[/color][color=DarkCyan]*[/color][color=Navy]64[/color][color=DarkCyan]/[/color][color=Navy]86[/color][color=DarkCyan]*[/color][color=Navy]16[/color][color=DarkCyan]/[/color][color=Navy]10[/color]
I divided the max duty cycle (1024) by 16 and the chMax(860) by 10.

It works well with very little rounding error. Is there a better way to accomplish this?
 
Last edited:

hippy

Ex-Staff (retired)
You could try "NewDuty = Spd * 64 / 54". That 64/54 is quite close to 1023/860 ...

Code:
1023    1024   256    256   64
---- ~= ---- = --- ~= --- = --
860     860    215    216   54
 

hippy

Ex-Staff (retired)
Code:
1023                       ( 0.189 * 65536 )
---- = 1.189 = 0.189 + 1 =  ---------------  + 1
860                              65536
The divide by 65536 is implict in the ** operation, so all that's left is to calculate 0.189 * 65536 = 12421

Done to maximum calculator resolution rather than 0.189, eg ...

( ( 1023 / 860 ) - 1 ) * 65536
 
Top