HLVD interrupts 4 times per event

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
I have a pic18f27J53 which has HLVD. I have everything working the way I want except that each event interrupts 4 times. That doesn't seem right. I have been able to code around it but just does not seem like I should have to.

Has anyone use HLVD?

Code:
#include <xc.h>
#define LOW_POWER_SETPOINT 0b1001
#define NORMAL_POWER_SETPOINT 0b1010
#define _XTAL_FREQ 8000000

unsigned interruptCount = 0;

#define DETECT_LOW_POWER 0
#define DETECT_NORMAL_POWER 1

unsigned char  detectPowerMode = 0;

unsigned char enterSleep = 0;


void main(void)
{
  OSCCONbits.IRCF0 = 1;
  OSCCONbits.IRCF1 = 1;   
  OSCCONbits.IRCF2 = 1;   
   
  TRISAbits.TRISA0 = 0;
  TRISAbits.TRISA1 = 0;
   
  LATAbits.LATA0 = 1;
   
 
   
  OSCCONbits.IDLEN = 0;
   
  HLVDCONbits.HLVDEN = 0;  // Disable HLDV
  HLVDCONbits.HLVDL = LOW_POWER_SETPOINT;  // Set point to low value   
  HLVDCONbits.VDIRMAG = detectPowerMode;  // Interrupt when voltage drops   
  PIR2bits.HLVDIF = 0;  // Clear the HLVD interrupt flag   
  HLVDCONbits.HLVDEN = 1;  // Enable HLDV   
  RCONbits.IPEN = 1;
  INTCONbits.GIEH = 1;  // Enable general interrupts high
  PIE2bits.HLVDIE = 1;  // Enable low voltage detect interrupt   
   
   
   
   
   
  while(1)
  {
   
  LATAbits.LATA1 = 0;
  __delay_ms(100);
  LATAbits.LATA1 = 1;
  __delay_ms(100);

  if (enterSleep)
  Sleep();

   
  }
  return;
}


__interrupt(high_priority) void interrupts_highPriority(void)
{
  if (PIR2bits.HLVDIF == 1)   
  {
  PIR2bits.HLVDIF = 0;


  interruptCount++;

  if (interruptCount<4)
  return;

  interruptCount=0;

  if (detectPowerMode == 1)
  {

  LATAbits.LATA0 = 1;   
  detectPowerMode = DETECT_LOW_POWER;
  HLVDCONbits.HLVDEN = 0;   
  HLVDCONbits.HLVDL = LOW_POWER_SETPOINT;   
  HLVDCONbits.VDIRMAG = detectPowerMode;   
  HLVDCONbits.HLVDEN = 1;
  enterSleep=0;


  }
  else
  {

  LATAbits.LATA0 = 0;   
  detectPowerMode = DETECT_NORMAL_POWER;   
  HLVDCONbits.HLVDEN = 0;   
  HLVDCONbits.HLVDL = NORMAL_POWER_SETPOINT;
  HLVDCONbits.VDIRMAG = detectPowerMode;
  HLVDCONbits.HLVDEN = 1;
  enterSleep =1;
  }   


   
  }
   
}
 
Last edited:

Picbuster

Joined Dec 2, 2013
1,058
I have a pic18f27J53 which has HLVD. I have everything working the way I want except that each event interrupts 4 times. That doesn't seem right. I have been able to code around it but just does not seem like I should have to.

Has anyone use HLVD?

Code:
#include <xc.h>
#define LOW_POWER_SETPOINT 0b1001
#define NORMAL_POWER_SETPOINT 0b1010
#define _XTAL_FREQ 8000000

unsigned interruptCount = 0;

#define DETECT_LOW_POWER 0
#define DETECT_NORMAL_POWER 1

unsigned char  detectPowerMode = 0;

unsigned char enterSleep = 0;


void main(void)
{
  OSCCONbits.IRCF0 = 1;
  OSCCONbits.IRCF1 = 1;  
  OSCCONbits.IRCF2 = 1;  
  
  TRISAbits.TRISA0 = 0;
  TRISAbits.TRISA1 = 0;
  
  LATAbits.LATA0 = 1;
  

  
  OSCCONbits.IDLEN = 0;
  
  HLVDCONbits.HLVDEN = 0;  // Disable HLDV
  HLVDCONbits.HLVDL = LOW_POWER_SETPOINT;  // Set point to low value  
  HLVDCONbits.VDIRMAG = detectPowerMode;  // Interrupt when voltage drops  
  PIR2bits.HLVDIF = 0;  // Clear the HLVD interrupt flag  
  HLVDCONbits.HLVDEN = 1;  // Enable HLDV  
  RCONbits.IPEN = 1;
  INTCONbits.GIEH = 1;  // Enable general interrupts high
  PIE2bits.HLVDIE = 1;  // Enable low voltage detect interrupt  
  
  
  
  
  
  while(1)
  {
  
  LATAbits.LATA1 = 0;
  __delay_ms(100);
  LATAbits.LATA1 = 1;
  __delay_ms(100);

  if (enterSleep)
  Sleep();

  
  }
  return;
}


__interrupt(high_priority) void interrupts_highPriority(void)
{
  if (PIR2bits.HLVDIF == 1)  
  {
  PIR2bits.HLVDIF = 0;


  interruptCount++;

  if (interruptCount<4)
  return;

  interruptCount=0;

  if (detectPowerMode == 1)
  {

  LATAbits.LATA0 = 1;  
  detectPowerMode = DETECT_LOW_POWER;
  HLVDCONbits.HLVDEN = 0;  
  HLVDCONbits.HLVDL = LOW_POWER_SETPOINT;  
  HLVDCONbits.VDIRMAG = detectPowerMode;  
  HLVDCONbits.HLVDEN = 1;
  enterSleep=0;


  }
  else
  {

  LATAbits.LATA0 = 0;  
  detectPowerMode = DETECT_NORMAL_POWER;  
  HLVDCONbits.HLVDEN = 0;  
  HLVDCONbits.HLVDL = NORMAL_POWER_SETPOINT;
  HLVDCONbits.VDIRMAG = detectPowerMode;
  HLVDCONbits.HLVDEN = 1;
  enterSleep =1;
  }  


  
  }
  
}
Did you set intcon and intcon2 (up or down going edge)
intcon set to on change will produce 2 ints.

picbuster
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
Did you set intcon and intcon2 (up or down going edge)
intcon set to on change will produce 2 ints.

picbuster

What bit in intcon? The only thing that is set is GIE called out by the datasheet. If yo u mean RB then this is not am RB pin interrupt,


Why intcon2? This is not an external interrupt. HLVD is not really an external interrupt. I see nothing in HVLD setup that says anything about INTCON2.

There are 4 interrupts not 2.

I have included all of my code.
 

Picbuster

Joined Dec 2, 2013
1,058
What bit in intcon? The only thing that is set is GIE called out by the datasheet. If yo u mean RB then this is not am RB pin interrupt,


Why intcon2? This is not an external interrupt. HLVD is not really an external interrupt. I see nothing in HVLD setup that says anything about INTCON2.

There are 4 interrupts not 2.

I have included all of my code.
You are correct about the int

This might help;
http://ww1.microchip.com/downloads/en/DeviceDoc/39725a.pdf

Picbuster
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
You are correct about the int

This might help;
http://ww1.microchip.com/downloads/en/DeviceDoc/39725a.pdf

Picbuster

Read it or a similar article. Plus it is pretty much what is in my datasheet. Usually those separate publications go much further into detail than what is in the chip's datasheet but not this one.

Information is very sparse on the HLVD feature. For example the datasheet says.

bit 6BGVST: Band Gap Voltage Stable Flag bit1 = Indicates that the band gap voltage is stable0 = Indicates that the band gap voltage is unstable

I would assume that is a status bit to be read. It does say in part of the documentation that HLVDEN must be disabled to read it but it seems to me that bit never goes high. I would assume you need to wait for the voltage to be stable but it seems like it never happens. Likewise for IRVST.

Here is what the datasheet says about setup (or one of the things)

Enable the HLVD interrupt if interrupts are desired. An interrupt will not be generated untilthe BGVST bit (HLVDCON<10>) is set

But it does not say who is going to set the darn thing. The Pic or the programmer through code.
 

Picbuster

Joined Dec 2, 2013
1,058
oops, looks strange however; the manual indicates that an interrupt will occur when bgvst is active ( looks like that you can't read it without a disable).
it also produces a note;
Note 1:The hardware sets the HLVD interrupt flag back to ‘1’ if the condition is still true
That implies that this int is on during that condition and clear int has no real effect other than an extra interrupt.
It might help is you do output = interrupt; (output to scope)


Picbuster
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
oops, looks strange however; the manual indicates that an interrupt will occur when bgvst is active ( looks like that you can't read it without a disable).
it also produces a note;
Note 1:The hardware sets the HLVD interrupt flag back to ‘1’ if the condition is still true
That implies that this int is on during that condition and clear int has no real effect other than an extra interrupt.
It might help is you do output = interrupt; (output to scope)


Picbuster

I appreciate the help but I am anot clear on what you are trying to describe. If you can please stop typing in shorthand, it would help.

I have no idea what this means.

"It might help is you do output = interrupt; (output to scope)"


As for the rest of it. Does that mean.

1. Interrupt occurs.
2. You need to disable HVLD.
3. Wait for bgvst to clear.
4. Clear interrupt flag.
5. Enable HVLD.

If that is so, then that seems like a really dumb way to do interrupts.

But from this chart it looks like that might be a clue but it is IRVST they are referencing. Not bgvst. It looks like you do need to wait for IRVST ,

upload_2019-3-24_7-48-58.png
 
I have not used HVLD, but your post made me look at it. Have you seen the code here? http://www.embeddedcodesource.com/codesnippet/hlvd-power-down-save

If I am following it correctly, they disable HLVD interrupts in the ISR
PIE2bits.LVDIE = 0; // disable further HLVD interrupts until Vdd is stable again

and it is enabled in the main program (which loops), but only after the test for stable Vdd is passed (void WaitForStableVdd(void)).
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
I have not used HVLD, but your post made me look at it. Have you seen the code here? http://www.embeddedcodesource.com/codesnippet/hlvd-power-down-save

If I am following it correctly, they disable HLVD interrupts in the ISR
PIE2bits.LVDIE = 0; // disable further HLVD interrupts until Vdd is stable again

and it is enabled in the main program (which loops), but only after the test for stable Vdd is passed (void WaitForStableVdd(void)).
Have not seen that code thanks,

All they are doing is delaying for a while till the voltage settles. Basically what I am doing except with an interrupt counter. But it seems like they are delaying upwards of 0xFFFF * 32000 * 4 instructions that seems to be a bit extreme and not the most efficient way to wait.

My way of doing it is not the best either as the count would likely be dependent on the speed of the mcu
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
But notice they are waiting for both BCVST and IRVST at the top of the code. Right after they enable HLVD but before enable interrupts.

while(HLVDCONbits.BGVST == 0); // wait for stable bandgap reference voltage
while(HLVDCONbits.IRVST == 0); // wait for stable HLVD internal reference voltage
 
I did notice that setup (your post #10) but to your post #9, are they just waiting (i.e., just delaying)??

Overview: If the HLVD flag is getting set due to Vdd being
below the trip point, this routine will wait.
Once Vdd rises above the trip point and stays
above for several iterations, the routine will
return.

and in the code,
if(PIR2bits.LVDIF)

when that is true, stable gets reset to 0xffff. I interpreted that test as "unstable Vdd", and WaitForStableVdd(void) will not return until if(PIR2bits.LVDIF) fails (meaning a stable Vdd) for at least one full iteration. No?
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
All they are doing is delaying for a while till the voltage settles. Basically what I am doing except with an interrupt counter. But it seems like they are delaying upwards of 0xFFFF * 32000 * 4 instructions that seems to be a bit extreme and not the most efficient way to wait.
Oh I see no. What they are waiting for is the interrupt flag to no longer be set. That is a little more efficient.

Code:
void WaitForStableVdd(void)
{
  unsigned int stable = 0xFFFF;
  while(stable--)
  {
  if(PIR2bits.LVDIF)  //If flag is not cleared then wait
  {
  PIR2bits.LVDIF = 0;  // clear HLVD interrupt flag
  stable = 0xFFFF;
  printf("\r\nUnstable Vdd");
  wait();
  }
  }
}
 
Last edited:

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
This works and makes a whole lot more sense than what they did.

Basically what I do is to disable the HLVD interrupt in the ISR, set a flag in the ISR that there was an HLVD interrupt then wait for BGVST and IRVST to be set in the main loop.
Not sure if that is just acting as a delay or it is actually waiting for those bits to set. Maybe I will experiment later ro find out for sure

Thanks for the help Pic and Ray. You didn't give me the answer but led me down the path.

Code:
#include <xc.h>
#define LOW_POWER_SETPOINT 0b1001
#define NORMAL_POWER_SETPOINT 0b1010
#define _XTAL_FREQ 8000000

unsigned interruptCount = 0;

#define DETECT_LOW_POWER 0
#define DETECT_NORMAL_POWER 1

unsigned char  detectPowerMode = 0;

unsigned char enterSleep = 0;
unsigned char hlvdISRoccured = 0;

void WaitForStableVdd(void);

void main(void)
{
  OSCCONbits.IRCF0 = 1;
  OSCCONbits.IRCF1 = 1;   
  OSCCONbits.IRCF2 = 1;   
   
  TRISAbits.TRISA0 = 0;
  TRISAbits.TRISA1 = 0;
   
  LATAbits.LATA0 = 1;
   
 
   
  OSCCONbits.IDLEN = 0;
   
  HLVDCONbits.HLVDEN = 0;  // Disable HLDV
  HLVDCONbits.HLVDL = LOW_POWER_SETPOINT; // Set point to low value   
  HLVDCONbits.VDIRMAG = detectPowerMode;  // Interrupt when voltage drops   
  PIR2bits.HLVDIF = 0;  // Clear the HLVD interrupt flag   
  HLVDCONbits.HLVDEN = 1;  // Enable HLDV   
  while(HLVDCONbits.BGVST == 0);  // wait for stable bandgap reference voltage
  while(HLVDCONbits.IRVST == 0);  // wait for stable HLVD internal reference voltage
  RCONbits.IPEN = 1;
  INTCONbits.GIEH = 1;  // Enable general interrupts high
  PIE2bits.HLVDIE = 1;  // Enable low voltage detect interrupt   
   

   
   
   
  while(1)
  {
   
  LATAbits.LATA1 = 0;
  __delay_ms(100);
  LATAbits.LATA1 = 1;
  __delay_ms(100);

   
  if (hlvdISRoccured)
  {
   
  hlvdISRoccured = 0;   
  WaitForStableVdd();
  PIE2bits.LVDIE = 1;  // Renable HLVD ISR   
   
  if (enterSleep)
  Sleep();
   
   
  }

   
  }
  return;
}


__interrupt(high_priority) void interrupts_highPriority(void)
{
  if (PIR2bits.HLVDIF == 1)   
  {
  PIE2bits.LVDIE = 0;  
  hlvdISRoccured = 1;

  if (detectPowerMode == 1)
  {

  LATAbits.LATA0 = 1;   
  detectPowerMode = DETECT_LOW_POWER;
  HLVDCONbits.HLVDEN = 0;   
  HLVDCONbits.HLVDL = LOW_POWER_SETPOINT;   
  HLVDCONbits.VDIRMAG = detectPowerMode;   
  HLVDCONbits.HLVDEN = 1;
  enterSleep=0;


  }
  else
  {

  LATAbits.LATA0 = 0;   
  detectPowerMode = DETECT_NORMAL_POWER;   
  HLVDCONbits.HLVDEN = 0;   
  HLVDCONbits.HLVDL = NORMAL_POWER_SETPOINT;
  HLVDCONbits.VDIRMAG = detectPowerMode;
  HLVDCONbits.HLVDEN = 1;
  enterSleep =1;
  }   


   
  }
   
}

void WaitForStableVdd(void)
{  
   
 while(HLVDCONbits.BGVST == 0);  // wait for stable bandgap reference voltage
 while(HLVDCONbits.IRVST == 0);  // wait for stable HLVD internal reference voltage   
 PIR2bits.LVDIF = 0;  // clear HLVD interrupt flag   
 
}
 
ok good deal. Now, I have a question for you. Microchip is the master of the brown-out reset...why all this hub-bub with HLVD? What is the great value? I thought, perhaps naively, you detect a brown-out and quit and don't restart until there is no brown out.

Yes, using some kind of HLVD to initiate a save of some critical variables makes some sense, but it seems to me that other methods would be preferable. I am under appreciating the issue.
 

Picbuster

Joined Dec 2, 2013
1,058
oops, looks strange however; the manual indicates that an interrupt will occur when bgvst is active ( looks like that you can't read it without a disable).
it also produces a note;
Note 1:The hardware sets the HLVD interrupt flag back to ‘1’ if the condition is still true
That implies that this int is on during that condition and clear int has no real effect other than an extra interrupt.
It might help is you do output = interrupt; (output to scope)


Picbuster
Sorry I am always in a hurry.
but I try to indicate the following;
set an output port when an interrupt is received.
If you clear the interrupt flag you should set output port to zero; ( observe output port with scope )

Information below comes from microchip
Note 1:The hardware sets the HLVD interrupt flag back to ‘1’ if the condition is still true
//================ end microchip info ==================
Clearing the int is useless if the condition is still on.
example:
Interrupt received:
you set flag off;
two possibilities : A: condition does not exists anymore interrupt stays off.
b: condition exists Interrupt is set again. (a delay could occur).

Picbuster
























Picbuster
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
ok good deal. Now, I have a question for you. Microchip is the master of the brown-out reset...why all this hub-bub with HLVD? What is the great value? I thought, perhaps naively, you detect a brown-out and quit and don't restart until there is no brown out.

Yes, using some kind of HLVD to initiate a save of some critical variables makes some sense, but it seems to me that other methods would be preferable. I am under appreciating the issue.
For me?

1. Thought HLVD was way more easier to implement than BOR (that is what I thought ;) )

2. Not sure if I can use BOR in this instance but then again I did not investigate further. I have a clock with a battery backup. Normal supply is at ~3.1v battery is at ~2.8V. I want to put the mcu to sleep if it is on battery power.

I must say I must look more into BOR.
 
Top