1
\$\begingroup\$

I'm trying to build a power controller for a battery operated device. I choose PIC12F675. The idea is putting pic in sleep mode. Wake it up with Watchdod timer approx each second. Check pin states, decide whether to switch on or off. The decision code is working as expected. But PIC does not sleep. It looks like PIC skips SLEEP() macro. Before asking this question i've made a deep research and tested everything I found. So here are the configuration:

                          ----------
                      Vdd |1      8| GND/VSS
  Dock test pin(out)  GP5 |2      7| GP0 (in) Batt Measure
  Power Fet Drive(out)GP4 |3      6| GP1 (in) Batt Measure reference voltage
  Charge Status  (in) GP3 |4      5| GP2 (in) Dock sense
                          ----------

All pins are io. No external crystal, no reset. No floating pin.

I do not observe any sleep condition, also no reset condition.

The question is what am i doing wrong that the PIC12F675 is not sleeping?

Programing platform: MPLABX + XC8 (Latest version-Free) + pickit3 Config.h

#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = ON       // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = ON      // Power-Up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = ON       // Brown-out Detect Enable bit (BOD enabled)
#pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)

#define _XTAL_FREQ  4000000        // this is used by the __delay_ms(xx) and __delay_us(xx) functions

main.c

unsigned int Read_ADC_Value(void)
{
    unsigned int ADCValue;

    ADCON0bits.GO = 1;              // start conversion
    while (ADCON0bits.GO);          // wait for conversion to finish
    ADCValue = ADRESH << 8;         // get the 2 msbs of the result and rotate 8 bits to the left
    ADCValue = ADCValue + ADRESL;   // now add the low 8 bits of the resut into our return variable
    return (ADCValue);              // return the 10bit result in a single variable
}

unsigned int Check_Dock() {
    GPIO5 = HIGH;   
    __delay_ms(5);
    unsigned int result = GPIO2;
    GPIO5 = LOW;    
    return result;
}

unsigned int Read_Batt(){
    unsigned int adc=Read_ADC_Value();
    float voltage = ADCSTEP * adc * 200.0; 
    return (unsigned int)(voltage); 
}

void main(void) {

    //Configure Watchdog to approx 1 sec
    CLRWDT();
    OPTION_REGbits.PSA = 1; //postscaler is for wdt   
    OPTION_REGbits.PS = 0x110; //postscaler 1:64

    OPTION_REGbits.nGPPU = 0; //pullups enabled
    WPU = 0xff; //enable pullups 

    TRISIObits.TRISIO0 = INPUT;   //AN0-GPIO0 - input - analog okuma için pil değeri.   
    TRISIObits.TRISIO1 = INPUT;   //AN1 -Vref    
    ANS2=0; TRISIObits.TRISIO2 = INPUT;   //GP2 <- Dock sense low=docked high=undocked
    ANS3=0; TRISIObits.TRISIO3 = INPUT;   //Charge Status   -> GP3
    TRISIObits.TRISIO4 = INPUT;    
    TRISIObits.TRISIO5 = OUTPUT;  //Dock test pin   <- GP5
    GPIO5 = LOW; //do not output anything       

    //Setup analog
    ANSELbits.ANS0 = INPUT;       //analog input 0 is used 
    ADCON0bits.ADON = 1;          //adc is on
    ADCON0bits.CHS = 0x00;        //an0 is tied to the sampler
    ADCON0bits.VCFG = 1;          //1=>use vRref pin as voltage reference, 0=> use vdd
    ADCON0bits.ADFM = 0x01;       //ADC results are right-justifed
    ANSELbits.ADCS = 0x011;       //Conversion clock = FRC internal: measurement can take till 6usec

    INTCON = 0; //disable every interrupt
    PIE1=0;
    PIR1=0;
    INTCONbits.GIE = 0;

    //Program Loop
    while (1) {
        SLEEP();
        NOP();
        INTCONbits.GPIF=0;

        unsigned char sta = 0;
        if(Read_Batt() <= BATTLOWTHRESHOLD){
            //Batt low turn everything off
            sta++;
        }         

        unsigned int isCharging = GPIO3; //0:not charging; 1: charging;
        sta+=isCharging;

        unsigned int isnotDocked = Check_Dock();         
        if(isnotDocked) { //0:docked; 1:flying   
            NOP();
        }else{
            sta++;
        }

        if(sta) {
            //disable fet
            TRISIObits.TRISIO4 = INPUT; 
            WPU4=1; //enable port pullup
        } else {
            TRISIObits.TRISIO4 = OUTPUT; 
            GPIO4 = LOW; //enable fet
        }
    }//End of: Main loop
}
\$\endgroup\$
  • 1
    \$\begingroup\$ I think Roger has found the main issue, but I'd also add a CLRWDT immediately before your SLEEP. \$\endgroup\$ – brhans Jul 20 '16 at 11:28
  • \$\begingroup\$ For CLRWDT, i tried it before and could not get different result. Datasheet says SLEEP() also clears watchdog. Since the timeout is so long, i think there is no way that WDT can catch sleep. I'll try to disable WDT and post result here. Thanks. \$\endgroup\$ – Mert Gülsoy Jul 20 '16 at 11:58
  • \$\begingroup\$ @brhans Roger's answer is the correct solution. But since SLEEP() does the same thing for my code, there is no need to use CLRWDT. Thank you. \$\endgroup\$ – Mert Gülsoy Jul 20 '16 at 20:52
7
\$\begingroup\$

You have a small typo ;-)

OPTION_REGbits.PS = 0x110; //postscaler 1:64

Should be:

OPTION_REGbits.PS = 0b110; //postscaler 1:64
                     ^
                     |

By setting to 0x110, you effectively chose a 1:1 prescaler, which meant that the watchdog would wake every 18ms by default.

\$\endgroup\$
  • 1
    \$\begingroup\$ Sir, you are a holy man! thank you. It worked as expected. \$\endgroup\$ – Mert Gülsoy Jul 20 '16 at 20:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.