• AVR Freaks

Hot!MCU consumes high current in sleep mode if SCS1 isn't set

Author
pajuhesh80
Super Member
  • Total Posts : 101
  • Reward points : 0
  • Joined: 2019/12/08 11:23:37
  • Location: Nowshahr, Mazandaran, Iran
  • Status: offline
2020/08/05 05:57:21 (permalink)
0

MCU consumes high current in sleep mode if SCS1 isn't set

To save power while USB suspend mode, I put MCU (PIC18F14K50) in sleep (IDLEN = 0) mode. So all clock sources should be disabled. Main clock source is 12Mhz HS crystal oscillator.
However, if I set SCS1 bit (switch from primary to internal clock), MCU consumes even less power during sleep. Why this happens? I tried clearing SPLLEN and set PRI_SD before sleep but had no effect.
 

Slow and Steady!
#1

3 Replies Related Threads

    pajuhesh80
    Super Member
    • Total Posts : 101
    • Reward points : 0
    • Joined: 2019/12/08 11:23:37
    • Location: Nowshahr, Mazandaran, Iran
    • Status: offline
    Re: MCU consumes high current in sleep mode if SCS1 isn't set 2020/08/07 01:10:22 (permalink)
    0
    I found something: Above situation only happens when I enter sleep in an ISR. I put sleep somewhere out of ISR for testing. Current consumption reduced to 600µA (my multimeter battery is near empty so values may be inaccurate). Then I put it in "void __interrupt() INTERRUPT_InterruptManagerHigh (void)" to go to sleep before servicing any interrupt. Current consumption increased to 2mA in sleep mode. Then set SCS1 before sleep and current consumption again reduced to 600µA.
    What is going on? I read Oscillator Module and Interrupts in datasheet but didn't find anything related.

    Slow and Steady!
    #2
    dan1138
    Super Member
    • Total Posts : 3843
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: MCU consumes high current in sleep mode if SCS1 isn't set 2020/08/08 21:32:30 (permalink)
    0
    pajuhesh80
    I found something: Above situation only happens when I enter sleep in an ISR. I put sleep somewhere out of ISR for testing. Current consumption reduced to 600µA (my multimeter battery is near empty so values may be inaccurate). Then I put it in "void __interrupt() INTERRUPT_InterruptManagerHigh (void)" to go to sleep before servicing any interrupt. Current consumption increased to 2mA in sleep mode. Then set SCS1 before sleep and current consumption again reduced to 600µA.
    What is going on? I read Oscillator Module and Interrupts in datasheet but didn't find anything related.



    It is not possible to enter sleep mode when an enabled interrupt source has asserted an interrupt flag.
     
    This is the case even when the GIE bit in the INTCON register is zero.
     
    Without seeing your test code I cannot say that this is your problem. It is likely that you have more issues that need to be addressed.
     
    This code uses just 1.9 microamps when in sleep:
    /*
     * File:   main.c
     * Author: dan1138
     * Target: PIC18F14K50
     * Compiler: XC8 v2.20
     * IDE: MPLABX v5.40
     *
     * Created on August 8, 2020, 9:18 PM
     *
     *                         PIC18F14K50
     *              +--------------:_:--------------+
     *    5v0 ->  1 : VDD                       VSS : 20 <- GND
     *        <>  2 : RA5               PGD/AN0/RA0 : 19 <> PGD
     *        <>  3 : RA4/AN3           PGC/AN1/RA1 : 18 <> PGC
     *    VPP ->  4 : RA3/VPP                  VUSB : 17 <- 3v3
     *        <>  5 : RC5/CCP1              AN4/RC0 : 16 <>
     *        <>  6 : RC4                   AN5/RC1 : 15 <>
     *        <>  7 : RC3/PGM               AN6/RC2 : 14 <>
     *        <>  8 : RC6/AN8/T1OSCI       AN10/RB4 : 13 <>
     *        <>  9 : RC7/AN9/T1OSCO   RXD/AN11/RB5 : 12 <>
     *    TXD <> 10 : RB7/TXD                   RB6 : 11 <>
     *              +-------------------------------:
     *                           DIP-20
     *
     *  Description:
     *      Test sleep mode current.
     */
    #pragma config CPUDIV = NOCLKDIV// CPU System Clock Selection bits (No CPU System Clock divide)
    #pragma config USBDIV = OFF     // USB Clock Selection bit (USB clock comes directly from the OSC1/OSC2 oscillator block; no divide)
    #pragma config FOSC = IRC       // Oscillator Selection bits (Internal RC oscillator)
    #pragma config PLLEN = OFF      // 4 X PLL Enable bit (PLL is under software control)
    #pragma config PCLKEN = ON      // Primary Clock Enable bit (Primary clock enabled)
    #pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled)
    #pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
    #pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
    #pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
    #pragma config BORV = 19        // Brown-out Reset Voltage bits (VBOR set to 1.9 V nominal)
    #pragma config WDTEN = ON       // Watchdog Timer Enable bit (WDT is always enabled. SWDTEN bit has no effect.)
    #pragma config WDTPS = 2048     // Watchdog Timer Postscale Select bits (1:2048)
    #pragma config HFOFST = OFF     // HFINTOSC Fast Start-up bit (The system clock is held off until the HFINTOSC is stable.)
    #pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RA3 input pin disabled)
    #pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
    #pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
    #pragma config BBSIZ = OFF      // Boot Block Size Select bit (1kW boot block size)
    #pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
    #pragma config CP0 = OFF, CP1 = OFF, CPB = OFF, CPD = OFF
    #pragma config WRT0 = OFF, WRT1 = OFF, WRTC = OFF, WRTB = OFF
    #pragma config WRTD = OFF, EBTR0 = OFF, EBTR1 = OFF, EBTRB = OFF

    #include <xc.h>
    #include <stdint.h>
    #include <stdio.h>

    #define _XTAL_FREQ (4000000ul)
    #define FCYC (_XTAL_FREQ/4L)
    /*
     * Initialize this PIC
     */
    void PIC_Init(void)
    {
        INTCON  = 0;    /* Disable all interrupt sources */
        PIE1    = 0;
        PIE2    = 0;
        
        OSCCON  = 0x50; /* INTOSC at 4MHz, Primary oscillator selected by configuration bits */
        OSCTUNE = 0x00; /* LFINTOSC 31.25 kHz, PLL disabled */
        ANSEL   = 0xFF; /* make AN0 to AN7 analog inputs */
        ANSELH  = 0xFF; /* make AN8 to AN11 analog inputs */
        TRISA   = 0xDF; /* make RA5 digital output */
        TRISB   = 0x1F; /* RB0/INT0 as input, RB1 to RB4 analog inputs */
        TRISC   = 0xC7; /* T1OSC as inputs RC0, RC1, RC2 analog inputs */
        LATA    = 0;
        LATB    = 0x80; /*Set TXD out high on POR */
        LATC    = 0;
    }
    /*
     * Set the UART baud rate
     */
    #define U1_BAUD 9600
    #define U1_BRGH_VALUE 1
    #define U1_BRG16_VALUE 1
    /*
     * Compute the value for the UART1 baud rate registers
     */
    #if U1_BRG16_VALUE
        #if U1_BRGH_VALUE
            #define U1_BRGH_SCALE 1L
        #else
            #define U1_BRGH_SCALE 4L
        #endif
    #else
        #if U1_BRGH_VALUE
            #define U1_BRGH_SCALE 4L
        #else
            #define U1_BRGH_SCALE 16L
        #endif
    #endif

    #define U1_SPBRG_VALUE ( ((FCYC + (U1_BRGH_SCALE * U1_BAUD/2)) / (U1_BRGH_SCALE * U1_BAUD))-1L )

    #if U1_BRG16_VALUE
        #if U1_SPBRG_VALUE > 65535
        #error Cannot set up UART1 for the FCY and BAUDRATE.
        #endif
    #else
        #if U1_BRGREG > 255
        #error Cannot set up UART1 for the FCY and BAUDRATE.
        #endif
    #endif
    /*
     * Check if the real baud rate is within 2.5 percent of the require baud rate
     */
    #define REAL_BAUDRATE ( FCYC / ( U1_BRGH_SCALE * ( U1_SPBRG_VALUE + 1L) ) )
    #if (REAL_BAUDRATE > (U1_BAUD + (U1_BAUD * 25L) / 1000L)) || (REAL_BAUDRATE < (U1_BAUD - (U1_BAUD * 25L) / 1000L))
    #error UART baudrate error greater than 2.5 percent for the FCY and U1_BAUD.
    #endif
    #undef REAL_BAUDRATE
    /*
     * Define bits used to initialize the UART
     */
    #define BIT_RCIE  PIE1bits.RCIE
    #define BIT_TXIE  PIE1bits.TXIE
    #define BIT_RCIF  PIR1bits.RCIF
    #define BIT_TXIF  PIR1bits.TXIF
    #define BIT_TXEN  TXSTAbits.TXEN
    #define BIT_TRMT  TXSTAbits.TRMT
    #define BIT_CREN  RCSTAbits.CREN
    #define BIT_SPEN  RCSTAbits.SPEN
    #define BIT_OERR  RCSTAbits.OERR
    #define BIT_BRG16 BAUDCONbits.BRG16
    #define BIT_BRGH  TXSTAbits.BRGH
    /*
     * Initialize UART1 for transmit only
     */
    void UART_Init( void )
    {
        BIT_RCIE = 0;           /* Disable receiver interrupt */
        BIT_TXIE = 0;           /* Disable transmitter interrupt */
        LATCbits.LATC6 = 1;     /* Make TXD a stop bit when */
        TRISCbits.TRISC6 = 0;   /* the UART is disabled */
        RCSTA = 0;              /* Reset receiver and disable UART */
        TXSTA = 0;              /* Reset transmitter */
        BIT_BRG16 = U1_BRG16_VALUE;
        BIT_BRGH = U1_BRGH_VALUE;
        SPBRG = (unsigned char)(U1_SPBRG_VALUE);
        SPBRGH = (unsigned char)(U1_SPBRG_VALUE >> 8);
        BIT_TXEN = 1;           /* Enable transmitter */
        BIT_SPEN = 1;           /* Enable UART */
    }
    /*
     * This function allows printf to send output to UART1
     */
    void putch(char data)
    {
        while(!BIT_TRMT);
        TXREG = data;
    }
    /*
     * INT0 Initialization
     */
    void INT0_Init(void)
    {
        INTCONbits.INT0IE = 0;
        INTCON2bits.INTEDG0 = 0;
        INTCONbits.INT0IF = 0;
        INTCONbits.INT0IE = 1;
    }
    /*
     * Main application
     */
    uint16_t SpinWait;
    uint16_t WakeCount;
    uint16_t INT0Count;

    void main(void)
    {
        /*
         * Application initialization
         */
        PIC_Init();
        UART_Init();
        INT0_Init();
        for(SpinWait=16000;--SpinWait;)Nop();   /* Give clocks time to stabilize */
        printf("\r\n\r\nTest wake from sleep\r\n");
        while(!BIT_TRMT);
        
        INTCONbits.GIEL = 1;
        INTCONbits.GIEH = 1;
        
        WakeCount = 0;
        INT0Count = 0;
        /*
         * Application loop
         */
        WDTCONbits.SWDTEN = 1;      /* Turn on Watchdog */
        for(;;)
        {
            printf("Enter sleep ");
            while(!BIT_TRMT);
            Sleep();
            Nop();
            for(SpinWait=16000;--SpinWait;)Nop();   /* Give clocks time to stabilize */
            if(INT0Count)
            {
                INTCONbits.INT0IE = 0;
                printf("INT0 %u ",INT0Count);
                INT0Count = 0;
                INTCONbits.INT0IE = 1;
            }

            printf("Wake from sleep %u\r\n", ++WakeCount);
            while(!BIT_TRMT);
        }
    }
    /*
     * Interrupt Service Routine handlers
     */
    void __interrupt(high_priority) ISR_high(void)
    {
        if(INTCONbits.INT0IE)
        {
            if(INTCONbits.INT0IF)
            {
                INTCONbits.INT0IF = 0;
                INT0Count++;
            }
        }
    }
    void __interrupt(low_priority) ISR_low(void)
    {
        INTCONbits.GIEL = 0;    /* there are no low priority interrupts in this application */
    }

    I suspect that you have some obscure issues with the way you have structured your application.

    Measuring the sleep mode current properly is tricky.

    Microchip demo boards can be a problem and you will need to analyze the schematic to be sure that there are no extra loads on the VDD supply to the controller.
    #3
    pajuhesh80
    Super Member
    • Total Posts : 101
    • Reward points : 0
    • Joined: 2019/12/08 11:23:37
    • Location: Nowshahr, Mazandaran, Iran
    • Status: offline
    Re: MCU consumes high current in sleep mode if SCS1 isn't set 2020/08/08 23:47:15 (permalink)
    +1 (1)
    I tried another simple code before destroying Ammeter functions of my multimeter by accidentally connecting it to 220V AC wall outlet while it was on DC 200mA ammeter mode! :-\ (fuse didn't help)
    It was a simple code generated by MCC and a little edition. MCU runs on 12MHz HS clock mode, starts timer0 (clocked by Fosc/4) and enters sleep when timer0 overflow interrupt triggered. If I entered sleep mode outside interrupt, current consumption was a little less.
    Looks like MCU keeps main clock source running without supplying it to CPU and peripherals while device is in ISR (after interrupt trigger and before RETFIE). I guessed this way because if I set SCS1, current consumption decreases like when MCU is running normally and I switch from HS oscillator to LFINTOSC.
    As I said, those values in my post may be inaccurate because:
    1. my multimeter is (actually was!) inaccurate.
    2. PICkit3 is always connected to my MCU and may drain some current. When I enable internal USB pullup (which is also connected to PGD or PGC), current consumption increases a lot.
    3. My breadboard is a little old and may cause some current leakage.
    Currently, there is no problem with current consumption for USB suspend mode. I just wonder why MCU keeps main clock running in sleep (not idle) mode in an ISR?

    Slow and Steady!
    #4
    Jump to:
    © 2020 APG vNext Commercial Version 4.5