pwm_dac.c - Demonstrates a PWM DACΒΆ

Demonstrates a PWM DAC - connect an RC filter on the OC1 output and vary the pulse width of the PWM signal, and monitor the DC value on the capacitor. The RC time constant should be at least 10x greater than the PWM period. Examples values used for testing were R=6.8k, C = 1.0u, PWM period= 500 us In this code, the pulse width of the PWM signal is varied by reading an analog voltage generated by a potentiomer, same as in the ledpwm.c example. So, this duplicates the input voltage on the output of the PWM DAC.

 
#include "pic24_all.h"
#include <stdio.h>



#ifndef PWM_PERIOD
#define PWM_PERIOD 500  // desired period, in us
#endif

void  configTimer2(void) {
  T2CON = T2_OFF | T2_IDLE_CON | T2_GATE_OFF
          | T2_32BIT_MODE_OFF
          | T2_SOURCE_INT
          | T2_PS_1_8 ;  //1 tick = 1.6 us at FCY=40 MHz
  PR2 = usToU16Ticks(PWM_PERIOD, getTimerPrescale(T2CONbits)) - 1;
  TMR2  = 0;       //clear timer2 value
  _T2IF = 0;
  _T2IP = 1;
  _T2IE = 1;    //enable the Timer2 interrupt
}

void configOutputCompare1(void) {
  T2CONbits.TON = 0;          //disable Timer when configuring Output compare
  CONFIG_OC1_TO_RP(RB4_RP);   //map OC1 to RB4
  OC1RS = 0;  //clear both registers
  OC1R = 0;
#ifdef OC1CON1
//turn on the compare toggle mode using Timer2
  OC1CON1 = OC_TIMER2_SRC |     //Timer2 source
            OC_PWM_CENTER_ALIGN;  //PWM
  OC1CON2 = OC_SYNCSEL_TIMER2;   //synchronize to timer2
#else
//older families, this PWM mode is compatible with center-aligned, OC1R=0
//as writes to OC1RS sets the pulse widith.
  OC1CON = OC_TIMER2_SRC |     //Timer2 source
           OC_PWM_FAULT_PIN_DISABLE;  //PWM, no fault detection
#endif
}

void _ISR _T2Interrupt(void) {
  uint32_t u32_temp;
  _T2IF = 0;    //clear the timer interrupt bit
  //update the PWM duty cycle from the ADC value
  u32_temp = ADC1BUF0;  //use 32-bit value for range
  //compute new pulse width that is 0 to 99% of PR2

pulse width (PR2) * ADC/1024

  u32_temp = (u32_temp * (PR2))>> 10 ;  // >>10 is same as divide/1024
  OC1RS = u32_temp;  //update pulse width value
  AD1CON1bits.SAMP = 1; //start next ADC conversion for next interrupt
}

int main(void) {
  uint16_t u16_oc1rs;
  uint32_t u32_pw;
  float f_dacV;
  configBasic(HELLO_MSG);
  configTimer2();
  configOutputCompare1();
  CONFIG_RA0_AS_ANALOG();
  configADC1_ManualCH0(RA0_AN, 31, 0);
  SET_SAMP_BIT_ADC1();      //start sampling and conversion
  T2CONbits.TON = 1;       //turn on Timer2 to start PWM
  while (1) {
    u16_oc1rs = OC1RS;
    u32_pw= ticksToUs(u16_oc1rs, getTimerPrescale(T2CONbits));
    f_dacV = u16_oc1rs;
    f_dacV = f_dacV * 3.3/(PR2+1);
    printf("PWM PW (us): %ld, PWM DAC voltage: %4.2f\n",u32_pw, (double) f_dacV);
    DELAY_MS(100);
  }
}