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

18F26k22 randomly not waking-up on int_rb

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



Joined: 14 Feb 2016
Posts: 24

View user's profile Send private message

18F26k22 randomly not waking-up on int_rb
PostPosted: Fri May 06, 2016 9:32 am     Reply with quote

Hello.
I have one pic with a keyboard switch on RB5.
When I press switch, led comes red. When I release it, led comes off.
But, randomly (1/100), pic not execute code above sleep, after an int_rb callback. Red led keep on, while key is released.

Here the minimal code :
Code:
#include <18F26k22.h>
#DEVICE ADC=10
#fuses INTRC_IO,NOWDT,NOCPD,NOPROTECT,NOLVP,NOMCLR,NOPUT,BROWNOUT,NOFCMEN,NOSTVREN,NOPLLEN,NOIESO,NOPBADEN,NOHFOFST,NOSTVREN,NOXINST,NODEBUG,NOCPB,NOWRT,NOWRTC,NOWRTB,NOWRTD,NOEBTR,NOEBTRB
#USE delay(clock=16000000)
#USE fast_io(A)
#USE fast_io(B)
#USE fast_io(C)

#define LED_OFF TRUE
#define LED_ON FALSE
#define   IO_LEDB PIN_C2
#define   IO_LEDR PIN_C3
#define   IO_LEDG PIN_C4

unsigned int8 ioRawBState;
int1 inputRawB(iobOffset)
{
return ((ioRawBState >> iobOffset)  & 0x01);
}

#INT_RB
void handler_rb(void)
{
// Keep port b value
ioRawBState=input_b();
}

#SEPARATE
main()
{
//           76543210
set_tris_a(0b00000111);
set_tris_b(0b10110100);
set_tris_c(0b10000000);
//               76543210
port_b_pullups(0b10110000);

// For hardware compliance
output_bit(PIN_C0,false);
output_bit(PIN_C1,false);
output_bit(IO_LEDR,LED_OFF);
output_bit(IO_LEDG,LED_OFF);
output_bit(IO_LEDB,LED_OFF);
output_bit(PIN_A3,true);
output_bit(PIN_A5,false);
output_bit(PIN_A4,false);
output_bit(PIN_A7,true);
output_bit(PIN_A6,false);

enable_interrupts(INT_RB5);
enable_interrupts(GLOBAL);
while(TRUE)
   {
   output_bit(IO_LEDG,LED_OFF);
   sleep(SLEEP_FULL);
   output_bit(IO_LEDG,LED_ON);

   // Check RB5 saved value
   if(!inputRawB(5))
      output_bit(IO_LEDR,LED_ON);
   else
      output_bit(IO_LEDR,LED_OFF);
   }
}


Green led (IO_LEDG) keep off. Then sleep full stop the execution properly.

If I move "check RB5 saved value" code into int_rb Handler code, it works perfectly. Every time I change RB5, red led (IO_LEDR) is ok. Then, I understand that int_rb is raised every time RB5 changes. But some times, int_rb does not Wake-up sleep command (randomly, I need to test one or two minutes to get error).

I should make some mistakes. But what ... I can't see.
Any idea ?
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Fri May 06, 2016 2:23 pm     Reply with quote

There are actually three different ways of working with INT_RB on different PIC's.

Oldest chips, only clear the condition when a byte wide input is done. So input_b.
Then there are some that have an erratum, and you must use 'bit' operations to clear the latch.
Then there are some that have another erratum/problem, and there must be at least one dummy instruction between the read and clearing the interrupt, and the read must not be done using MOVFF.

Yours is one of the third type.

It's hidden away in section 10.3.2 of the data sheet.....

You have to be sneaky:
So:
Code:

#INT_RB
void handler_rb(void)
{
   // Keep port b value
   ioRawBState=input_b() & 0xFF;
}


Doing the '&' makes the compiler code it as a MOVF, not a MOVFF, and add one more instruction afterwards to write the result.
tssir



Joined: 14 Feb 2016
Posts: 24

View user's profile Send private message

PostPosted: Sun May 08, 2016 2:15 pm     Reply with quote

Thank you for those informations.

I tried this codes :
Code:
#include <18F26k22.h>
#DEVICE ADC=10
#fuses INTRC_IO,NOWDT,NOCPD,NOPROTECT,NOLVP,NOMCLR,NOPUT,BROWNOUT,NOFCMEN,NOSTVREN,NOPLLEN,NOIESO,NOPBADEN,NOHFOFST,NOSTVREN,NOXINST,NODEBUG,NOCPB,NOWRT,NOWRTC,NOWRTB,NOWRTD,NOEBTR,NOEBTRB
#USE delay(clock=16000000)
#USE fast_io(A)
#USE fast_io(B)
#USE fast_io(C)

#define LED_OFF TRUE
#define LED_ON FALSE
#define   IO_LEDB PIN_C2
#define   IO_LEDR PIN_C3
#define   IO_LEDG PIN_C4

unsigned int8 ioRawBState;
int1 inputRawB(iobOffset)
{
return ((ioRawBState >> iobOffset)  & 0x01);
}

#INT_RB
void handler_rb(void)
{
// Keep port b value
ioRawBState=input_b() & 0xFF; // Correction from Ttelmah 20160506
output_bit(IO_LEDB,LED_ON);
}

#SEPARATE
main()
{
//           76543210
set_tris_a(0b00000111);
set_tris_b(0b10110100);
set_tris_c(0b10000000);
//               76543210
port_b_pullups(0b10110000);

// For hardware compliance
output_bit(PIN_C0,false);
output_bit(PIN_C1,false);
output_bit(IO_LEDR,LED_OFF);
output_bit(IO_LEDG,LED_OFF);
output_bit(IO_LEDB,LED_OFF);
output_bit(PIN_A3,true);
output_bit(PIN_A5,false);
output_bit(PIN_A4,false);
output_bit(PIN_A7,true);
output_bit(PIN_A6,false);

enable_interrupts(INT_RB5);
enable_interrupts(GLOBAL);
while(TRUE)
   {
   output_bit(IO_LEDG,LED_OFF);
   sleep(SLEEP_FULL);
   output_bit(IO_LEDB,LED_OFF);
   output_bit(IO_LEDG,LED_ON);

   // Check RB5 saved value
   if(!inputRawB(5))
      output_bit(IO_LEDR,LED_ON);
   else
      output_bit(IO_LEDR,LED_OFF);
   }
}


The problem still exists, after 3 minutes of random pushing button.

I change code to detect interrupt call. In accordance with above code, blue led keeps "on" only at start. After each push/release on button (RB5 with internal pull-up), red led is "on" then "off". In normal operation no green led (IO_LEDG) and no blue (IO_LEDB).
After many tries on pushing button, red led and blue led keeps "on" after released button.
Conclusion : Interrupt handler is called at each RB5 changes, but no wake-up some times (blue led go "off" if sleep instruction is waking).
Strangely, this problem occur only on release button event. Never at push. I.e. at low->high changes.

Then I must modify my design. Full sleep when waiting push, and idle sleep with timer to check release (active sensing).
It's insane ... but it's the only way to get reliability.
temtronic



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

View user's profile Send private message

PostPosted: Sun May 08, 2016 3:46 pm     Reply with quote

OK, go back to basic I/O 101.
What is the 'pushbutton'? Some cheap generic PB or a real PB designed for interfacing to a computer?
What kind of pullup and conditioning do you have for the PB?
What does the signal look like on a scope? Nice clean edges or 'noisy'?
Did you install a Schmitt chip in between the PB and the PIC?
Before you try any 'fancy' code, like sleeping.... confirm you get 1 input for every push of the button EVERY time. Yup, a dull boring job to do at least 1000 random presses but it has to be done.

If you can get 1000 perfect responses from your PB circuit then you've probably eliminated it as the source of 'random' failures.

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Mon May 09, 2016 12:45 am     Reply with quote

Make one other change:
Code:

   sleep(SLEEP_FULL);
   delay_cycles(1);
   output_bit(IO_LEDB,LED_OFF);


The instruction _following_ the sleep instruction, is 'prefetched'. The read of it has already started, when you go to sleep. This is why it should be a 'NOP' (delay_cycles(1) codes as a NOP in CCS). Now if it wakes and interrupts, it is actually going to be 'inside' the operation to turn the LED 'OFF', when the interrupt is called to also turn it 'ON'. Don't know the effect of this, but this is why Microchip tell you to have a NOP here....

You are also never going to see the LED go 'ON' from the interrupt, since the instruction it returns to, turns it OFF. Rather pointless bit of code.

I would echo Temtronic's comments about the actual button/circuit. 'Real' buttons do not give nice simple on/off behaviour. They give multiple (often dozens!) of edges for a switch change. Often more on release than make.

Have a look at:
<http://www.labbookpages.co.uk/electronics/debounce.html>

Use bit_test instead of inputRawB. That is why the compiler has such functions!...

Further comment though. What decoupling have you got close to the actual chip?. The symptom you actually have is not of a chip failing to wake but a chip where the code is actually hung. Probably processor spiked by RF signal into an undriven pin, or simply spiked by the current transition as it switches the LED's.
Have you got a 0.1uF right adjacent to the PIC's supply connections?. What decoupling is on the supply?. What is the supply?. What are you doing with the unused pins?.

The chip is probably doing something like toggling the various LED's on and off several times at high speed, and it is this that is resulting in things going wrong....

One thing that would give problems, if the signal is giving nasty little 'spike' bounces, is this entry in the data sheet:
"If a change on the I/O pin should occur
when the read operation is being executed
(start of the Q2 cycle), then the RBIF
interrupt flag may not get set. Furthermore,
since a read or write on a port affects all
bits of that port, care must be taken when
using multiple pins in Interrupt-on-change
mode. Changes on one pin may not be
seen while servicing changes on another
pin."

If the edge just happens to change in the instruction reading the port in the interrupt handler, then potentially you have the value in ioRawBState, not matching what is actually on the port. The interrupt will not be re-triggered, and the code will fail.
You need to process the input signal to make it give clean edges, for the code to ever really hope to work...

Given that this chip only talks about the latches being changed when a port read is done, you could potentially 'bodge' the interrupt handler like this:
Code:

#INT_RB noclear
void handler_rb(void)
{
// Keep port b value
   do
   {
      ioRawBState=input_b() & 0xFF;
      clear_interrupt(INT_RB);
   }
   while (bit_test(ioRawBState,5)!=input(PIN_B5));
}

This should then reload the ioRawState value, if the port has changed during the previous instruction. If it changes during the test, the interrupt flag will be set, so the routine will execute again (this is why the interrupt must only be cleared between the first read and the test).
This is a 'bodge' route, but could handle the situation of the input changing in the routine.

Beware though. You have three bits of RB4:7, set as inputs. If you poll the other ones of these (reading elsewhere in the code), these can potentially trigger the same problem. Much better to use these bits as outputs.


Last edited by Ttelmah on Mon May 09, 2016 8:05 am; edited 2 times in total
temtronic



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

View user's profile Send private message

PostPosted: Mon May 09, 2016 7:59 am     Reply with quote

As to Mr. T's comments about RF....
These days it is very important to bypass evry chip and input pin to eliminate any RF signal from giving false inputs! With the huge amount of 'wireless' devices around( modems,cameras,cellfones,etc) the air is not as 'clean' as it used to be. even power lines are great 'antenna'.
20 years ago had a 'semi random' PITA problem that was finally found to be 'cross talk' on a certain span pair in a certain cable in the Bell Telephone network. When I ran out of 'adjustments' on my system I had Bell rewire THEIR wires to eliminate the cross talk. problem solved. That event only took about 3 months to debug......sigh.

Have to ask , what is the power supply? It should be rated for 5-10X the overall max of the system at full load and be sure to use bypass caps where it enters the PCB! An underrated supply can 'dip' just enough to cause 'problems' but not enough to reset the PIC, BTDT.....

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Mon May 09, 2016 8:04 am     Reply with quote

I just updated my post with a bodge for one potential problem, but like you, was wondering about everything else in the circuit!... Smile
tssir



Joined: 14 Feb 2016
Posts: 24

View user's profile Send private message

PostPosted: Mon May 09, 2016 8:45 am     Reply with quote

Pushbutton on RB5 is a simple CMS keyboard switch.
It is welded to multi-strand cable, then connect to PCB with Graupner JR connector (https://www.graupner.de/Servo-Verlaengerungsk0-3qmm-500mm/S8178/).
From an electrical point of view, the pushbutton is connected to RB5 by only a 4.7kOhm serie resistor. No schmitt trigger IC.

Just when I wanted to program the software débouncer, I noticed this problem. I can not use an hardware debouncer, because RB5 should be alternatively used with a serial signal remote control or a simple switch remote control. Software manage both modes with the same input.

I try asked modifications :
Code:
.................... while(TRUE)
....................    {
....................    output_bit(IO_LEDG,LED_OFF);
00120:  BSF    F8B.4
....................    sleep(SLEEP_FULL);
00122:  MOVFF  FD3,00
00126:  BCF    FD3.7
00128:  SLEEP
0012A:  MOVFF  00,FD3
....................    delay_cycles(1); // Correction from Ttelmah 20160509
0012E:  NOP   
....................    output_bit(IO_LEDB,LED_OFF);
00130:  BSF    F8B.2

Same result : Some times, red and blue led keeps "on" after releasing pushbutton.

I check signal by oscilloscope. I notice no significant noise. Push button signal is very clean. Direct to the ground.
But release button can sometimes be very dirty, as you can see :


Ok, it should be a good clue, because I only have problem with released pushbutton. But if it's a debouncing problem, why interruption raise without waking-up (demonstrated by previous tests) ?

All pins are connected and used. Supply output capacitor is a MnO2 680uF 4V 100mOhm (1 cm distant to SOIC CPU), with a MIC5225 regulator. It is battery powered, with a buck/boost converter for multi-voltage tests only. Pic is connected to a Bluetooth tranceiver, a TSK 433MHz tranceiver, a thermal sensor, mosfets drivers, leds, ... But test program disable all devices, except one RGB leds. No ground loop. Simple two sided PCB.

As asked, I add 100nF ceramic capacitor, directly welded on SOIC package pin 19 and 20 (VDD and VSS). I add 100nF plastic capacitor close to push-button, in parallel (not best debouncer, but for test). Now the push-button signal is always very clean, but very slow (16ms to reach VDD after released, with internal pull-up, not a problem for me).
After many, many, tries, the problem is solved. To reach my design, I need to add hardware debouncer on switch side (because I can not debounce on PCB side).

But I can not understand why pic not waking-up after interruption.
1) Maybe a strange side effect of something.
2) Or my led program test is not correct (green led if not going to sleep, blue led if not waking-up after interruption, red led if released is not computed by main function).
3) Or a slower input is usefull for full working wake-up (pic not recommended for a full software debounce).

Anyway, thank you for your advices.
tssir



Joined: 14 Feb 2016
Posts: 24

View user's profile Send private message

PostPosted: Mon May 09, 2016 8:49 am     Reply with quote

Sorry, I just saw that you have completed your posts while I was writing the mine while testing.
So I'll read yours now.
tssir



Joined: 14 Feb 2016
Posts: 24

View user's profile Send private message

PostPosted: Mon May 09, 2016 9:13 am     Reply with quote

I experienced the same kind of problems with insufficient supply, that cause strange pic behaviour. Then I use a input diode to isolate Pic supply, good full protected regulator, and large capacitor in case of supply drop.

Ttelmah procedure is very clever. I would not have thought.
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