Author Topic: PIC12F1571 ADC not working  (Read 3019 times)

0 Members and 1 Guest are viewing this topic.

Online Lion_Tamer

  • Contributor
  • Posts: 21
  • Country: gb
PIC12F1571 ADC not working
« on: January 04, 2016, 03:57:58 am »
Hi all

I am a self taught tinkerer/newbie and am working on a small project that is using a PIC12F1571 (I may switch to a PIC12F1572 if I run out of code space) as the controller in an infra-red key fob transmitter.
Due to space constraints I have to keep the physical size of the chip and associated circuitry as small as possible (yet still be able to hand solder the PCB), because of this I am trying to use one ADC pin for all 5 switches, I only ever need to be able to read one switch at a time and so I have set up a simple resister chain - see schematic. When checked with a DMM I can see that the ADC pin is receiving the input that I expect it to but I cannot get it to reliably read the ADC input if at all. (Please note that my test circuit [V1 - built on stripboard] has the switches wired to VDD and R3 to VSS - the configuration has been swapped in the V2 design to allow better low voltage reliability).

My programming environment is MPLAB X V3.15 and XC8 V1.35 with a PICKit 3 as the programmer/debuger.
Here is my code - I have been over it and the data sheet several times but can't see what is wrong - I am sure that it is probably staring me in the face but need your help to see it.

configuration_bits.c
Code: [Select]
if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

// PIC12F1571 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTOSC    //  (INTOSC oscillator; I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // 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 Disable (Low-voltage programming Disabled)

system.h
Code: [Select]
#define SYS_FREQ        250000L
#define FCY             SYS_FREQ/4

void ConfigureOscillator(void); /* Handles clock switching/osc initialization */

user.h
Code: [Select]
/******************************************************************************/
/* User Level #define Macros                                                  */
/******************************************************************************/

#define Umpire_Box
//#define Medic_Box

/* TODO Application specific user parameters used in user.c may go here */

#define VisLED_Port     LATAbits.LATA2          //Location of the Indicator LED
#define VisLED_Tris     TRISAbits.TRISA2
#define VisLED_Off      0
#define VisLED_On       1

#define IRLED_Port      LATAbits.LATA5          //Location Of the IR LED
#define IRLED_Tris      TRISAbits.TRISA5
#define IRLED_Drive     ODCONAbits.ODA5

#define IRLED_Off       1
#define IRLED_On        0

#define PWR_SW_Port     LATAbits.LATA1          //Location Of The Power Mosfet
#define PWR_SW_Tris     TRISAbits.TRISA1
#define PWR_SW_Drive    ODCONAbits.ODA1

#define OP_SW_Tris      TRISAbits.TRISA4        //Location of the input switches
#define OP_SW_Port      ANSELAbits.ANSA4
#define OP_SW_CHS       0b00011

#define PWR_On          0
#define PWR_Off         1

#define _XTAL_FREQ      250000 //This is the speed your controller is running at

void InitApp(void);         /* I/O and Peripheral Initialization */
void Setup_Switch_Read(void);
void Read_Switch_Input(void);
void half_second_delay(void);

system.c
Code: [Select]
#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */

#include "system.h"

void ConfigureOscillator(void)
{
    OSCCONbits.IRCF = 0b0110;               //250KHz Oscillator
    OSCCONbits.SPLLEN = 0;                  //4X PLL Disabled
}

main.c
Code: [Select]
#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>        /* For uint8_t definition */
#include <stdbool.h>       /* For true/false definition */

#include "system.h"        /* System funct/params, like osc/peripheral config */
#include "user.h"          /* User funct/params, such as InitApp */

int Switch;

void main(void)
{
    /* Configure the oscillator for the device */
    ConfigureOscillator();

    /* Initialize I/O and Peripherals for application */
    InitApp();

    PWR_SW_Port = PWR_On;
    __delay_ms(1);
    Setup_Switch_Read();
    //VisLED_Port = VisLED_On;
    while(1)
    {
        Read_Switch_Input();
        #ifdef Umpire_Box
        {
            if (Switch == 1)
            {
                Set_PWM3_Duty_Cycle(0x2000);
            }
            else if (Switch == 2)
            {
                Set_PWM3_Duty_Cycle(0x4000);
            }
            else if (Switch == 3)
            {
                Set_PWM3_Duty_Cycle(0x6000);
            }
            else if (Switch == 4)
            {
                Set_PWM3_Duty_Cycle(0xC000);
            }
            else if (Switch == 5)
            {
                Set_PWM3_Duty_Cycle(0xF000);
            }
            else
            {
                Set_PWM3_Duty_Cycle(0x8000);
            }
        }
        #endif
        #ifdef Medic_Box

        #endif
        __delay_ms(1000);
//        Set_PWM3_Duty_Cycle(PWM3DC + 1000);
    }

//    PWR_SW_Port = PWR_Off;
}

void Read_Switch_Input(void)
{
    PIR1bits.ADIF = 0;                  //Clear ADC Interrupt Flag
    ADCON0bits.GO_nDONE = 1;            //Start ADC Conversion
    while(ADCON0bits.GO_nDONE == 1)     //Wait for ADC Conversion to be complete
    {
        //wait for result
    }
    if (ADRESL > 224)
    {
        Switch = 1;
    }
    else if (ADRESL > 173)
    {
        Switch = 2;
    }
    else if (ADRESL > 141)
    {
        Switch = 3;
    }
    else if (ADRESL > 122)
    {
        Switch = 4;
    }
    else if (ADRESL > 96)
    {
        Switch = 5;
    }
    else
    {
        Switch = 0;
    }
}

user.c
Code: [Select]
#if defined(__XC)
    #include <xc.h>         /* XC8 General Include File */
#elif defined(HI_TECH_C)
    #include <htc.h>        /* HiTech General Include File */
#endif

#include <stdint.h>         /* For uint8_t definition */
#include <stdbool.h>        /* For true/false definition */

#include "user.h"

void InitApp(void)
{
    /* TODO Initialize User Ports/Peripherals/Project here */
    APFCONbits.P1SEL = 1;           //Set PWM1 to RA5
    CM1CON0bits.C1ON = 0;           //disable compareter module.
    ODCONA = 0x00;                  //Set Port A pins to drive and sink current
    IRLED_Drive = 1;                //Set pin as current sink only
    PWR_SW_Drive = 1;               //Set pin as current sink only
    PWR_SW_Tris = 0;                //Set as Output
    VisLED_Tris = 0;                //Set as Output
    IRLED_Tris = 0;                 //Set as Output
    Setup_PWM3();
    Set_PWM3_Period(0xFFFF);
    Set_PWM3_Duty_Cycle(0x8000);
    Start_PWM3();

    /* Setup analog functionality and port direction */

    /* Initialize peripherals */

    /* Enable interrupts */
}

void Setup_Switch_Read(void)
{
    ADCON0bits.ADON = 1;        //Enable ADC Module
    OP_SW_Tris = 1;             //Set Input switch port as input
    OP_SW_Port = 1;             //Set Pin as analog input
    ADCON0bits.CHS = OP_SW_CHS; //Select Channel for measurement
   
                                //ADC TAD Clock period should fall between 1.0 and 6.0 uS
                                //Fosc = 250KHz
                                //ADCS 0b000 = Fosc/2 which is a period of 8us <- Too long
                                //Therefore ADCS must be set to FRC = 0b111 or 0b011
   
    ADCON1bits.ADCS = 0b111;    //Set ADC Conversion clock to FRC
   
    ADCON1bits.ADPREF = 0b00;   //Set ADC voltage reference to VDD
    ADCON1bits.ADFM = 0;        //Set ADC result to right justified
    ADCON2bits.TRIGSEL = 0x0;   //Auto conversion Trigger disabled
    __delay_ms(5);              //Allow the module to settle
}

Any help that you can give will be much appreciated.

Thank you

Jem
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 4335
  • Country: gb
Re: PIC12F1571 ADC not working
« Reply #1 on: January 04, 2016, 04:38:14 am »
What are the values R3-R7?

Have you tried a cap on AN3 to ground, say 1uF?

When debugging, are you sure there's nothing leaking into the diodes, or is the header just for programming, not debugging?
 

Online Lion_Tamer

  • Contributor
  • Posts: 21
  • Country: gb
Re: PIC12F1571 ADC not working
« Reply #2 on: January 04, 2016, 05:12:14 am »
What are the values R3-R7?
R3 = 10K
R4 - R7 = 3.3K

Have you tried a cap on AN3 to ground, say 1uF?
No - I will have to give it a go.

When debugging, are you sure there's nothing leaking into the diodes, or is the header just for programming, not debugging?
The header is being used for both programming and debugging but I get the same problem even if there is nothing connected to the header.

Jem
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 1678
  • Country: fi
  • Embedded SW/HW.
Re: PIC12F1571 ADC not working
« Reply #3 on: January 04, 2016, 05:42:33 am »
See the datasheet, page 138 and 139:

http://www.microchip.com/stellent/groups/picmicro_sg/documents/devicedoc/en566612.pdf

Check your code how you configure the ADC result format justification and how you read the ADC result (ADRESH vs ADRESL).
 

Online Lion_Tamer

  • Contributor
  • Posts: 21
  • Country: gb
Re: PIC12F1571 ADC not working
« Reply #4 on: January 04, 2016, 06:21:20 am »
Check your code how you configure the ADC result format justification and how you read the ADC result (ADRESH vs ADRESL).
Assuming that I got the code correct then it should be right justified and I am only reading ADRESL - I do notice though that you have linked to a slightly newer revision data-sheet than the one that I was using and that it now mentions about disabling the weak pull up resisters so I will have to give that a go.

Jem
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 1678
  • Country: fi
  • Embedded SW/HW.
Re: PIC12F1571 ADC not working
« Reply #5 on: January 04, 2016, 06:28:12 am »
Check your code how you configure the ADC result format justification and how you read the ADC result (ADRESH vs ADRESL).
Assuming that I got the code correct then it should be right justified and I am only reading ADRESL - I do notice though that you have linked to a slightly newer revision data-sheet than the one that I was using and that it now mentions about disabling the weak pull up resisters so I will have to give that a go.

Jem

You can use the current justification and read the ADRESH instead of ADRESL, you should get correct measurements. If you do change the justification and use the ADRESL, and your signal level is too high, you will get incorrect results again.
 

Online Lion_Tamer

  • Contributor
  • Posts: 21
  • Country: gb
Re: PIC12F1571 ADC not working
« Reply #6 on: January 04, 2016, 08:32:59 am »
Looks like you may have spotted my error - I had made a not in the comments that it was justified right when in fact it was left justified.  :palm:
I haven't cracked the scope out yet to confirm that the PWM is changing as expected but watching the LED it does look like it, I had gone over it so many times that I just couldn't see it till some one else pointed it out.

I have also added the disabling of the internal pull up resistors.

It is looking like it may be sorted though I will have to test it a bit more to make sure but that is a job for another evening.

Thank you

Jem
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 4335
  • Country: gb
Re: PIC12F1571 ADC not working
« Reply #7 on: January 04, 2016, 10:01:22 am »
Well caught, Kalvin. When I saw all that code I thought I'd go for the hardware approach first, you clearly have more patience than I do.

As a learning experience, it is to always unit test your code first. And then when you have a problem as a system, split it back down to the minimum to reproduce the fault.

Even after two decades of PICs, I still unit test each and every part first before putting it together as a system.

 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 1678
  • Country: fi
  • Embedded SW/HW.
Re: PIC12F1571 ADC not working
« Reply #8 on: January 04, 2016, 10:04:53 pm »
Well caught, Kalvin. When I saw all that code I thought I'd go for the hardware approach first, you clearly have more patience than I do.

I just got lucky. If the code would have been any longer, I wouldn't have bothered to skim it through. As the code was short and simple enough it was easy to read through. Then I thought to take a quick peek into the datasheet and the ADC registers if I could find anything obvious "oops, I missed that one". It was quite easy to spot the problem from there.
 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 3203
  • Country: gb
  • Will design for cookies
Re: PIC12F1571 ADC not working
« Reply #9 on: January 05, 2016, 01:53:17 am »
IIRC the header files for some (most? all?) PICs define a register ADRES, which is 16 bits wide, so you don't have to read ADRESL and ADRESH separately. Not sure this is actually documented anywhere.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf