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 support@ccsinfo.com

- SLEEP on the 16F616 just one PIN ISR [solved]

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

- SLEEP on the 16F616 just one PIN ISR [solved]
PostPosted: Mon Feb 08, 2016 3:30 pm     Reply with quote

I am trying to put out somebody else's fire with
a 16F616-
and won't have a "working" hardware sample for another day or so.
but i do have the schemo and source code is CCS . (YEAH!)

PIC runs on INT 8 MHZ OSC - and #FUSE INTRC ( no IO funct)

the question involves sleep mode.

the fuses are set to include NOMCLR and the MCLR pin (A3) is uncommitted.

#USE FASTIO() is set for all ports and pin_A3 is TRIS'd as an INPUT but floated - no connection but to customers own ICSD jack.

BUT --
the data sheet says the NOT/MCLR pin (A3) must be pulled high in order to
enter sleep ......?


Question #1

is the NOMCLR fuse for sure the same as pulling the pin high externally?
---------------------
next:

pin_a4 is available - but set now as a debug output -
however mine for the taking to use as i see fit ..
i can easily trace jump it to a pulled-high push button already in the design.

It is trivial for me to make A4 an input -
Then after the trace jump - a4 as an input will be normally HIGH
and i can ideally use it to detect a wake up call when it goes LOW-

one of the OK-2-sleep logic requirements to ENTER sleep is that A4 is detected as HIGH
and YES i plan to add a delay function after we wake up to allow the finger on the button to release it or STAY locked low for the duration of wakefulness.


THEN there is a ( useless looking to me ) G*D Watchdog running with resets salted through out the code .... grrrrr

so when entering sleep i THINK i need to

1* set a detect point in MAIN to go to sleep under defined conditions
an when conditions are met: (including A4 currently HIGH)

2* disable watchdog timer
3* enable INT_RA4
4* enter sleep

INSIDE the INT on CHANGE A port ISR - handler

* disable further INTS ( no other INTS are used in the design so far)
* dumi read port_a to clear the int state
* restart the watchdog
* return --> to the instruction after the SLEEP in main - right ?

what i am having a devil of a time with is
getting the enable interrupt function options set correct to do the darned job
when i turn it on before executing SLEEP.

i'm unsure of the correct constants needed in setting up the
#INT_RA4 handler to get the high to low thing to work right
-----------
Q#2 ??
Can anybody knowledgeable give me a clue about optimal syntax
to correctly enable the int handler?


Last edited by asmboy on Mon Feb 08, 2016 8:16 pm; edited 1 time in total
temtronic



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

View user's profile Send private message

PostPosted: Mon Feb 08, 2016 3:54 pm     Reply with quote

re: NOMCLR

In 'regular ' use.
If the pin is tied high, then any low will reset the PIC.

NOMCLR effectively disables the 'hardware reset' function attached to the pin, allowing it to be used for I/O(some restrictions apply, gotta read the datasheets!). Without that functionality you either have to kill power to reset or run a watchdog.

As for watchdogs. they can be 'fun' depending on what the PIC has to do as you need to figure out 'worst case' timings to calculate how long the PIC can be in LALA land before it resets.

Good news is you will have the entire SOURCE code ! Hopefully you can figure out the guys 'programming style' which has to be easier than 30 year old Moto ASM code !!

Jay
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Feb 08, 2016 4:33 pm     Reply with quote

PART OF THE BRAINBURN IS THIS --
i get an invalid processor directive on the line
#INT_RA4

using 5.042

Code:

void sleepysleep(void){
                                //disable_wdt
 restart_wdt();
 enable_interrupts(GLOBAL);
 enable_interrupts(INT_RA4);
 EXT_INT_EDGE(H_TO_L);

 delay_cycles(8);
 sleep();
 delay_cycles(8);
 disable_interrupts(GLOBAL);
 delay_cycles(8);
 restart_wdt();
}


#INT_RA4

void wakeywake(void){
 byte dumi;
 disable_interrupts(GLOBAL);
 disable_interrupts(INT_RA4);
 dumi=input_a();
}
jeremiah



Joined: 20 Jul 2010
Posts: 1320

View user's profile Send private message

PostPosted: Mon Feb 08, 2016 4:38 pm     Reply with quote

I don't think there are separate interrupts for each RA pin. It is probably one single interrupt for all of them (and you enable them individually to trigger that interrupt). See if #INT_RA works?

EDIT: I am not sure the High to Low setting can be used on IOC pins. Normally it is just for external interrupt pins denoted by INT, INT1, INT2, etc. Pin A2 looks like the INT pin. You may have to do the logic in the interrupt to verify high to low.
stinky



Joined: 05 Mar 2012
Posts: 99
Location: Central Illinois

View user's profile Send private message

PostPosted: Mon Feb 08, 2016 4:52 pm     Reply with quote

I agree with Jeremiah.

Code:
enable_interrupts(INT_RA4);
enable_interrupts(INT_RA);
enable_interrupts(GLOBAL);

#INT_RA
void foo(void) {
 input_a();
}


Re: hi --> lo. I think it uses the last read it has made and looks for the opposite. Might not be interpreting that correctly.

edit: There ARE separate interrupt flags. So it is possible to wake the cpu without an interrupt handler
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Feb 08, 2016 5:04 pm     Reply with quote

and though this now compiles -it is still a bit unclear in the .LST file
if it is really the ode i want
Code:

void sleepysleep(void){

 restart_wdt();
 enable_interrupts(GLOBAL);
 enable_interrupts(INT_RA);    //should this really come before
 EXT_INT_EDGE(INT_RA4,H_TO_L); // << THIS ?
 delay_cycles(8);
 sleep();
 delay_cycles(8);
 disable_interrupts(GLOBAL);
 delay_cycles(8);
 restart_wdt();
}


#INT_RA
void wakeywake(void){
 byte dumi;
 disable_interrupts(GLOBAL);
 disable_interrupts(INT_RA);
 dumi=input_a();
}
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Feb 08, 2016 5:26 pm     Reply with quote

so then brute force on IOCA but see what .LST conveys ???
Code:

/ using IOCA directly  at 0x96 for pin RA4
#BIT useRA4=0x96.4

void sleepysleep(void){

 restart_wdt();
 enable_interrupts(GLOBAL);
 enable_interrupts(INT_RA);    //should this really come before
 USERA4=1;                     // brute force approach 
 //    EXT_INT_EDGE(INT_RA4,H_TO_L); // first arg only takes int8 
 EXT_INT_EDGE(0,H_TO_L); // << THIS ?
 delay_cycles(8);
 sleep();
 delay_cycles(8);
 disable_interrupts(GLOBAL);
 delay_cycles(8);
 restart_wdt();
}


BUT .LST is puzzling as to USERA4
Code:

.................... // using IOCA directly  at 0x96 for pin RA4
.................... #BIT useRA4=0x96.4 
.................... 
.................... void sleepysleep(void){
.................... 
....................  restart_wdt();
*
0192:  CLRWDT
....................  enable_interrupts(GLOBAL); 
0193:  MOVLW  C0
0194:  IORWF  0B,F
....................  enable_interrupts(INT_RA);    //should this really come before
0195:  BSF    0B.3 // PORTA IE enabled
0196:  MOVLW  FF // load work reg
0197:  BSF    03.5  //select bank one effectively adding 0x80 to address
0198:  IORWF  16,F // turn on ALL bits in port a INT enable  <<<<<
....................  USERA4=1;                     // brute force approach   
0199:  BSF    16.4  //  turned on again
....................  //    EXT_INT_EDGE(INT_RA4,H_TO_L); // first arg only takes int8   
....................  EXT_INT_EDGE(0,H_TO_L); // << THIS ?
019A:  BCF    01.6
....................  delay_cycles(8);
019B:  MOVLW  02
019C:  BCF    03.5
019D:  MOVWF  20
019E:  DECFSZ 20,F
019F:  GOTO   19E
01A0:  NOP
....................  sleep();


i'm at the point of using #ASM to set ONLY the RA4 edge INT


Last edited by asmboy on Mon Feb 08, 2016 6:15 pm; edited 1 time in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Feb 08, 2016 6:13 pm     Reply with quote

The bank select bit is set, prior to executing that line. This makes the
register access be to Bank 1. So it will be accessing register 0x96.
Quote:
0197: BSF 03.5
0198: IORWF 16,F
.................... USERA4=1; // brute force approach
0199: BSF 16.4 // <--- WTF ??????????????????????????????????????



As shown in bold below, INT_RA will enable all the PortA interrupts.
It's moving 0xFF to the IOCA register:
Quote:
.................... enable_interrupts(INT_RA); //should this really come before
0195: BSF 0B.3 // PORTA IE enabled
0196: MOVLW FF // load work reg
0197: BSF 03.5 //select bank one effectively adding 0x80 to address
0198: IORWF 16,F // turn on ALL bits in port a INT enable <<<<<
.................... USERA4=1; // brute force approach
0199: BSF 16.4 // turned on again

But you don't want that. You could just write 0x10 (which is bit 4)
to IOCA with one line of code. Create a #byte statement for the IOCA
register to declare the address.


Also, ext_int_edge() is for the external interrupt only. It doesn't work
with interrupt-on-change interrupts. And, the 16F616 doesn't have the
ability to set the edge for interrupt-on-change. It will interrupt on either
edge.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Feb 08, 2016 6:52 pm     Reply with quote

so i came up with this
Code:

void sleepysleep(void){

 restart_wdt();
 enable_interrupts(GLOBAL);
 enable_interrupts(INT_RA);    //should this really come before
#ASM
  MOVLW 0x10   
  ANDWF 0x96,W
#endasm
 EXT_INT_EDGE(0,H_TO_L); // << THIS ?
 delay_cycles(8);
 sleep();
 delay_cycles(8);
 disable_interrupts(GLOBAL);
 delay_cycles(8);
 restart_wdt();
}



which produces THIS:
Code:

....................  enable_interrupts(INT_RA);    //should this really come before
0195:  BSF    0B.3
0196:  MOVLW  FF
0197:  BSF    03.5
0198:  IORWF  16,F
.................... #ASM
....................   MOVLW 0x10   
0199:  MOVLW  10
....................   ANDWF 0x96,W
019A:  ANDWF  16,W
.................... #endasm
....................  EXT_INT_EDGE(0,H_TO_L); // << THIS ?
019B:  BCF    01.6
....................  delay_cycles(8);
019C:  MOVLW  02
019D:  BCF    03.5
019E:  MOVWF  20
019F:  DECFSZ 20,F
01A0:  GOTO   19F
01A1:  NOP
....................  sleep();



selecting only ONE port A pin for int handling was more fun than i thought and i wont know for sure till the hardware piece shows up.
thanks PCM !!
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Feb 08, 2016 7:34 pm     Reply with quote

Enabling global interrupts should be the last thing done in the interrupt
setup code. A couple more things should be done before you do that:
Code:

temp = input(PIN_A4);  // Clear interrupt-on-change condition
clear_interrupt(INT_RA);  // Clear the interrupt flag
enable_interrupts(GLOBAL);   


The line below can be removed from the program. It's irrelevant to
interrupt-on-change interrupts:
Quote:
EXT_INT_EDGE(0,H_TO_L);
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Feb 08, 2016 8:08 pm     Reply with quote

I am in your debt as are we all.
Thanks PCM
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Mon Feb 08, 2016 8:14 pm     Reply with quote

now all together
Code:

#INT_RA
void wakeywake(void){
 byte dumi;
 disable_interrupts(GLOBAL);
 disable_interrupts(INT_RA);
 dumi=input_a();
}


#BYTE IOCA=0x96

void sleepysleep(void){
  byte temp;
  restart_wdt();
  temp = input(PIN_A4);  // Clear interrupt-on-change condition
  clear_interrupt(INT_RA);  // Clear the interrupt flag
  enable_interrupts(INT_RA);    //should this really come before
  IOCA=0x10;                    // set ONLY RA4 for action   
  enable_interrupts(GLOBAL);   // NOW let it fire
  delay_cycles(8);            // pause
 sleep();                    // snore
 delay_cycles(8);            // wakey here
//  disable_interrupts(GLOBAL);  //  now done inside the ISR
//  disable_interrupts(INT_RA);
//  delay_cycles(8);
 restart_wdt();
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19259

View user's profile Send private message

PostPosted: Tue Feb 09, 2016 2:09 am     Reply with quote

As a couple of little comments on this:

First the INT_RAx stuff is very poorly explained. As has already been found, there is only one actual interrupt, INT_RA. So why does INT_RA4 exist?. The answer is in the IOC setting.
If you enable INT_RA4, then the compiler automatically does the IOC setting for you. However you can't 'use' RA4 as the actual name for the interrupt routine.
This is unfortunately not documented, but was found be experiment. So:
Code:

    enable_interrupts(INT_RA4);
//codes as:
0016:  BSF    0B.3  //enable the interrupt
0017:  BSF    03.5
0018:  BSF    16.4  //set bit 4 in IOCA


Then there is a little 'oops' in the use of delay_cycles(8)

The point about having a delay after the sleep, is that the instruction after this operation is 'pre-fectched', and should be a NOP.

Now 'delay_cycles(1);', codes as a NOP. So delay_cycles(8) must be better?. Answer. No.
Code:

....................  delay_cycles(8);
0019:  MOVLW  02
001A:  BCF    03.5
001B:  MOVWF  20
001C:  DECFSZ 20,F
001D:  GOTO   01C


While:
Code:

....................  delay_cycles(1);
0020:  NOP


So the way to code what is wanted here is:
Code:

void sleepysleep(void)
{
  byte temp;
  restart_wdt();
  temp = input(PIN_A4);  // Clear interrupt-on-change condition
  clear_interrupt(INT_RA);  // Clear the interrupt flag
  enable_interrupts(INT_RA4);    //This does the IOCA setting for you
  enable_interrupts(GLOBAL);   // NOW let it fire
  delay_cycles(8);            // pause
  sleep();                        // snore
  delay_cycles(1);           // Just one cycle here
  restart_wdt();
}


Have fun. Smile
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Feb 09, 2016 8:05 am     Reply with quote

i am always grateful to find how to do it better. and delighted that there are others willing to share. Thanks to you too Mr. T Idea
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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