Slightly improved code for PIC DDS

I realized my original code was delaying the PWM loop some because it was waiting on a ADC read before finishing the loop. In the code below, the ADC read is started and read the next time around. Then the next time is started again, this eliminates the delay of waiting on the ADC.


#define ADCStart ADCON0.b1 = 1 //set this bit to begin ADC conversion
const unsigned char sine[256] =
{// sine wave 8 bit resolution scaled to 90% max val
119,116,113,111,108,105,103,100, 97, 95, 92, 89, 87, 84, 82, 79,
77, 74, 72, 69, 67, 64, 62, 60, 58, 55, 53, 51, 49, 47, 45, 43,
41, 39, 37, 36, 34, 32, 31, 29, 28, 26, 25, 24, 22, 21, 20, 19,
18, 17, 16, 15, 15, 14, 13, 13, 12, 12, 12, 11, 11, 11, 11, 11,
11, 11, 11, 12, 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 19, 21,
22, 23, 24, 26, 27, 29, 30, 32, 33, 35, 37, 39, 41, 43, 45, 47,
49, 51, 53, 56, 58, 60, 63, 65, 68, 70, 73, 75, 78, 81, 83, 86,
89, 92, 94, 97, 100,103,106,108,111,114,117,120,123,126,129,130};
////////////////////////////////Global variable here//////////////////////////////////////////////
long PhaseAccum;//phase accumilator generates the cycle rate for lookup table
//loading therby changing frequency. The MSbyte is used to provide the byte address
//of the look up table value to be used.
long PhaseShift;//value added to PhaseAccum every PWM cycle. This makes the waveform
//lookup faster or slower – which changes frequency.
////////////////////////////////PIC Config routine here////////////////////////////////////
void Init_Main(){
//PIC12F1822 specific config
OPTION_REG = 0b10000000; // disable internal pull ups
OSCCON = 0b11110000; //8MHz clk //32Mhz pll
TRISA = 0b00011000; // configure IO/a2d(gpio0) and mclr set as inputs
T2CON = 0b00000100;// TMR2 ON, postscale 1:1, prescale 1:1
PR2 = (0x50);// sets PWM rate to approx 98.5KHz with 32Mhz internal oscillator
CCP1CON = 0b00001111;// CCP1 ON, and set to simple PWM mode
PhaseShift = 0x00FFFFFF;//frequency values loaded into
ANSELA = 0b00010000; //select RA4 as A2D input 32Mhz clk
ADCON0 = 0b00001101; // configure ADC
ADCON1 = 0b00100000; // configure ADC
////////////////////////////main program loop here/////////////////////////////////
void main() {
Init_Main();//configue part
while(1){ //alway do this
while(!PIR1.TMR2IF);// wait for TMR2 cycle to restart
CCPR1L = (sine[((char *)&PhaseAccum)[3]]) >> 2;// load MSbits 7-2 duty cycle value into CCPRIL
CCP1CON ^=((sine[((char *)&PhaseAccum)[3]]) & 0x03) << 4;// load in bits 1-0 into 5 and 4 of CCP1CON
//////duty cycle value byte is now loaded for next cycle comming//////
if(PIR1.ADIF == 0)ADCStart; //start ADC here to get value into PhaseShift to change Freq
//will have to go around the loop one time before ready flag is high
if(PIR1.ADIF){ //if ADC read complete load values and clear flag
((char *)&PhaseShift)[1] = ADRESL; //load ADRESL into PhaseShift
((char *)&PhaseShift)[2] = ADRESH; //load ADRESH into PhaseShift
PIR1.ADIF = 0;//clear flag so next time ADC canΒ run
PhaseAccum = PhaseAccum + ((PhaseShift << 5) + 1); //move PhaseAccum through waveform values
//”<<5″ can be more or less and sets the frequency sweep range
// the +1 is just so there is never 0;
porta.b0 = ((char *)&PhaseAccum)[3].b7;
PIR1.TMR2IF = 0; // clear TMR2 int flag


18 thoughts on “Slightly improved code for PIC DDS

  1. I would like to put my own values into a variable that I can set for specific frequencies. This would be in place of the value of the ADC. I would like to program in 7.83Hz exactly.

    I imagine that typing in a distinct value for ADRESL and ADRESH would do the trick?

    What value would I use in this code:

    ((char *)&PhaseShift)[1] = ADRESL; //load ADRESL into PhaseShift
    ((char *)&PhaseShift)[2] = ADRESH; //load ADRESH into PhaseShift

    Thanks for your help!
    Russ πŸ™‚

  2. the best thing would be to comment out all of the ADC related lines of code:

    then use something like this:
    PhaseAccum = PhaseAccum + PhaseShift //move PhaseAccum through waveform value
    this line already exists but you can modify to make Phaseshift a long (4 byte) constant just load in whatever value you want in your initialization

    I think the value you will want in Phaseshift will roughly 269037 for 7.83 Hz ……7.83Hz/(1/(.000008 * 2^32)) -> where 8 uSec is the period of the PR2 time of 125KHz

    also in the init_main() make PR2 = 40 not 50 the cycle rate will be 125Khz…it will perform better.

    • Wow!!! Thanks for your help!
      I will do just that and test it out. πŸ™‚

      I need to find a C compiler as I have never worked in C. Can you recommend one?

      I use MELABs PIC Basic Pro and there USB PIC Programmer. So, I can easily flash a HEX code to the PIC.

      Thanks for the speedy response and THANK-YOU for this great circuit!!!!!

      • Thanks so much for your circuit and code. I am stocked! It is brilliantly simple and performs perfectly!!!
        I am now thinking about adding a push-button interface where I can scroll through a pre-set frequencies. So, I can see using one Port for the pushbutton, and the remaining 4 Ports outputting a 4-bit word that I can then decode to 1 of 16 states using 16 LEDs to indicate what frequency I have selected. That type of thing.

        Problem is I no nothing about C language!


  3. Are you asking me rewrite the code? I don’t have a dev board or the compiler tools to do that. For ATTiny micros that support pwm(not sure about the 85?) the PWM is handled differently so the code would have to be changed with regard to the PWM config registers and how you actually load the PWM value register but those parts will work fine. Of course the IO definitions also have to change but it should only take a few hours to get working.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s