Electronic – PIC12 DAC has no output

dacmicrocontrollerpic

I have a PIC12F1571 (datasheet here: http://ww1.microchip.com/downloads/en/DeviceDoc/40001723b.pdf) that I have programmed to read an analog input, do some processing on the value read and then ouput a related value on the onchip DAC.

For testing, I have hooked up a potentiometer to the analog input and I can see in the MPLAB debugger that the correct value is being read by the PIC (ADRESH/ADRESL are set appropriately by the ADC). I have also verified that the DAC bits are being set properly in DACCON0 and DACCON1 registers- in the debugger I can see that the DAC is getting set to the right output, but there is no voltage on the output pin.

I have double checked the direction of my TRISA register for the appropriate pins, made sure that the alternate pin function register has no conflicts and that everything else is disabled.

Code is below. I have set up the PIC so that RA4 – pin 3 (Analog Channel 3) is being used as the ADC input and RA0 – pin 7 is being used as the DAC output.

#if defined(__XC)
  #include <xc.h>         /* XC8 General Include File */
#endif

#include <stdio.h>
#include <stdlib.h>

#include <pic12f1571.h>

#define SYS_FREQ        500000L
//#define FCY             SYS_FREQ/4

//Set up using the Memory View (Window -> PIC Memory Views -> Configuration Bits
// CONFIG1
#pragma config FOSC = INTOSC       //  (ECH, External Clock, High Power Mode (4-32 MHz); device clock supplied to CLKIN pin)
#pragma config WDTE = OFF        // Watchdog Timer Enable (WDT enabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOREN = OFF    // Low Power Brown-out Reset enable bit (LPBOR is disabled)
#pragma config LVP = OFF         // Low-Voltage Programming Enable (Low-voltage programming enabled)


void setup(void)
{
 /* Configure Interrupts
 * INTCON - Interrupt Control Register:
 * Set GIE (Global Interrupt Enable)
 * Set PEIE (Peripheral Interrupt Enable bit (for ADC interrupts)
 * Set TMR0IE (Timer0 Overflow Interrupt Enable bit)
 *
 * PEI1 - Peripheral Interrupt Enable Register:
 * Set ADIE (ADC Interrupt Enable bit)
 */
    INTCON = 0xE0;
    PIE1 = 0x40;
    PIE2 = 0x00;
    PIE3 = 0x00;

/* Configure PORTA for the following:
 *
 * Configure TRISA for Port A Direction Control
 * only have 1 input pin - RA4
 * 1 output pin - RA0 (for DAC1)
 *
 * Configure ODCONA for Open-drain Control
 * PORTA configured as standard push-pull
 *
 * Configure SLRCONA for Slew Rate Control
 * Slew rate is unlimited
 *
 * Configure INLVLA for Input Threshold Control
 * Doesn't need to be set since all input is analog
 *
 * Configure ANSEL registers for ADC operation on AN3 (RA4/pin 3)
 */
    TRISA = 0x10;
    ODCONA = 0x00;
    SLRCONA = 0x00;
    INLVLA = 0x00;
    ANSELA = 0x10;

    /* Configure TIMER0
     *
     * In OPTION_REG:
     * Select Internal instruction clock
     * Select no prescaler on the timer
     *
     *  */
    OPTION_REG = 0x84;

    /* Configure ADC
     *
     * Set ADCON0 to the following:
     * CHS set to analog channel AN3 = 00011 (RA4/pin 3)
     * ADON set to ADC enabled = 1
     *
     * Set ADCON1 to the following:
     * ADFM set to left justified = 0 (so that we can get away with reading a
     *   single byte for our converted value)
     * ADCS Conversion clock source set to Fosc/8 = 001
     * ADPREF set to Vdd reference = 00
     *
     * Set ADCON2 to trigger on Timer0 overflow
     * ADCON2:TRIGSEL = 0011

     */
    ADCON0 = 0x0D;
    ADCON1 = 0x10;
    ADCON2 = 0x30;

    /* Configure up DAC
     * Set DACCON0 register:
     * DACEN set to DAC enabled = 1
     * DACOE set to voltage level output = 1
     * DACPSS<1:0> is set to Vdd = 00
     *
     * DACCON1 register contains the DACR bits (i.e. the output value)
     *
     */
    DACCON0 = 0xA0;
    DACCON1 = 0x00;

    // Set APFCON register to
    APFCON = 0xFF;
}

void interrupt isr(void)
{
    if(TMR0IF)
    {
        TMR0IF = 0; /* Clear TIMER0 Overflow Interrupt Flag*/
        //ADC will automatically start converting now

    //    ++counter;
    }

    if(ADIF)
    {   /* Clear ADC Completion Interrupt Flag */
        ADIF = 0;
        DACCON1 = ADRESH >> 3;
    }
}

int main(int argc, char** argv) {
    setup();
    while(1);
    return (EXIT_SUCCESS);
}

What am I missing? This should be easy…

Best Answer

I think the code worked all along - the problem was that the DAC would not actually output anything when the PIC was programmed for debug mode. This is because the RA0 pin is also used for ICSPDAT, so there was a conflict and I'm guessing the compiler/IDE decided not to actually output anything - I had checked that it wasn't just a pull down in the PICKit3 programmer by disconnecting the wire. Definitely an issue with programming the PIC in debug mode.

Programmed the PIC in regular mode and the DAC outputs just fine - although if the PICKit3 is left connected to the DAC output pin, the max voltage is 1/3 of Vdd. This makes sense as well.

In the end, its user error.