![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
jgschmidt
Joined: 03 Dec 2008 Posts: 184 Location: Gresham, OR USA
|
dsPIC33CK32MC102 DACOUT |
Posted: Wed Mar 24, 2021 9:55 pm |
|
|
I'm trying to use sine tables and a DAC to generate some nice-sounding tones. I started out using 16LF1614 and got good results, but there were not any cycles left to do any other work.
I searched the Microchip Parametrics and settled on dsPIC33CK32MC102 since it would run at 100MIPS and has a 10-bit DAC. Should be plenty of time to generate the DAC outputs and do a little extra work.
I went through all the joys of working with a new chip, got it running at 100MIPS, generated my sine values and tried to feed them to the DAC. Apparently this DAC does not behave as I expected. Not being an EE I don't understand a lot of the data sheet, but since there doesn't even seem to be a Vref for the DAC I apparently chose the wrong device.
Am I missing something?
Is there another device I can use instead? Or am I going to have to feed the sine table values to an external DAC, at the cost of precious cycles?
Thanks for any insights - current code is attached.
Cheers.
Code: | #include <33CK32MC102.h>
#device ansi
#device PASS_STRINGS=IN_RAM
#FUSES FRC_PLL
//#use delay(internal=100M)
#use delay(internal=200M,clock_out)
// Serial debug data via SW. INVERT so can connect directly to legacy PC serial port
#use rs232( BAUD=19200, XMIT=PIN_B6, INVERT, STREAM=JGSDBG )
#define LEDHB PIN_A0 // heartbeat LED
#define LED0 PIN_B15 // loop LED
typedef unsigned int8 UINT8;
typedef unsigned int16 UINT16;
typedef int1 BIT;
//--------------------------- CONSTANTS ---------------------------------------
//--------------------------- Macros and Globals ------------------------------
//
// Sine Table Generator:
// https://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml
#define SINE_STEPS 40
UINT16 SINE_WAVE[SINE_STEPS] = {
0x200,0x250,0x29e,0x2e8,0x32c,0x369,0x39d,0x3c7,
0x3e6,0x3f9,0x3ff,0x3f9,0x3e6,0x3c7,0x39d,0x369,
0x32c,0x2e8,0x29e,0x250,0x200,0x1af,0x161,0x117,
0xd3,0x96,0x62,0x38,0x19,0x6,0x0,0x6,
0x19,0x38,0x62,0x96,0xd3,0x117,0x161,0x1af
};
UINT8 sine_index = 0; // pointer into sine table
//-------------------------------------- INT_TIMER1 ---------------------------
//
UINT16 offset=0xF63B; //for 1KHz sine wave
#int_timer1
void SineTime()
{
set_timer1( offset );
dac_write( 0, SINE_WAVE[sine_index] ); // ?? don't know what first parm should be
if(++sine_index==SINE_STEPS) {
sine_index=0;
}
output_toggle( PIN_B5 ); // verify timing with OScope here
}
//------------------------------------- main() ---------------------------------
void main()
{
setup_adc_ports( NO_ANALOGS);
setup_comparator_dac( COMP_COMMON_DAC_ENABLE ); // ?? Guessing at this...
// Timer1 - 16-bit Prescalar: 1/8/64/256
// 200MHz -> 100MIPS / 65535 -> 1525.9 ticks per second - yup, works!
//
setup_timer1( TMR_INTERNAL | TMR_DIV_BY_1, 0xFFFF ); // Tick timer - adjust as needed via scope
enable_interrupts(INT_TIMER1); // for tick timer
enable_interrupts(GLOBAL);
delay_ms( 500 ); // allow serial port to warm up :)
fprintf(JGSDBG,"\r\n%s %s %s\r\n",__FILENAME__, __DATE__, __TIME__);
while( TRUE ){
delay_ms( 500 );
output_toggle( LED0 );
}//end of BIG LOOP
}//end of main() |
_________________ Jürgen
www.jgscraft.com |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19360
|
|
Posted: Thu Mar 25, 2021 2:47 am |
|
|
It doesn't have a simple DAC as you are thinking. It has a pulse modulation
DAC. This generates a pulse train, which is then integrated by an internal
filter to generate the output voltage. It is 12bit, not 10bit.
Now you could do exactly the same yourself by simply adding an RC filter
to a PWM output, and this would then give simple control.
The DAC is assumed to always feed a comparator, and the actual output
enable has to be done by this..
The comparator channel is the first value in the dac_write command, and
in the slope setup commands. The DAC is actually controlled by the
comparator settings, so it is here that you have to set what clock it is
going to use, etc. You are currently missing these settings.
First thing you need is to select the comparator to use COMP_DAC_CMPXA.
Then enable the output COMP_OUTPUT_DAC. This sets which one is fed
to the output. Only one can be selected at any time.
The clock source for the DAC is set by COMP_DAC_CLK_SRC_xxxxx
Now the slope generator module can feed the DAC, and be programed
to output a table of values from memory automatically. However you are
currently trying to just drive is 'directly', and this is the simpler mode.
So. Probably missed some, but:
Code: |
setup_comparator_dac( COMP_COMMON_DAC_ENABLE | COMP_FILTER_CLK_DIV_1 | COMP_DAC_CLK_DIV_1 | COMP_DAC_CLK_SRC_FVCODIV); //This is the fastest clock settings.
setup_comparator_slope ( 1, COMP_DISABLE_SLOPE_FUNCTION ); //manual setting not slope
setup_comparator(1, COMP_DAC_CMPXA | COMP_OUTPUT_DAC ); //select this comparator to use DAC, and output it.
//Then to output:
dac_write( 1, SINE_WAVE[sine_index] ); // selecting comparator 1.
|
I think I have remembered all the settings that had to happen!... |
|
![](templates/subSilver/images/spacer.gif) |
jgschmidt
Joined: 03 Dec 2008 Posts: 184 Location: Gresham, OR USA
|
|
Posted: Thu Mar 25, 2021 9:41 am |
|
|
Thank you, T. I'll give that a try.
I've tried the RC, and LC, filter approach but haven't had much luck at sub 1KHz frequencies, despite trying a lot of the sample circuits I've found. The range of frequencies for this project is 800 to 40 Hz. This analog stuff is fairly new territory for me, I'm much more comfortable with switch on, switch off
I appreciate your tireless support of this forum - I've learned a lot from you and your fellow responders over the years.
Cheers, _________________ Jürgen
www.jgscraft.com |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19360
|
|
Posted: Thu Mar 25, 2021 11:07 am |
|
|
You'd want the PWM frequency as high as possible. This then allows a
small filter to be used, and still give fast responses. |
|
![](templates/subSilver/images/spacer.gif) |
jgschmidt
Joined: 03 Dec 2008 Posts: 184 Location: Gresham, OR USA
|
|
Posted: Thu Mar 25, 2021 12:31 pm |
|
|
I tried the DAC setup setup you suggested but not a wiggle on DACOUT. Ordering external DAC.
If I understand correctly, what you are suggesting is set up a PWM and then adjust the duty periodically per my sine table, and a sufficiently high frequency PWM should make the smoothing of the wave form easier. I can certainly give that a try, even though I'm dubious about getting a pretty result. Something to do while I wait for my DAC to arrive.
Sigh, I should be used to this, what I thought would be a simple afternoon project for a friend is turning into a months-long affair, especially with the currently long shipping delays from suppliers.
Cheers, _________________ Jürgen
www.jgscraft.com |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19360
|
|
Posted: Fri Mar 26, 2021 1:39 am |
|
|
That is what the DAC on the chip you are trying to use actually does....
Understand that a 'real' (resistive array) DAC to give 10+ bits is
expensive. Hence once you get above perhaps 10 bits, the 'standard'
way to build cheaper DAC's, for low frequencies is by using PWM modulation.
Now the final result is dependant on a series of things:
1) How accurate the frequency and duty cycle is (easy).
2) How accurate the source voltage is (applies to all DAC's).
3) How small the voltage drop is in the switching elements (with modern
FET's can be very small).
4) The switching times of the gates.
5) How good the output filter used is.
For your application, a bandpass filter designed to only pass signals below
a couple of KHz, should give excellent results.
However you should be able to get the output to work on your PIC. I'd
need to go through the assembler and see if the compiler is actually
making the settings correctly. I used a similar DAC on another chip,
and this one worked once I had everything clocked correctly. |
|
![](templates/subSilver/images/spacer.gif) |
jgschmidt
Joined: 03 Dec 2008 Posts: 184 Location: Gresham, OR USA
|
|
Posted: Fri Mar 26, 2021 12:06 pm |
|
|
Thanks. I'm digging into the data sheets, especially the family reference manual for 24/33 parts. I'm having trouble relating the CCS functions to what I want to do - lots of trial and error: code, look at the assembler, repeat. I'm just going to go with setting the registers directly.
I also see now, after my initial disappointment about there being only 1 timer that there are actually quite a few more in the CCP module.
Looks like the "Dual Edge Buffered Compare Mode" will be fun to play with
Still holding the external DAC in reserve - several on the way. 8 bits is plenty. I'm comfortable with switch on/switch off, not so much with the stuff in between (analog). I (sorta) understand the theory behind band-pass filters but they never seem to work for me in real life.
Onward... _________________ Jürgen
www.jgscraft.com |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19360
|
|
Posted: Fri Mar 26, 2021 1:05 pm |
|
|
If you look at what the functions set, and the values given, which registers
they actually put values into becomes obvious. Alternatively simply enable
symbolic mode for the output listing file, send a value, and then look at
the assembler. The functions are not complex. What is 'awkward' is the
way that the comparators and the DAC are crosslinked. So the DAC
output value actually goes into a CCP register. Very strange design indeed.... |
|
![](templates/subSilver/images/spacer.gif) |
jgschmidt
Joined: 03 Dec 2008 Posts: 184 Location: Gresham, OR USA
|
PWM setup difficulties |
Posted: Sat Mar 27, 2021 12:28 am |
|
|
I'm working my way through the CCP modules, timer and interrupt is working great, now on to PWM. Found a lot of articles on using PWM as a DAC. I've worked out my maths and now am ready to try it. Here is my code for setting up a basic 25% duty cycle:
Code: |
pin_select( "CCP2OUT", PIN_B3 ); // CCP2 output for PWM demo
setup_ccp2( CCP_PWM | CCP_DIV_BY_1 | CCP_SYSTEM_CLOCK );
set_timer_period_ccp2( 0x4000, 0xFFFF ); // sets PR to 0x4000
set_pwm2_duty( 0x1000 ); // should be a 25% duty // sets RB to 0x1000,
|
I checked the listing and all the registers seem to be set correctly but nothing comes out on B3.
Any suggestions?
Is there a problem with the Pin Select? One doc labels the output pin as OC2, the device spec sheet lists the assignable pin as OCM2A and CCS lists it as CCP2OUT in the header file. I'm hoping these are all the same. _________________ Jürgen
www.jgscraft.com |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19360
|
|
Posted: Sat Mar 27, 2021 2:31 am |
|
|
Yes.
Actually, correct myself. Your chip does have a CCP. Amazed. Didn't think
any of the DSPIC's did have!... On most of the DSPIC's there is not a CCP
module instead there is an input capture and output compare modules.
However, the CCP output, is not the PWM output. The PWM output is not
a relocatable output. |
|
![](templates/subSilver/images/spacer.gif) |
jgschmidt
Joined: 03 Dec 2008 Posts: 184 Location: Gresham, OR USA
|
|
Posted: Sat Mar 27, 2021 11:46 am |
|
|
So where does the signal go? My 33/24 CCP reference says it goes to "OCx Pin Output". I can't find any reference to that in the device sheet. I tried all the pins, no signal. _________________ Jürgen
www.jgscraft.com |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19360
|
|
Posted: Sat Mar 27, 2021 12:37 pm |
|
|
First thing, have you actually verified your chio is operating?. A simple
output toggle on a single pin with a time delay. Does the pin toggle at the
frequency expected?. Would explain a lot if it is not actually working.
Then the CCP data says that the PWM operates the PWMx pins.
So for PWM1, PWM1H and PWM1L.
The pwm also support fault disable, so this needs to be turned off,
or the fault input needs to be off. |
|
![](templates/subSilver/images/spacer.gif) |
jgschmidt
Joined: 03 Dec 2008 Posts: 184 Location: Gresham, OR USA
|
|
Posted: Sat Mar 27, 2021 12:57 pm |
|
|
Yes, I've been around a while and am familiar with that first step.
The chip is running, LED is toggling, serial output message is displayed. I'm generating a Timer1 and CCP1 timer interrupts that toggle pins, and all speeds are as expected.
PWMxH/L pins seem to be associated with the HSPWM module, which uses a totally different set of registers from the CCP module. I'll look for the fault disable.
I perused a PIC24 datasheet and found an OC1 pin. Perhaps my device doesn't support that particular feature, even though all the registers are there. Sigh... Looks like I'll be digging into the HSPWM - based on previous posts, it causes a lot of grief.
Thanks for your attention. _________________ Jürgen
www.jgscraft.com |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19360
|
|
Posted: Sun Mar 28, 2021 12:45 am |
|
|
OK.
I don't see anywhere you saying what compiler version you are using?. This
is vital. All my assumptions are based on a modern compiler.
So what version do you have?.
There is also an issue with what you were originally trying to do.
If you read the data on the DACOUT, it allows values between 0xCD and
0xF32. It only supports operation between 5% and 95%. So your data
would have to change to use this.
With this asked and said, I therefore decided to try setting up the DACOUT
and make sure the compiler does generate sensible settings.
Will come back as soon as I have done this. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19360
|
|
Posted: Sun Mar 28, 2021 2:28 am |
|
|
OK.
Had a quick play. Generated some test code, and looked at the assembler
versus the MicroChip application note on this peripheral. Turns out there
are two other bits setup by CCS that need to be enabled to generate the
output:
Code: |
#include <33CK32MC102.h>
#device ICSP=1
#device ansi
#device PASS_STRINGS=IN_RAM
#FUSES NOWDT //No Watch Dog Timer
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
#use delay(internal=200M,clock_out)
// Serial debug data via SW. INVERT so can connect directly to legacy PC serial port
#use rs232( BAUD=19200, XMIT=PIN_B6, INVERT, STREAM=JGSDBG )
#define LEDHB PIN_A0 // heartbeat LED
#define LED0 PIN_B15 // loop LED
typedef unsigned int8 UINT8;
typedef unsigned int16 UINT16;
typedef int1 BIT;
//--------------------------- CONSTANTS ---------------------------------------
//--------------------------- Macros and Globals ------------------------------
//
// Sine Table Generator:
#define SINE_STEPS 40
//Modified sine table for 5% to 95% allowed for DACOUT
UINT16 SINE_WAVE[SINE_STEPS] = {
0x7FF,0x91E,0xA37,0xB42,0xC39,0xD14,0xDD0,0xE67,
0xED5,0xF19,0xF2F,0xF19,0xED5,0xE67,0xDD0,0xD14,
0xC39,0xB42,0xA37,0x91E,0x7FE,0x6DF,0x5C6,0x4BB,
0x3C4,0x2E9,0x22D,0x196,0x128,0xE4,0xCE,0xE4,
0x128,0x196,0x22D,0x2E9,0x3C4,0x4BB,0x5C6,0x6DF
};
UINT8 sine_index = 0; // pointer into sine table
//-------------------------------------- INT_TIMER1 ---------------------------
//
#int_timer1
void SineTime()
{
dac_write( 1, SINE_WAVE[sine_index] ); // selecting comparator 1.
if(++sine_index==SINE_STEPS) {
sine_index=0;
}
output_toggle( PIN_B5 ); // verify timing with OScope here
}
//------------------------------------- main() ---------------------------------
void main()
{
setup_adc_ports( NO_ANALOGS);
setup_comparator_dac(COMP_COMMON_DAC_ENABLE | COMP_FILTER_CLK_DIV_1 | COMP_DAC_CLK_DIV_1 | COMP_DAC_CLK_SRC_FVCODIV); //This is the fastest clock settings.
setup_comparator_slope (1, COMP_DISABLE_SLOPE_FUNCTION, 0); //manual setting not slope
setup_comparator(1, COMP_DAC_CMPXA | COMP_OUTPUT_DAC ); //select this comparator to use DAC, and output it. .
setup_timer1( TMR_INTERNAL | TMR_DIV_BY_1, 2499 ); // set for 40KHz interrupt
//Fed by Fosc/2, so need /2500 = 2499 for count (0..2499)
C1OUT = TRUE;
C1ENV = TRUE; //Need to add these. Enables the output.
enable_interrupts(INT_TIMER1); // for tick timer
enable_interrupts(GLOBAL);
delay_ms( 500 ); // allow serial port to warm up :)
fprintf(JGSDBG,"\r\n%s %s %s\r\n",__FILENAME__, __DATE__, __TIME__);
while( TRUE ){
delay_ms( 500 );
output_toggle( LED0 );
}//end of BIG LOOP
}//end of main()
|
As you can see I've tweaked the output table to produce legal values,
and changed the timer code to give the correct tick without loading a value.
(On the DSPIC's you can set the timer to actually 'tick' at an exact
frequency). Added the extra output enables.
On 5.103, this produces exactly the same register values that MicroChip
says are needed to output a DAC value. Hopefully will work. ![Very Happy](images/smiles/icon_biggrin.gif) |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|