• AVR Freaks

Hot!12LF1840 Wake from Sleep with ADC ISR not working

Author
bxdobs
Junior Member
  • Total Posts : 42
  • Reward points : 0
  • Joined: 2014/10/13 18:05:44
  • Location: 0
  • Status: offline
2020/04/09 17:59:21 (permalink)
0

12LF1840 Wake from Sleep with ADC ISR not working

The mc documentation suggests that selecting the frc clock for ADC will allow the ADC to continue during sleep ... which I believe I have done + selected the 31000 Hz internal clock ... with "#define mySleep" active the code sets D5 and never comes back ... with "#define mySleep" turned off (commented out) the code works as designed.
 
The expectation is the MCU should reawake from sleep when the ADC interrupt occurs ... scoping D5 confirms that there is absolutely no activity on D5
 
MC 41441B.pdf
section 16.1.5 Interrupts
Note 2:
ADC operates during Sleep only when the Frc oscillator is selected
 
further in the same section with reference to the ADC interrupt:
If the device is in Sleep, the Interrupt will wake-up the device.
 
Thoughts?
Have I missed something?
or
is my logic possibly flawed?
 
I had originally read and restarted the ADC inside the ISR ... however, in that scenario, the logic never exited the ISR ... possibly due to the Frc being 1 to 6 uS vs the slow speed of the internal clock cycle (1/(31000/4)) 129uS suggesting the ADC conversions were being completed well before the ISR was finished causing the ADC interrupt to reenter the ISR immediately following retie()   
 
 
/* Pickit3 must be set to low programming voltage
  * PicDem LAB board Vdd must be adjusted to 3.1V
  *
  *                 12LF1840 (1.8-3.6V)
  *       3V1 Vdd {1 8} Vss
  * Dop D5 RD5 {2 7} RA0 A0 Aip (10 Bit ADC)
  * Dop D4 RD4 {3 6} RD1 D1 Dop
  *         MCLR\ {4 5} RD2 D2 Dop
  *
  * using internal 31k clock (lowest power use)
 */

//#define myTest
#define myADC
#define myDbg
#define mySleep

// automatically included #include <pic12f1840.h>
#include <pic.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#define _XTAL_FREQ 31000 // Internal Frequency of Clock

// PIC12LF1840 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable (PWRT enabled)
// RD3 Pin 4 set to MCLR\
#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 CPD = OFF // Data Memory Code Protection (Data 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 for CLKOUT pin 3)
#pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

// 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 LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)

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

#include <xc.h>
// Constants
#define AdcMaxCount 16
#define AHH 520 // ADC Hysteresis Hi value for 10bit 0-1023
#define AHL 480 // ADC Hysteresis Lo value for 10bit 0-1023

// Global Vars
uint8_t AdcCount = 0;
uint16_t AdcVal = 0;
uint16_t AdcAvgVal = 0;

union { //
 unsigned char _Flags;
 struct {
   unsigned B0 : 1; // ADCF
   unsigned B1 : 1;
   unsigned B2 : 1;
   unsigned B3 : 1;
   unsigned B4 : 1;
   unsigned B5 : 1;
   unsigned B6 : 1;
   unsigned B7 : 1;
 };
} bFlags;

union { //
 unsigned char _PAV;
 struct {
   unsigned B0 : 1;
   unsigned B1 : 1; // D1
   unsigned B2 : 1; // D2
   unsigned B3 : 1; // MCLR\ (READ ONLY)
   unsigned B4 : 1; // D4
   unsigned B5 : 1; // D5
   unsigned B6 : 1;
   unsigned B7 : 1;
 };
} bPAV;

#define D1 bPAV.B1
#define D2 bPAV.B2
#define D4 bPAV.B4
#define D5 bPAV.B5
#define PAV bPAV._PAV
#define ADCF bFlags.B0
#define FLAGS bFlags._Flags

// -------------------------- Main() Start ------------------------------------

void main(void) {
 OSCCONbits.IRCF = 0b0000; // 31 kHz Internal Osc
 OSCCONbits.SCS = 0b00; // clock set in FOSC<2:0> in Config 1

 TRISAbits.TRISA0 = 1; // RD1 Digital Input on Pin 7
 ANSELAbits.ANSA0 = 1; // RA0 Analog Input on Pin 7 (10 Bit ADC)
 TRISAbits.TRISA1 = 0; // RD1 Digital Output on Pin 6
 TRISAbits.TRISA2 = 0; // RD2 Digital Output on Pin 5
// TRISAbits.TRISA3 = 0; // RD3 is READ ONLY on Pin 4
 TRISAbits.TRISA4 = 0; // RD4 Digital Output on Pin 3
 TRISAbits.TRISA5 = 0; // RD5 Digital Output on Pin 2
 
#ifdef myTest
 PAV = 32;

#else
 // init/config
 D1 = 1;
 D2 = 1;
 D4 = 1;
 D5 = 1;
 
 FVRCONbits.FVREN = 0; // FVR Disabled
 // FVRCONbits.ADFVR = 0b01; // ADC FVR 1x 1.024V
 // FVRCONbits.ADFVR = 0b10; // ADC FVR 2x 2.048V
 // FVRCONbits.FVRRDY = 1; // ADC FVR Ready

 ADCON1bits.ADFM = 1; // ADC VALUE Right Adjust
 ADCON1bits.ADCS = 0b111; // CLOCK SOURCE FRC 1.0-6.0us (to allow for use in sleep mode)
 ADCON1bits.ADPREF = 0b00; // Vref connected to Vdd

 ADCON0bits.CHS = 0b00000; // Select AN0
 ADCON0bits.ADON = 1; // ADC Enable
    
 ADCF = 0;
 AdcCount = 0;
 AdcVal = 0;
    
 INTCONbits.GIE = 1; // Global Internet Enable
 INTCONbits.PEIE = 1; // Peripheral Internet Enable
    
 PIE1bits.ADIE = 1; // ADC Enable Interrupt
 
 // Start ADC
 ADCON0bits.ADGO = 1; // Start ADC
#endif

 while ( true ) { // Main loop forever

#ifndef myTest

#ifdef myDbg
  // external debug Flag to show activity
  D5 = ~D5;
#endif

  if ( ADCF == 1) {// is ADC complete?
    AdcVal = AdcVal + ADRES;
    AdcCount++;
    ADCF = 0;
    ADCON0bits.ADGO = 1; // restart ADC
  }
  
  if ( AdcCount >= AdcMaxCount ) { // Calc ADC Average
   AdcAvgVal = AdcVal / AdcCount;
   AdcVal = 0;
   AdcCount = 0;
   
   if( AdcAvgVal >= AHH ) {
    D4 = 1; // actual intended output from Hysteresis Check
   } else if ( AdcAvgVal <= AHL ) {
    D4 = 0; // actual intended output from Hysteresis Check
   }

#ifndef myDbg
   PORTA = PAV; // update I/O
#endif
  } // Calc ADC Average
#ifdef myDbg
  PORTA = PAV; // update I/O under debug
  __delay_ms(10); // add 10mS delay for debug with scope
#endif

#ifdef mySleep
  //SLEEP(); // intended sleep location
  asm("sleep");
  asm("nop");
#endif
  
#endif

 /* test block
  // D5 32
  // D4 16 Clock out
  // D3 8 MCR\
  // D2 4
  // D1 2
  // D0 1
 */

#ifdef myTest // sequential led stepping test to validate MCU
  if( PAV >= 32) {
   // PAV = 1; // RA0 is set to Analog ADC input
   PAV = 2;
  }
  else {
   PAV = PAV << 1;
   if( PAV == 8) { // RD3 is Read ONLY so need to skip 0x08
    PAV = 16;
   }
  }
  PORTA = ~PAV; // invert for Gnd activated test leds
  
   __delay_ms(500); // 1/2 Sec Delay

#endif // end of test block
     
 } // while
return;
} // main()
// -------------------------- Main() End -------------------------------------

// -------------------------- ISR() Start ------------------------------------
#ifndef myTest
void __interrupt () isr (void) { // Interrupt Service Routine

#ifdef myADC
 if ( PIR1bits.ADIF == 1 ) {
  ADCF = 1;
  PIR1bits.ADIF = 0; // clear ADC interrupt flag

#ifdef myDbg
  // external Debug activity flag
  D2 = ~D2;
#endif // myDbg

 } // ADC
#endif // my Adc
 
#ifdef myDbg
 // external Debug activity flag
 D1 = ~D1;
 PORTA = PAV;
#endif // myDbg
 
} // return from isr()
#endif // myTest
// -------------------------- ISR() End --------------------------------------

#1

15 Replies Related Threads

    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11813
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/09 18:07:39 (permalink)
    +1 (1)
    The ADC in sleep feature means you can start a conversion, then immediately go to sleep, and be awakened when the conversion completes.  It doesn't appear that's what you're doing.
    #2
    bxdobs
    Junior Member
    • Total Posts : 42
    • Reward points : 0
    • Joined: 2014/10/13 18:05:44
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 00:21:30 (permalink)
    0
    Added Timer1 with an interrupt but it also doesn't wake up from sleep ... per documentation, Timer0 and 2 won't update during sleep but in certain configurations (using the 31000 internal clock) Timer 1 is supposed to keep working and wake up? Not certain what I am doing wrong.
     
    Have added a 500k and 4M internal clock logic which might not work in sleep mode but curious if anyone can suggest a way to stop the output jitter caused by the Timer Interrupt  ... if I can't get sleep to work then may have to use Timer 2 as it has an option to automatically reset the TMR2 register ... I wrote an RS232C UART simulator in {ASM} for the 16C84 some time ago which basically counted the instruction cycles during the interrupt then added that count as an offset to next timer count to minimize the baud rate jitter ... tried various methods including turning on and off timer 2 inside the ISR ... the best result I have thus far is to immediately reset the Timer1 IF then reset the TMR1 value with a fixed Value (tested for 10 Hz) + an Offset (the number of instructions required to update the TMR1)
     
     
    /* Pickit3 must be set to low programming voltage
      * PicDem LAB board Vdd must be adjusted to 3.1V
      *
      * 12LF1840 (1.8-3.6V)
      * 3V1 Vdd {1 8} Vss
      * Dop D5 RD5 {2 7} RA0 A0 Aip (10 Bit ADC)
      * Dop D4 RD4 {3 6} RD1 D1 Dop
      * MCLR\ {4 5} RD2 D2 Dop
      *
      * using internal clock
      * 31,000 (lowest power use)
      * 4,000,000
      *
     */

    #define my4M // 4 MHz internal ... comment out for 31 kHz internal
    #define myTimer
    #define myADC
    #define myDbg
    //#define mySleep
    //#define myTest
    //#define myTest2

    #ifdef my4M
    //#define _XTAL_FREQ 500000 // Internal Frequency of Clock
    #define _XTAL_FREQ 4000000 // Internal Frequency of Clock

    //#define FMS 0xE796 // 9.234 Hz ( Prescale 8 )
    //#define FMS 0xE7A0 // 10.00 Hz ( Prescale 8 )
    #define FMS 0x3D00 // 10.00 Hz (Prescale 1)
    #else // my4M
    #define _XTAL_FREQ 31000 // Internal Frequency of Clock
    //#define FMS 0xF9F2 // 9.116 Hz
    #define FMS 0xFA82 // 10.00 Hz
    #endif

    // PIC12LF1840 Configuration Bit Settings
    // 'C' source line config statements
    // #pragma config statements should precede project file includes.
    // Use project enums instead of #define for ON and OFF.

    // CONFIG1
    #pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
    #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
    #pragma config PWRTE = ON // Power-up Timer Enable (PWRT enabled)

    /* RD3 Pin 4 set to MCLR\ */
    #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 CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
    #pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)

    // CLKOUT is ALWAYS FOSC/4
    //#pragma config CLKOUTEN = ON // Clock Out Enable (CLKOUT function is enabled for CLKOUT pin 3)
    #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled for CLKOUT pin 3)
    #pragma config IESO = OFF // Internal/External Switchover (Internal/External Switchover mode is disabled)
    #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

    // 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 LVP = ON // Low-Voltage Programming Enable (Low-voltage programming enabled)

    // Includes
    #include <xc.h>
    // automatically included #include <pic12f1840.h>
    #include <pic.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>

    // Constants
    #define AdcMaxCount 16
    #define AHH 520 // ADC Hysteresis Hi value for 10bit 0-1023
    #define AHL 480 // ADC Hysteresis Lo value for 10bit 0-1023

    // Global Vars
    uint8_t AdcCount = 0;
    uint8_t T1Count = 0;
    uint16_t AdcVal = 0;
    uint16_t AdcAvgVal = 0;

    union { //
     unsigned char _Flags;
     struct {
       unsigned B0 : 1; // ADCF
       unsigned B1 : 1; // STATE
       unsigned B2 : 1;
       unsigned B3 : 1;
       unsigned B4 : 1;
       unsigned B5 : 1;
       unsigned B6 : 1;
       unsigned B7 : 1;
     };
    } bFlags;

    union { //
     unsigned char _PAV;
     struct {
       unsigned B0 : 1;
       unsigned B1 : 1; // D1 4 Hz 12.5% duty cycle when D2 is Lo
       unsigned B2 : 1; // D2 = Lo -> D1 = on D2 = Hi -> D1 = off
       unsigned B3 : 1; // MCLR\ (READ ONLY)
       unsigned B4 : 1; // D4 main() activity (Debug mode only)
       unsigned B5 : 1; // D5 50 mS Timer activity (Debug mode only)
       unsigned B6 : 1;
       unsigned B7 : 1;
     };
    } bPAV;

    #define D1 bPAV.B1
    #define D2 bPAV.B2
    #define D4 bPAV.B4
    #define D5 bPAV.B5
    #define PAV bPAV._PAV
    #define ADCF bFlags.B0
    #define STATE bFlags.B1
    #define FLAGS bFlags._Flags

    // -------------------------- Main() Start ------------------------------------

    void main(void) {
     // Set Internal Clock Frequency
    #ifndef my4M
     OSCCONbits.IRCF = 0b0000; // 31 kHz Internal Osc
    #else
     //OSCCONbits.IRCF = 0b0111; // 500 kHz Internal Osc
     OSCCONbits.IRCF = 0b1101; // 4 MHz Internal Osc
    #endif
     OSCCONbits.SCS = 0b00; // use FOSC<2:0> = INTOSC in Config 1

     // OSCTUNE only works for the 500 kHz Osc (and it's multiples) 31 k excluded
     // MAX swing @ 500 k is around +/- 15 k (485 - 515 k)
     //OSCTUNE=31; // Max + Freq swing
     //OSCTUNE=0; // Uses Factory Setting
     //OSCTUNE=63; // -1 at room temp this was slightly better then factory
     //OSCTUNE=32; // Max - Freq swing @ 500 kHz ->
     
    #ifdef myTest
     TRISAbits.TRISA0 = 0;
    #else
     TRISAbits.TRISA0 = 1; // RD1 Digital Input on Pin 7
     ANSELAbits.ANSA0 = 1; // RA0 Analog Input on Pin 7 (10 Bit ADC)
    #endif
     TRISAbits.TRISA1 = 0; // RD1 Digital Output on Pin 6
     TRISAbits.TRISA2 = 0; // RD2 Digital Output on Pin 5
    // TRISAbits.TRISA3 = 0; // RD3 is READ ONLY on Pin 4
     TRISAbits.TRISA4 = 0; // RD4 Digital Output on Pin 3
     TRISAbits.TRISA5 = 0; // RD5 Digital Output on Pin 2
     
    #ifdef myTest
     D5 = 0;
     D4 = 1;
     D2 = 1;
     D1 = 1;

    #else
     // init/config
     D1 = 1;
     D2 = 1;
     D4 = 1;
     D5 = 1;

     INTCONbits.GIE = 1; // Global Internet Enable
     INTCONbits.PEIE = 1; // Peripheral Internet Enable
     
    #ifdef myADC
     
     ADCON1bits.ADFM = 1; // ADC VALUE Right Adjust
     ADCON1bits.ADCS = 0b111; // CLOCK SOURCE FRC 1.0-6.0us (allow sleep usage)
     ADCON1bits.ADPREF = 0b00; // Vref connected to Vdd

     ADCON0bits.CHS = 0b00000; // Select AN0
     ADCON0bits.ADON = 1; // ADC Enable
     
     FVRCONbits.FVREN = 0; // FVR Disabled
    // FVRCONbits.ADFVR = 0b01; // ADC FVR 1x 1.024V
    // FVRCONbits.ADFVR = 0b10; // ADC FVR 2x 2.048V
    // FVRCONbits.FVRRDY = 1; // ADC FVR Ready
     
     ADCF = 0; // Clear ADC Flag
     STATE = 0; // Set State to Down
     AdcCount = 0; // Clear ADC Counter
     AdcVal = 0; // Clear ADC Value
        
     PIE1bits.ADIE = 1; // ADC Enable Interrupt
     
    // Start ADC
     ADCON0bits.ADGO = 1; // Start ADC
    #endif // myADC

    #ifdef myTimer
    #ifdef my4M
     T1CONbits.TMR1CS = 0b00; // Select FOSC/4 Clock
    // T1CONbits.T1CKPS = 0b11; // Select Prescale 1:8
     T1CONbits.T1CKPS = 0b00; // Select Prescale 1:1
    #else
     T1CONbits.TMR1CS = 0b01; // Select FOSC Clock
     T1CONbits.T1CKPS = 0b00; // Select Prescale 1:1
    #endif
     T1CONbits.nT1SYNC = 1; // Select SYNC off
     T1CONbits.T1OSCEN = 0; // Turn off Timer 1 OSC
     T1GCONbits.TMR1GE = 0; // Turn off Timer 1 Gate Enable
     TMR1 = FMS; // 50 mS count is FOSC/4 /8 /TMR1
     PIR1bits.TMR1IF = 0; // Clear Timer 1 Interrupt Flag
     T1CONbits.TMR1ON = 1; // Turn on Timer 1
     PIE1bits.TMR1IE = 1; // Enable Timer 1 Interrupt
    #endif // myTimer
             
    #endif // ! myTest

     while ( true ) { // Main loop forever

    #ifndef myTest

    #ifdef myDbg
      D4 = ~D4; // external debug activity Flag for main()
    #endif

      if ( ADCF == 1) { // is ADC complete?
       AdcVal = AdcVal + ADRES; // accumulate several readings for an average
       AdcCount++;
       
       if ( AdcCount >= AdcMaxCount ) { // Calculate ADC Average
        AdcAvgVal = AdcVal / AdcCount;
        AdcVal = 0; // Clear
        AdcCount = 0;
       
        if( AdcAvgVal >= AHH ) {
         STATE = 0;
         D2 = 1; // output of Hysteresis Check
        }
        else if ( AdcAvgVal <= AHL ) {
         STATE = 1;
         D2 = 0; // output of Hysteresis Check
        }
       }
       ADCF = 0; // Clear the ADC Completion Flag
       ADCON0bits.ADGO = 1; // restart ADC
      } // ADC Complete
      PORTA = PAV; // update I/O under debug

    #ifdef mySleep
      asm("sleep");
      //SLEEP(); // intended sleep location
      asm("nop");
    #endif
      
    #else // myTest

     /* test block
      // D5 32
      // D4 16 Clock out
      // D3 8 MCR\
      // D2 4
      // D1 2
      // D0 1
     */

    #ifdef myTest2
      D5 = ~D5;
      PORTA = PAV;
      //__delay_ms(9);
    #else
      if( PAV >= 32) {
       // PAV = 1; // RA0 is set to Analog ADC input
       PAV = 2;
      }
      else {
       PAV = PAV << 1;
       if( PAV == 8) { // RD3 is Read ONLY so need to skip 0x08
        PAV = 16;
       }
      }
      PORTA = ~PAV; // invert for Gnd activated test leds
      
       __delay_ms(500); // 1/2 Sec Delay
    #endif
    #endif // end of myTest block
         
     } // while
    return;
    } // main()

    // -------------------------- Main() End -------------------------------------

    // -------------------------- ISR() Start ------------------------------------
    #ifndef myTest
    void __interrupt () isr (void) { // Interrupt Service Routine
    #ifdef myTimer
     if (PIR1bits.TMR1IF == 1 ) {
      TMR1 = FMS + 20;
      PIR1bits.TMR1IF = 0; // reset Timer Irq Flag
    #ifdef myDbg
      D5 = ~D5;
    #endif
      T1Count++;
      
      if ( T1Count >= 80) {
       T1Count = 0;
      }
      
      if ( STATE == 0 && T1Count < 10 ) {
       D1 = 0;
      }
      else {
       D1 = 1;
      }
      
      PORTA = PAV;
      
     }
    #endif // my Timer
        
    #ifdef myADC
     if ( PIR1bits.ADIF == 1 ) {
      ADCF = 1;
      PIR1bits.ADIF = 0; // clear ADC interrupt flag
     } // ADC
    #endif // my Adc
    } // return from isr()
    #endif // myTest
    // -------------------------- ISR() End --------------------------------------

    #3
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11813
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 10:42:32 (permalink)
    +1 (1)
    (using the 31000 internal clock) Timer 1 is supposed to keep working and wake up?

     
    Where do you see that in the data sheet?  You'll need to add a crystal to TMR1 for it to run in sleep.
     
    Use timer 2  for your periodic interrupt, that's what it's made for.   Start the ADC conversion in the TMR2 interrupt handler, then go to sleep.
    #4
    bxdobs
    Junior Member
    • Total Posts : 42
    • Reward points : 0
    • Joined: 2014/10/13 18:05:44
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 13:33:21 (permalink)
    0
    The concept of Sleep is that a processor should either periodically or on some i/o stimulus, wake up, take some measurements, do any necessary I/O and go back to sleep ... in this case, the only i/o stimulus is an analog input, so would need to rely on a timer interrupt ... as T0 and 2 only use System Clock, which Sleep turns off, these Timers do not update during Sleep, meaning they can't be used to Wake up Sleep  ... Timer 1 supposedly has the ability to keep running during Sleep ... based on documentation: 9.0  POWER-DOWN MODE (SLEEP) point 5: suggests the internal 31 kHz LFINTOSC is available to some peripherals ... looking at the block diagram for Timer 1, the clock path really isn't clear ... TMR1CS shows options to internal FOSC and internal FOSC/4 which I read to be the LFINTOSC ... perhaps this should be clarified to read System Clock? ... I see the path you are suggesting via the xtern xtal configured as T1OSC ... I have a 200kHz Xtal available that I could use for this but unfortunately, this still leaves the jitter problem with the T1 reloading of TMR1 ... Hmmm ... maybe I just need to remove the ADC IRQ ... perhaps that is where the jitter component is being introduced ... the ADC value accumulations should be able to carry on in the while loop without an IRQ ... if I attach and config the xtern 200 kHz Xtal, move the adjust val to the #define FMS then T1 could be stable and work in Sleep ... although wake from Sleep may introduce some additional clock cycles that may need to be adjusted for in FMS
     
    Sleep will not work with this application if I have to use T2 to generate a stable (Jitter Free) LF clock ... the moment I use T2 to generate that clock, Sleep mode is out.  22.4 TIMER OPERATION DURING SLEEP ... Timer 2 cannot be operated while the processor is in Sleep mode. The contents of TMR2 and PR2 remain unchanged during sleep.
     
    Your suggestion to use Sleep mode during servicing a TMR2 IRQ will not work as it will cause major instability to the generated LF clock ... too bad T2 doesn't have other options for Clocking ... OR ... TMR1 have an auto reload option.
    #5
    jtemples
    عُضْوٌ جَدِيد
    • Total Posts : 11813
    • Reward points : 0
    • Joined: 2004/02/13 12:31:19
    • Location: Southern California
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 13:52:30 (permalink)
    +1 (1)
    200 kHz is far outside the supported range for the TMR1 oscillator; see parameter 48.
     
    There are PICs that will do what you want; e.g. the 16F18424 will let you enable an internal oscillator to drive TMR2 while in sleep mode.
    #6
    dan1138
    Super Member
    • Total Posts : 3484
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 14:40:56 (permalink)
    +1 (1)
    @bxdobs,
     
    You have written a lot about how you want to resolve your issue with the PIC12LF1840.
     
    I'm not really seeing the big picture of what you need to accomplish.
     
    Lacking a stable clock source any controller that provides a low power sleep operating state will have issue with jitter on the outputs. If you seek cycle accurate timing where the outputs change on the same clock edge there may be other methods you should consider. Without a better idea if what you need there is nothing that springs to mind.
    #7
    bxdobs
    Junior Member
    • Total Posts : 42
    • Reward points : 0
    • Joined: 2014/10/13 18:05:44
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 15:29:57 (permalink)
    0
    The entire code is in my last post ... needing a stable .5 sec pulse ever 4 Secs (12.5 % duty cycle) only when State is Lo ... when State is Hi there is no output  ... State is determined by the ADC Hysteresis Logic ... the key is the .5 Sec - 4 Sec timing needs to be Stable ... the only reason I was looking to use SLEEP was that this project will be working totally off Solar/Battery 24/7/365 so was trying to minimize Power Consumption.
     
    My original post was incomplete/premature in that it was missing the Output Timer Logic ... I am not new to PIC controllers ... have successfully used Sleep on other MCUs ... this particular MCU has me slightly stumped with its sleep options ... was kind of hoping my sharing with this forum would set me in the right direction.
     
    The code, as is, sort of works, however, it has a major jitter component which I believe may be due to the duplicity head butting of 2 separate out of sync interrupts that are chasing each other ... eliminating the ADC IRQ should prove | disprove this ... I am currently working on 3 projects, (helping my Daughter with 2 year end projects for her college degree (covid 19 online style)) so will get back to testing the IRQ theory on my project more hopefully later tonight.
     
    #8
    davea
    Super Member
    • Total Posts : 228
    • Reward points : 0
    • Joined: 2016/01/28 13:12:13
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 19:29:01 (permalink)
    0
    have a look at the CPS module, 1 pin for a cap
    as input for timer1, CCP could be used as a wake-up source and setup as "move the goal post" for timing   
    #9
    dan1138
    Super Member
    • Total Posts : 3484
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 19:58:32 (permalink)
    +1 (1)
    bxdobs
    The entire code is in my last post ... needing a stable .5 sec pulse ever 4 Secs (12.5 % duty cycle)...

    You have stated that this is the behavior you want.


    What you have not done is explain the need for precision or define what variations may be acceptable.

    In short there is no way to offer useful suggestions without more information about your practical requirements.

    You have stated you want the controller to operate from a power source supplied by a battery for an extended period of time.

    With goals of (1)low power, (2)high accuracy, (3)low cost: the answer is you can achieve any two.
    #10
    bxdobs
    Junior Member
    • Total Posts : 42
    • Reward points : 0
    • Joined: 2014/10/13 18:05:44
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 22:55:27 (permalink)
    0
    Dan ... Thanks, I fully understand
     
    For numerous reasons, I am not comfortable publicly sharing the true nature of the device ... suffice to say, Precision and Low Power are key factors ... with donating my time and experience, cost is less of an issue 
     
    AS I TOTALLY DETEST TOSSING THINGS, I basically offered to repair this commercial-grade manufactured discontinued and unsupported device that was critically damaged due to major water infiltration (Water, AH Batteries and Electronics don't play nicely together especially when UNFUSED ... WHO designs BATTERY powered stuff with NO FUSE?) ... the device's MC processor, which didn't survive its bath, was driven by a hermetically sealed/epoxy encapsulated 200kHz Xtal. The manufacturer was approached for any technical information but their only interest was in selling new devices that have no published specifications.
     
    UPDATE:
    Now have removed the ADC IRQ and applying a fixed adjustment factor to the TMR1 reload ... while there is still a slight jitter on one clock edge within a stream of cycles, this appears to only manifest an occasional duty cycle jitter instead of a frequency jitter which is what I was seeing with the prior versions of the code (ADC IRQ in) ... using a Tek 2024C (200MHz DSS) shows the resulting LF is stable which in turn produces a stable 12.5% duty cycle output signal.
     
    My next endeavor will be to use the original 200 kHz Xtal as an external T1 Clock ... then attempt to incorporate the SLEEP option again.
     
    Again thank-you everyone for your feedback
    #11
    ric
    Super Member
    • Total Posts : 26942
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/12 23:26:57 (permalink)
    +1 (1)
    When reloading the timer inside the ISR, it is much better to ADD to the value in the timer, rather than just overwriting it.
    That automatically allows for however long it takes from the timer rollover to the point where you update it.
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #12
    bxdobs
    Junior Member
    • Total Posts : 42
    • Reward points : 0
    • Joined: 2014/10/13 18:05:44
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/13 00:42:51 (permalink)
    0
    These are the steps I took:
    1) in a closed while loop just toggling one i/o I determined the ACTUAL internal System Clock frequency FOSC/4 + loop instruction count
    2) using the 500k internal Clock I adjusted the base rate to as close to FOSC/4 as possible ... for the MCU I was using, this  just required changing OSCTUNE to -1 ( 63 ) from the factory setting of 0
    3) configured Timer 1 for a 50mS 
    4) measured the resulting frequency/period on the scope
    5) looked at the actual machine code generated by XC8 and counted the number of instructions executed from the point of ISR ENTRY to the RESTART of  TIMER1 ... PIR1bits.TMR1IF = 0; (9 instructions)
    6) 9 was added to the TMR1 CONSTANT as a new TMR1 CONSTANT
    #define FSMB  0xnnnn // where nnnn is 2^16 - (Fosc/4)/(expected frequency)    1/50mS = 20 Hz
    #define FSM    0xNNNN // where NNNN is FSMB + 9 
    7) the ISR is written as:
    __interrupt() ISR() {
     if (PIR1bits.TMR1IF == 1) {
       TMR1 = FSM;             // Add next time interval less 9 instrution cycles
       PIR1bits.TMR1IF = 0;  // restart Timer
       D5 = ~D5;
       PORTA = PAV;             // PAV includes D5 as a Bit Structure
    8) confirmed that the Output of T1 is now 50mS
     
    The remaining jitter is now most likely due to ISR Latency of 3-5 Instruction Cycles ... might add another 4 to FMS to compensate for this as an average latency factor
     
     
     
     
     
     
     
     
    #13
    ric
    Super Member
    • Total Posts : 26942
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/13 01:12:15 (permalink)
    +1 (1)
    The standard way to do it, as I already mentioned is
       TMR1 += FSMB;             // Add next time interval 

    which will AUTOMATICALLY allow for the latency.
     
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #14
    bxdobs
    Junior Member
    • Total Posts : 42
    • Reward points : 0
    • Joined: 2014/10/13 18:05:44
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/13 02:13:14 (permalink)
    0
    Thks for that ... I had been on that track earlier today ... then looked back at some of my old ASM code which derailed me.
     
     
     
    #15
    dan1138
    Super Member
    • Total Posts : 3484
    • Reward points : 0
    • Joined: 2007/02/21 23:04:16
    • Location: 0
    • Status: offline
    Re: 12LF1840 Wake from Sleep with ADC ISR not working 2020/04/13 13:06:01 (permalink)
    +1 (1)
    bxdobs
    ... I am not comfortable publicly sharing the true nature of the device ... suffice to say, Precision and Low Power are key factors ...

    Without a better idea for your precision requirements these suggestions will be more generic and perhaps abstract.


    When using the PIC212F1840 it is possible to reload the TIMER1 count registers and produce a jitter free, zero drift event but it's tricky.

    Things to consider when using TIMER1:

    There is no TMR1H holding register so the count registers cannot be updated in just one instruction cycle.

    When the timer is configure to use an external clock in asynchronous count mode writes to the count registers while the timer is on can cause count errors. This usually happens due to a setup and hold violation of the clock source.

    When using TIMER1 to count from an external clock in asynchronous count mode with the controller in sleep the CCP compare function cannot be used. This function needs the system clock running to operate even when the timer is clocked from an external source.
    #16
    Jump to:
    © 2020 APG vNext Commercial Version 4.5