Author Topic: PIC16F1847 wakeup from sleep interrupts  (Read 1453 times)

0 Members and 1 Guest are viewing this topic.

Offline VekettiTopic starter

  • Regular Contributor
  • *
  • Posts: 232
  • Country: fi
PIC16F1847 wakeup from sleep interrupts
« on: March 16, 2023, 04:32:02 pm »
Dear All,

I've got an issue with PIC16F1847 and wake up by button press from sleep. I've got button connected to RB0 and it should wake up the PIC from sleep and turn on FET by function TurnOnDisplay();. However it never gets flag FlagForBtnPress set in interrupts. I've tried to understand this from datasheet:
"On waking from Sleep, if the GIE bit is also set, the
processor will branch to the interrupt vector. Otherwise,
the processor will continue executing instructions after
the SLEEP instruction. The instruction directly after the
SLEEP instruction will always be executed before
branching to the ISR."

So I added INTCON = 0b11011000; before and after the sleep. Once it worked but when I tried removing either line it didn't go to interrupt anymore and after adding both never worked anymore. I don't understand that why it won't go to interrupt anymore. I measured the current and in sleep it draw 110uA and when I press the button 1mA so the PIC wakes up but disregards the interrupt. What's am I doing wrong? Using mikroC PRO for PIC. If I uncomment the "asm reset" line, it works from button press, so I can be sure it actually wakes up.

Interrupt:
Code: [Select]
void Interrupt(void){
    if (INTF_bit){  // Pin Interrupt happened
       INTF_bit = 0;
       FlagForBtnPress = 1;
    }
    if (IOCIF_bit) {
       IOCBF0_bit = 0;
       FlagForBtnPress = 1;
    }
}

In main loop.
Code: [Select]
  // Go to sleep
   if (FlagForSleep == 1)
   {
      if (ForceReading > 30) FlagForSleep = 0;
      else {
           Turnoffdisplay(); // Timer triggered sleep
           FlagForSleep = 0;
           INTCON     = 0b11011000;
           asm sleep;
           INTCON     = 0b11011000;
           //asm reset; // if this is uncommented, it works
      }
   }
      // Wake up from sleep and / or reset max reading
   if (FlagForBtnPress) {
      if (PORTA.f4 == 1)  {
         TurnOnDisplay();
         SetTheADC();
      }
      FlagForBtnPress = 0;
      maxForce = 0; // Reset max Force from button press
      VDetFlagPreviousStage = 0;
   }

Edit: Ok, if I set the flag directly after the sleep, it obviously works and no need to reset. But the question remains, why it won't go to the interrupt handler when it wakes up from button press? When it is normally running and pressing the button, it sets the flag in interrupt.
Code: [Select]
   if (FlagForSleep == 1)
   {
      if (ForceReading > 30) FlagForSleep = 0;
      else {
           Turnoffdisplay(); // Timer triggered sleep
           FlagForSleep = 0;
           asm sleep;
           FlagForBtnPress = 1;
      }
   }
« Last Edit: March 16, 2023, 05:18:40 pm by Veketti »
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 892
Re: PIC16F1847 wakeup from sleep interrupts
« Reply #1 on: March 16, 2023, 07:24:25 pm »
Target your specific problem by creating a simple app. Once it works in the simple, you may understand why and can apply to the full app. If you still have a problem, then you have others that can help and they will only be looking at the specific problem and not your surrounding code which is not relevant.

The nop after sleep is probably not needed in most cases, but is harmless and prevents from getting an instruction after the sleep that may cause a problem (1 instruction executes after the sleep instruction, whether gie is set or not). Also, it may be easier to skip using an interrupt as the pic will wake whether gie is set or not, just depends on what other interrupts are in use and whether gie needs to be on.

Code: [Select]
//16F1619 - turn on led d4 for 2 seconds when s1 pressed
#include <xc.h>
#include <stdbool.h>
#include <stdint.h>
#define _XTAL_FREQ 500000ul //default speed out of reset
//led D4=RA5, switch S1=RC4 (has external pullup)
void __interrupt() ISR(){ //no checking is done in this example to determine the irq cause
    TRISA5 = 0; LATA5 = 1;  //led output, on
    __delay_ms(2000);
    LATA5 = 0;              //led off
    IOCCFbits.IOCCF4 = 0;   //clear flag
}
void mySleep(){
    IOCCNbits.IOCCN4 = 1;   //RC4 irq on change negative
    INTCONbits.IOCIE = 1;   //enable ioc
    INTCONbits.GIE = 1;     //global irq's
    SLEEP();
    NOP();
}
int main(){
    while(1){
        mySleep();
    }
}
 
The following users thanked this post: Veketti

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6572
  • Country: es
Re: PIC16F1847 wakeup from sleep interrupts
« Reply #2 on: March 16, 2023, 08:06:43 pm »
First of all, any variables modified inside a ISR must be declared as volatile.
Are you doing so?
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 
The following users thanked this post: Veketti

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 16367
  • Country: fr
Re: PIC16F1847 wakeup from sleep interrupts
« Reply #3 on: March 16, 2023, 08:09:01 pm »
First of all, any variables modified inside a ISR must be declared as volatile.

Yes, very likely culprit here.

For the OP: to make sure the MCU is indeed running the ISR or not, toggle some GPIO inside of it. Contrary to optimization effects you can get with non-volatile variables, toggling a GPIO is guaranteed to be executed here.
 
The following users thanked this post: Veketti

Offline VekettiTopic starter

  • Regular Contributor
  • *
  • Posts: 232
  • Country: fi
Re: PIC16F1847 wakeup from sleep interrupts
« Reply #4 on: March 16, 2023, 09:10:27 pm »
Actually, they were not declared as volatile. That would have made sense why the same code worked earlier few years back. Compiler has updated recently and maybe they've made some optimization. But unfortunately declaring volatile didn't fix this. This is very odd. If I compile the same code twice I might get different results. One time it works, other time not.  |O
 

Offline 8goran8

  • Contributor
  • Posts: 32
  • Country: cs
Re: PIC16F1847 wakeup from sleep interrupts
« Reply #5 on: March 17, 2023, 09:33:33 am »
Can you post initialization code for your MCU?
Why do you use INT0 and RB0 Interrupt on change at the same time?
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 16367
  • Country: fr
Re: PIC16F1847 wakeup from sleep interrupts
« Reply #6 on: March 17, 2023, 11:36:57 pm »
Actually, they were not declared as volatile. That would have made sense why the same code worked earlier few years back. Compiler has updated recently and maybe they've made some optimization. But unfortunately declaring volatile didn't fix this. This is very odd. If I compile the same code twice I might get different results. One time it works, other time not.  |O

Have you toggled some GPIO inside your ISR, as suggested, to see for sure whether it actually executes it or not?
 

Offline VekettiTopic starter

  • Regular Contributor
  • *
  • Posts: 232
  • Country: fi
Re: PIC16F1847 wakeup from sleep interrupts
« Reply #7 on: March 18, 2023, 07:36:30 am »
Had to take some distance as banging head to brickwall two days with this single matter was getting my nerves. Anyhow.
8goran8 here are the initialization:
Code: [Select]
TRISA  = 0b00100100;
TRISB  = 0b10000001;
ANSELA = 0b00000000;
ANSELB = 0b00000000;
OPTION_REG = 0b10000000;
INTCON = 0b11011000;
IOCBN0_bit = 1;
And attached is picture of the project settings. I'm not sure where it writes these values set in project properties, but I guess it uses OSC* and PCON registers to write these dropdown values. There is also I2C and timer registers involved, but maybe you're not interested in them..
Originally I had only INT0 interrupt handling and now later tried also this RB0 to see whether it makes any differences. So that's why you see both, no other reason.

SiliconWizard I added GPIO toggle inside the ISR and it successfully toggled the GPIO from button press wake up.

Does this mean that there is a bug in the latest version (7.6.0) of compiler software?
« Last Edit: March 18, 2023, 07:44:04 am by Veketti »
 

Offline DavidAlfa

  • Super Contributor
  • ***
  • Posts: 6572
  • Country: es
Re: PIC16F1847 wakeup from sleep interrupts
« Reply #8 on: March 18, 2023, 12:21:57 pm »
I doubt very much it's a compiler bug. Chances you're doing something wrong are 99%.

cv007, what a terrible way of helping... 2s delay inside a ISR?? Code for a totally different pic...

Veketti, depending on the RB pin you're using, modify IOCB_TRIS , IOCB_EDGE_N and IOCB_FLAG to match the same pin...

Code: [Select]
#define IOCB_TRIS   TRISBbits.TRISB0
#define IOCB_EDGE_N IOCBNbits.IOCBN0
#define IOCB_FLAG   IOCBFbits.IOCBF0

volatile char got_ioc=0;

void init(){
    INTCON = 0;                 // Disable everything
    TRISAbits.TRISA5 = 0;       // RA5 = output (LED)
    IOCB_TRIS = 1;              // RBx = input (IOC pin)
    ANSELA = 0b00000000;
    ANSELB = 0b00000000;
    OPTION_REG = 0b10000000;
    IOCBP = 0;                  // Disable IOCB positive edges
    IOCBN = 0;                  // Disable IOCB negative edges
    IOCB_EDGE_N = 1;            // Enable IOCBx negative edge
    INTCONbits.PEIE = 1;        // Peripheral Interrupt enabled
    INTCONbits.INTE = 1;        // External Interrupt enabled
    IOCB_FLAG = 0;              // Clear IOCBx flag just in case
    __delay_ms(200);            // 200ms delay, let all the pins stabilize or you might get weird readings
    INTCONbits.GIE = 1;         // Global irqs enabled
}

void __interrupt() ISR(){
    if(IOCB_FLAG){              // Check IOCBx flag
        INTCONbits.IOCIE = 0;   // Disable IOC isr until processed
        IOCB_FLAG = 0;          // Clear IOCBx flag
        got_ioc=1;              // Indicate we got IOC ISR
    }
}

void mySleep(){
    INTCONbits.IOCIE = 1;       // enable ioc irq
    SLEEP();
    NOP();
}

void woken(){
    if(got_ioc){                // got_ioc active?       
        LATA5 = 1;              // led on
        __delay_ms(2000);       // 2s delay
        LATA5 = 0;              // led off
        got_ioc=0;              // Clear flag
    }
    else{
        for(char i=0;i<10;i++){   
            LATA5 ^= 1;         // Toggle led fast several times
            __delay_ms(100);    // 100ms delay
        }
        LATA5 = 0;              // led off
    }
}

int main(){
    init();
    while(1){
        mySleep();              // Go to sleep
        woken();                // Woke up
    }
}
« Last Edit: March 18, 2023, 01:18:09 pm by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline VekettiTopic starter

  • Regular Contributor
  • *
  • Posts: 232
  • Country: fi
Re: PIC16F1847 wakeup from sleep interrupts
« Reply #9 on: March 18, 2023, 05:43:36 pm »
Issue solved! I had two pic mcu's and the other was always in the programmer and I swapped between those two. Took a while to realize that the issue happened always with the other MCU. So it was somehow damaged. Now it's in garbage bin and never cause issue anymore.  :palm:

Thanks everybody.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf