CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

16F1503 IOC detects L2H when none specified
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
apakSeO



Joined: 07 Dec 2016
Posts: 60
Location: Northeast USA

View user's profile Send private message

16F1503 IOC detects L2H when none specified
PostPosted: Tue Oct 10, 2017 8:09 am     Reply with quote

PIC16F1503 & CCS v5.070

I have succeeding in putting this PIC16 to sleep and waking it up via button presses. The problem I am having is that if the user holds the button down to put the PIC16 to sleep, instead of tapping it, upon releasing the button the PIC16 wakes up as if an interrupt was specified on low-to-high transition. I've only enabled an interrupt on high-to-low transitions as the PIC16 is using internal pullups, and 0V is considered the asserted state. There is no hardware, RC debounce on the input pins. A stripped-down demonstration code follows:
Code:

#include <16F1503.h>
#device PIC16F1503
#use delay(INTERNAL=16MHZ, CLOCK=2MHZ) 

#fuses NOWDT,NOPROTECT,NOBROWNOUT,NOPUT     
#fuses NOMCLR                               
#fuses NOCLKOUT                             
#fuses NOWRT                                                     
#fuses NOLPBOR                                                   
#fuses NOSTVREN                                                 
#fuses NOLVP                                                     
                         

// ***************** PROTOTYPES ******************//
void gotoSleep(void);
void exitSleep(void);

//*******************   MAIN   *******************//
void main(void)
{

    set_tris_a(0b00110000);             //  RA4 / RA5 as inputs
    port_a_pullups(0b00110000);         // Use internal pullups on RA4 / RA5
    enable_interrupts(GLOBAL);          // Enable global int to allow handler calls
   
   
    while(1)
    {     
        if(!input(PIN_A4)){             // Quick n' dirty debounce
            delay_ms(50);
            if(!input(PIN_A4)){
                delay_ms(125);
                gotoSleep();
            }
            delay_ms(125);
        }
       
        if(!input(PIN_A5)){             // Quick n' dirty debounce
            delay_ms(50);
            if(!input(PIN_A5)){
                delay_ms(125);
                gotoSleep();
            }
            delay_ms(125);
        }
             
        // Proof-of-life 50Hz signal//
        output_toggle(PIN_C0);
        delay_ms(10);
       
    }   
}
void gotoSleep(void)
{
    enable_interrupts(INT_IOC_A4_H2L);    // Enable IOC for PIN_A4 high-to-low; WORKS
    enable_interrupts(INT_IOC_A5_H2L);    // Enable IOC for PIN_A5 high-to-low; WORKS
   
    sleep();
    delay_cycles(1);                      // nop() for resume from sleep
   


void exitSleep(void)
{
    disable_interrupts(INT_IOC_A4_H2L);
    disable_interrupts(INT_IOC_A5_H2L);
}

#INT_IOC
void  IOC_isr(void)
{
    int8 portAstate;                         
    portAstate = input_a();

    if (interrupt_active(INT_IOC_A4_H2L))
    {
      clear_interrupt(INT_IOC_A4_H2L);
      exitSleep();   
    }
    if (interrupt_active(INT_IOC_A5_H2L))
    {
      clear_interrupt(INT_IOC_A5_H2L);
      exitSleep();   
    }
}



What I observe is the following: Oscilloscope probe on RC0, upon system power up I observe a 50% duty cycle 50Hz square wave as expected.

If awake, tapping RA4 or RA5 puts the PIC to sleep, as expected.
If asleep, tapping RA4 or RA5 wakes the PIC up and the RC0 signal is observed, as expected.

If awake, holding RA4 or RA5 down puts the PIC to sleep. Upon releasing the pressed button, the PIC wakes up and the signal on RC0 resumes.

Why is the PIC waking up on a low-to-high transition from RA4/RA5? I have only specified interrupts enabled on high-to-low transitions.
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Tue Oct 10, 2017 11:59 am     Reply with quote

IOC programming doesn't allow successive sets. The second overrides the first. If you want to enable two pins for IOC, the syntax is:

Code:

    enable_interrupts(INT_IOC_A4_H2L | INT_IOC_A5_H2L);   


These are not separate interrupts, but masks for the single interrupt.

You also have to clear the IOC bit for the interrupts that have triggered. This is not done for you.

Have a look at this thread where I show how this is done for RA1:

<https://ccsinfo.com/forum/viewtopic.php?p=195505>
apakSeO



Joined: 07 Dec 2016
Posts: 60
Location: Northeast USA

View user's profile Send private message

PostPosted: Wed Oct 18, 2017 6:07 pm     Reply with quote

After reading your suggestions for code changes and about a dozen threads here in relation to IOC and waking from sleep, the issue still exists. I am still seeing a wake-from-sleep occurring on a low-to-high transition, despite attempting various methods of clearing the individual IOCAF bits.

In my system, the user pushes a button which shorts RA4/RA5 to ground through a 1k resistor. This puts the system into sleep just fine, but if the user so happens to hold down the button too long ( > the debounce routine delay) the PIC16 wakes up from sleep and resumes the 50Hz proof-of-life signal. I do not understand why it is waking up from sleep, because when the user releases the buttons, RA4/5 are pulled from a low to high state, and the uC should not be waking up on such a transition.

I noticed that I did not select which edge polarity I wanted the uC to wake from, so I thought that using the function ext_int_edge(H_TO_L) would remedy this issue. Alas, it did not have any effect.

Modified code below, with my comments on various experiments I tried. Any other suggestions I may have missed?



Code:

#include <16F1503.h>
#device PIC16F1503
#use delay(INTERNAL=16MHZ, CLOCK=2MHZ) 

#fuses NOWDT,NOPROTECT,NOBROWNOUT,NOPUT     
#fuses NOMCLR                               
#fuses NOCLKOUT                             
#fuses NOWRT                                                     
#fuses NOLPBOR                                                   
#fuses NOSTVREN                                                 
#fuses NOLVP                                                     
               
// Interrupt mask bits, need to be cleared manually from IOC
#byte IOCAF = getenv("SFR:IOCAF")                 // Port A IOC register
#bit IOCAF4 = IOCAF.4                             // Individual pins
#bit IOCAF5 = IOCAF.5                             // Individual pins

// ***************** PROTOTYPES ******************//
void gotoSleep(void);
void exitSleep(void);

//*******************   MAIN   *******************//
void main(void)
{

    set_tris_a(0b00110000);             // RA4 / RA5 as inputs
    port_a_pullups(0b00110000);         // Use internal pullups on RA4 / RA5
    enable_interrupts(GLOBAL);          // Enable global int to allow handler calls
   
   
    while(1)
    {     

        if(!input(PIN_A4)){             // Quick n' dirty debounce
            delay_ms(50);
            if(!input(PIN_A4)){
                delay_ms(125);
                gotoSleep();
            }
            delay_ms(125);
        }
       
        if(!input(PIN_A5)){             // Quick n' dirty debounce
            delay_ms(50);
            if(!input(PIN_A5)){
                delay_ms(125);
                gotoSleep();
            }
            delay_ms(125);
        }
             
        // Proof-of-life 50Hz signal//
        //    means we are awake    //
        output_toggle(PIN_C0);
        delay_ms(10);
       
    }   
}//main()


void gotoSleep(void)
{
   // clear_interrupt(INT_IOC_A4_H2L);    //  no effect here
   // clear_interrupt(INT_IOC_A5_H2L);    //  no effect here
   // IOCAF = FALSE;                      //  no effect here
    // ext_int_edge(INT_EXT_H2L);         //  no effect here
    ext_int_edge(H_TO_L);                 //  Try to force interrupt on high-to-low only;    no effect here ???
    //ext_int_edge(L_TO_H);               // surprisingly, PIC16 still wakes up out of sleep with this set to L_TO_H ???
    enable_interrupts(INT_IOC_A4_H2L | INT_IOC_A5_H2L);    // Enable IOC for PIN_A4 & PIN_A5;  maskable, must be on a single line
     
    sleep();
    delay_cycles(1);                      // nop() for resume from sleep
   


void exitSleep(void)
{
    disable_interrupts(INT_IOC_A4_H2L | INT_IOC_A5_H2L);     
    //disable_interrupts(INT_IOC_A4_H2L);                    // doesn't matter if one line or separate
    //disable_interrupts(INT_IOC_A5_H2L);                    //
   
}

#INT_IOC
void  IOC_isr(void)
{
    int8 portAstate;                         
    portAstate = input_a();                  // Read to clear latches
   
    if (interrupt_active(INT_IOC_A4_H2L))
    {
        clear_interrupt(INT_IOC_A4_H2L);     // Clears the interrupt
        //IOCAF4 = 0;                        // no effect here
        //bit_clear(IOCAF, 4);               // no effect here
        IOCAF = FALSE;                       // no effect here
        exitSleep();   
    }
    if (interrupt_active(INT_IOC_A5_H2L))
    {       
        clear_interrupt(INT_IOC_A5_H2L);     // Clears the interrupt
        //IOCAF5 = 0;                        // no effect here
        //bit_clear(IOCAF, 5);               // no effect here
        IOCAF = FALSE;                       // no effect here
        exitSleep();   
    }
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Oct 18, 2017 8:35 pm     Reply with quote

Before we go any farther, add a 100 nF (0.1 uF) ceramic capacitor
between each of the two IOC input pins and ground. Does that fix it ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 12:08 am     Reply with quote

PCM_Programmer is suspecting (as I do), that in fact you are actually getting a high to low transition.

Buttons have bounce.

Almost certainly when you release the button you actually get a little sequence low-high high_low low-high etc.. Hence the interrupt triggers. I'd actually go a little smaller than this on the capacitors, even 1nF is enough to smooth bounce on most buttons. It'll prove the point though...
temtronic



Joined: 01 Jul 2010
Posts: 9255
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 5:00 am     Reply with quote

I have to agree, contact bounce. I use .68 ufd caps, aluminum electrolytics. 'Somehow' I acquired a REEL of them (5000 pcs) years ago and no matter how many I use per project, the reel still seems full, lol.

One of the most important tools you need to buy is an oscilloscope. Even if it's 30 years old, 2 channel analog, 20MHz. Being able to SEE the '1's and '0's is crucial. I've not used a PC based unit maybe cause I'm 'old school' and well, brought up on CRTs.

Jay
apakSeO



Joined: 07 Dec 2016
Posts: 60
Location: Northeast USA

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 1:02 pm     Reply with quote

Tried using a 0.1uF cap on RA5, no luck. Moved onto a 2.2uF cap on RA5, no luck either.

Using an Agilent MSO7000 series scope, 1GHz bandwidth, acquire mode set to High-Res & Realtime, I've taken 10 screen grabs of the button being pushed and 10 screen grabs of the button being released.

The yellow trace is RA5, probed at the uC pin. The green trace below it is the "I'm awake" signal in the while(1) loop ( it looks like diamonds because of aliasing.) It doesn't seem to matter if the rising edge is clean or dirty; the PIC16 stays asleep as long as the button is held down ( RA5 low ) which is expected, but wakes up upon button release, on RA5's rising edge, which is not desired.






















From this experiment and data obtained, I cannot credit the wake-from-sleep on this PIC due to contact bounce upon button release.
gaugeguy



Joined: 05 Apr 2011
Posts: 304

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 2:01 pm     Reply with quote

It is possible that the compiler may be incorrectly setting the interrupt for both high and low transitions. You can look at the assembler listing to see this.

It is possible that there is something in the chip that causes a wake from sleep regardless of which edge is set.

One solution to consider would be on a switch press to go to a low power but running state and wait for the switch to be released. Once the switch is released then go to sleep.
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 2:50 pm     Reply with quote

The fact you are showing aliasing in the I'm awake signal implies you are sampling at a very slow rate. The scope bandwidth may be high but unless you have it turned up to a reasonably fast sample rate you can easily miss things. After all you are missing the transitions in the I'm awake signal....
The interrupt can trigger off fast signals.
However with the capacitors present this shouldn't be happening, and the edges look to be reasonably slowed.

EXT_INT_EDGE, has nothing to do with IOC. This only affects INT_EXT.

A quick compile shows that your compiler version is correctly setting the direction control bits:
Code:

....................     enable_interrupts(INT_IOC_A4_H2L | INT_IOC_A5_H2L);    // Enable IOC for PIN_A4 & PIN_A5;  maskable, must be on a single line
*
004C:  BSF    0B.3 //turn on the physical IOC interrupt
004D:  MOVLW  30
004E:  MOVLB  07 //turn on bits 4 & 5 in the IOCAN register
004F:  IORWF  12,F
0050:  MOVLW  CF  //Turn off the same bits in IOCAP
0051:  ANDWF  11,F
apakSeO



Joined: 07 Dec 2016
Posts: 60
Location: Northeast USA

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 3:21 pm     Reply with quote

Faster time base:

apakSeO



Joined: 07 Dec 2016
Posts: 60
Location: Northeast USA

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 3:46 pm     Reply with quote

*.lst file contents match in asm, line for line

PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 3:49 pm     Reply with quote

I have a 16F1503. I'll test it in hardware now. Wait a bit for me to
check it with your version and the current compiler version.
apakSeO



Joined: 07 Dec 2016
Posts: 60
Location: Northeast USA

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 3:59 pm     Reply with quote

Also, I found an "IOC bug" which may or may not be contributing to this behavior I am seeing. At first glance, I do not think my issue is related to it because this issue seems to affect Port B ...

http://www.xargs.com/pic/portb-change-bug.html
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Oct 19, 2017 5:24 pm     Reply with quote

I've duplicated your symptoms. I've stripped down your program and
I still get the problem. It may take me a few hours. I've got other things
to do, so maybe later this evening I'll have an answer.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Oct 22, 2017 11:58 am     Reply with quote

I made a short test program and it shows the same results.
If you specify that IOC is for the negative edge only, the PIC will
wake up from sleep on either edge.

Discussion of results from running my test program:

Here I start with the button in the "up" position. I'm not touching
the button initially, so it reads as a logic 1 before going to sleep.
Then I press it, and the PIC wakes up. The button pin reads as "0" which
indicates the button is pressed down. This is all expected behaviour.
Quote:
Start
Button pin = 1 before going to sleep
Woke up. Button pin = 0


Next, I hold down the button down and re-start the PIC from MPLAB
(v8.92). I then release the button and the PIC wakes up. This is not
expected behavior.
Quote:
Start
Button pin = 0 before going to sleep
Woke up. Button pin = 1


So I think the PIC hardware must be designed to wake up from sleep on
either edge, even if only one edge is specified.

This was tested with CCS vs. 5.074 on a Microchip Low Pin Count board
running at +5v. The Sparkfun RS-232 level shifter board was used to
connect to my PC. The serial results were displayed on TeraTerm.
Sparkfun level shifter: https://www.sparkfun.com/products/449

Test program:
Code:
#include <16F1503.h>
#fuses INTRC_IO, NOWDT
#use delay(clock=4M)
#use rs232(baud=9600, xmit=PIN_C4)  // Software UART

#define BUTTON_PIN  PIN_A4

#byte IOCAF = getenv("SFR:IOCAF")
#bit IOCAF4 = IOCAF.4
#define clear_IOCAF4() IOCAF4 = 0
#define clear_IOCA_flags() IOCAF = 0

//---------------------------
#int_ra
void ra_isr(void)
{

clear_IOCA_flags();   
}

//==========================
void main()     
{
port_a_pullups(0x10);   // Enable pull-up on pin A4
delay_us(10);           // Allow time for weak pull-ups to get to +5v

printf("Start\n\r");

clear_interrupt(INT_RA);    // Clear any existing interrupt condition
clear_IOCA_flags();         // Clear any existing "change" condition
enable_interrupts(INT_RA4_H2L);  // Interrupt when button is pressed

enable_interrupts(GLOBAL);

printf("Button pin = %u before going to sleep\n\r", input(BUTTON_PIN));

sleep();
delay_cycles(1);

printf("Woke up. Button pin = %u\n\r", input(BUTTON_PIN));

while(TRUE);   
}
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group