Using the HLVD Module in Swordfish Basic

teaserMany of the 18F-series micros have an HIGH/LOW-VOLTAGE DETECT (HLVD) module that can be used to monitor VDD and warn if it has decreased below a specified voltage or increased above a specified voltage.  This is a great technique for monitoring the supply voltage of a micro that is directly battery powered.  It has several advantages over using an ADC channel for the purpose:

    1. No port pins are needed to implement.
    2. No external components are required and no power is consumed by an external voltage divider.
    3. The HLVD module uses an internal band-gap reference and draws a maximum of 45 µA when enabled.  It can be disabled except when needed to reduce even this tiny current draw.
    4. It can generate an interrupt when VDDis below or above (depending on how it's configured) the selected set point.



There are however a couple limitations:

    1. It can only be used to measure VDD, so it cannot be used to monitor a battery supplying power through a voltage regulator.
    2. There are only 16 steps over the measurement range with manufacturing tolerances on the band-gap reference and internal resistive voltage divider, so the settings are somewhat granular.  The trip point settings are shown below for an 18F2520. Please note the trip point settings depend on the device used.  Consult the data sheet.


The instructions for using the HLVD are spelled out in the data sheet:

22.2 HLVD Setup
The following steps are needed to set up the HLVD module:

    1. Write the value to the HLVDL<3:0> bits that selects the desired HLVD trip point.
    2. Set the VDIRMAG bit to detect high voltage (VDIRMAG = 1) or low voltage (VDIRMAG = 0).
    3. Enable the HLVD module by setting the HLVDEN bit.
    4. Clear the HLVD interrupt flag (PIR2<2>), which may have been set from a previous interrupt.
    5. Enable the HLVD interrupt, if interrupts are desired, by setting the HLVDIE and GIE bits (PIE2<2> and INTCON<7>). An interrupt will not be generated until the IRVST bit is set.


At first glance, the procedure for using the HVLD module appears daunting, requiring configuring several registers of the PIC and setting up interrupts.  It's actually pretty simple to use.  In this article, I will cover a polled implementation rather than an interrupt-driven one.  Additional information may be found in the data sheet in the section on the HIGH/LOW-VOLTAGE DETECT (HLVD) module, which is 22 for the 18F2520.

Swordfish makes it simple to access the PIC's registers.  The register names are pre-configured as variable names.  For example, the HLVD setup is done using the HLVDCON register.  If you start typing hlvdc... when you complete the word, it will snap to all caps -  HLVDCON - meaning Swordfish recognizes it.  So setting it up is as easy as typing HLVDCON = %00011011.

The first step above is configuring the trip point in the HLVDCON register.  This is slightly confusing because the trip point settings aren't shown in section 22; they are contained in Table 26-4 in section 26 as the footnote under the HLVDCON register indicates.

Table 26-4

An aside here.  The percent sign above indicates to the compiler that %00011011 is a binary number.  HLVDCON = 27 or HLVDCON = $1B mean exactly the same thing but are shown as decimal and hex values respectively.  So why use the binary format?  Each bit in the register has a specific meaning, so it's easier to specify the setting bit by bit.  You can easily tell from the binary representation which bits are set - the red dots show the values selected.

The lower 4 bits of the HLVDCON register come from the above table to set the trip voltage.  The upper four bits are configured according to Register 22-1 - HLVDCON.  We don't need to know the register number, since Swordfish already knows its name.  On a chip other than the 18F2520, the register number may even be different, but Swordfish knows which register to access because it's defined in the setup file for each chip.
Register 22-1

A couple of these need some explanation:

    • Bit 6 is unused.  The value written to it doesn't matter.
    • Bit 5 is a flag indicating that the internal voltage reference is stable.  Setting (writing a 1) or clearing (writing a 0) does not affect operation.
    • Bits 3 - 0 are the set-point, shown in table 26-4 (for the 18F2520).  For our test, %1011 was selected, giving a nominal trip point of 3.9 volts, but it can range from 3.7v - 4.1v depending on chip tolerances.

So the first step in using the HLVD module is configuring the HLVDCON register, which is simple:

HLVDCON = %00011011

This sets the trip to occur when VDD falls below the trip point, enables the HLVD module and sets to trip point to approximately 3.9 volts.

We've actually covered the first three (of five) steps from the data sheet and the hard part is done.  Not too tough so far!

If VDD falls below the voltage threshold we have defined, the HLVD interrupt flag will be set (i.e., equal to 1).  Since this is a polled implementation of the HVLD module, no interrupt will be generated.  Instead, we have to read another register to determine if the threshold has been crossed.  We'll read bit 2 in the register named PIR2.  Since we can't be sure what happened before our software came along, we first have to clear (set the bit equal to 0) before we read it to tell if the threshold has been crossed. 

Wow, this is a busy register - PIR2: PERIPHERAL INTERRUPT REQUEST (FLAG) REGISTER 2 - many things get reported in this register as shown below.

PIR2 copy

Oscillators and timers and EEPROM...all kinds of things.  But we're only interested in bit<2>, HLVDIF (High Low Voltage Detect Interrupt Flag).  The rest of the parameters here don't matter to us.  This register just contains status flags so it probably wouldn't hurt if we changed all of them but in general, it's best to modify only the bits we're interested in in a register to prevent unexpected results.  Fortunately, Swordfish makes it easy to read and write specific bits in a register (or any variable for that matter).

x = PIR2.bits(2) will read the value of only bit 2 in the register.

PIR2.bits(2) = 0 will make the bit equal to 0 (i.e, clear the bit)

PIR2.bits(2) = 1 will make the bit equal to 1 (i.e., set the bit)

So now we know how to clear the bit initially, and read the bit to tell if the HLVD threshold has been crossed.  This handles #4 in the instructions on how to use the HLVD module.

I want to poll the HLVD register to tell if the threshold has been crossed rather than generate an interrupt. A simple check can be added to the main program loop to check or the code can be put in a subroutine and called as desired.  So step #5 above isn't needed.  We've got all the pieces to use the HLVD module.

I wrote a simple program to test this all out.  One LED toggles each time through the program loop to indicate the program is running, and the other LED illuminates whenever VDD is below the set threshold.


*  Name    : HLVD Test                                                      *
*  Author  : Jon Chandler                                                   *
*  Notice  : Copyright (c) 2013 Creative Commons 3.0 sa-by-nc               *
*          : All Rights Reserved                                            *
*  Date    : 1/8/2013                                                       *
*  Version : 1.0                                                            *
*  Notes   : Poll the HLVD register to detect low Vdd voltage.              *
*          : Register settings may vary with device.                        *
Device = 18f2520
Clock = 20
Include ("utils.bas")
Dim LEDYellow As PORTB.3
Dim LEDBlue As PORTC.0
LEDBlue = 0
LEDYellow = 0
LEDBlue = 1
LEDYellow = 1
HLVDCON =%00011011      'see section 22.0 for setup and table 26-4 for voltage setting 
                        'set to 4 volts in this case
PIR2.bits(2) = 0        'clear HLVD interrupt flag
'PIE2.bits(2) = 1        'enable HLVD interrupt (section 22.2, sentence 5)
'intcon.bits(7) = 1     'enable HLVD interrupt (section 22.2, sentence 5)
                        'not needed for polled result    
While 1 = 1
    If PIR2.bits(2) = 1 Then          'check HLVD interrupt
            LEDBlue = 0                'LED = ON
            PIR2.bits(2) = 0          'clear HVLD interrupt
            LEDBlue = 1                'LED = OFF
    End If
    Toggle (LEDYellow)

Pretty simple, don't you think?

Testing The Program

 In order to test the program, VDD must be varied.  If you have a real deal PICkit 2 (not all clones support this) or a PICkit 3, VDD can be varied.  The picture below is the PICkit 2 GUI screen.   The supply voltage can be varied in the box shown.

NOTE:  This voltage indicated is only accurate if the PICkit 2 has been calibrated to the USB port being used.


In my test program, the HLVD range was <1011> which sets the voltage to a nominal range of 3.90 volts, with a minimum voltage of 3.70 to a maximum of 4.10 volts.  Using my adjustable bench supply and reading VDD accurately with a Fluke 45 bench meter, the threshold to activate the HLVD interrupt was found to be 3.85 volts at a temperature of about 65°F.  There appears to be a slight amount of hysteresis of around 0.05 volts - the voltage has to rise slightly above the threshold before the interrupt will clear.


When is a Battery Dead?

Determining the threshold for "low battery" depends on the battery chemistry and the load drawn by the circuit.  A typical battery discharge curve is shown below.  The voltage is somewhat flat in the operating range of the battery but starts to fall rapidly when the battery is depleted.  The challenge is to get the maximum life from the battery but still provide a warning in time to allow whatever action is necessary before the battery is dead.

The red axes shows about 90% of the battery capacity has been used and the cell voltage (for this particular type of battery) is about 1.04 volts.  The blue line shows about 95% of the battery capacity used and the cell voltage is about 0.99 volts.  The cell voltage is dropping rapidly at this point.

A three cell pack would provide 4.8 volts with fresh batteries.  The 90% point would be 3.12 volts, and the 95% point would be 2.97 volts.  How does this fit with the HLVD thresholds of the PIC18F2520?

HLVDL<3:0> = 0111 provides a range of 2.96 to 3.28 volts.  That exceeds the range of 90- 95% of capacity used and may not provide much warning of a low battery depending on chip tolerances.

the next stop of HLVDL<3:0> = 1000 would provide a range from 3.22 to 3.56 volts.  This would provide a warning at between 60 and 85% of battery depletion.  This would provide more warning of low batteries at the risk of loosing 40% of battery life.

Battery Discharge Curve

Swordfish Compiler

Swordfish is a highly structured, modular compiler for the PIC18 family of PIC® microcontrollers. Swordfish is a true compiler that generates optimised, stand alone code which can be programmed directly into your microcontroller.

Get it today!