New Approach to Implement MSP430 Battery Monitor

As we know, MSP430 doesn't have builtin battery monitor. Though the ADC module does have a dedicated channel to measure 1/2 VCC. But there is a critical issue with this approach.
  • The ADC module is usually used by other signal conversion task. It is difficult to switch ADC for channels with different sampling rate. In general, we only need to monitor battery voltage in a very slow frequency, for example, 1Hz. If the ADC module is working at 1KHz for converting other signal, it will be very inefficient to use "repeated-autoscan" mode to do both signal and battery voltage conversion.
So, it will be very useful to have a new approach to monitor battery without using ADC module. In MSP430FR68xx and 69xx series, there is a COMP_E module which is a very flexible voltage comparator. The idea is to utilize COMP_E to compare VCC with a reference voltage.

Well there is already a "shared reference" module which can generate 1.2V, 2.0V or 2.5V. Since MSP430 can work at 1.8V, the best choice of VREF voltage should be 1.2V. This will be the V- terminal of the comparator.

How about VCC input at V+ terminal? The simplest way is to use two resistors to divide VCC. But this method will continue to drain battery power when the system is shutdown. To overcome the side effect, we need to use a switch to turn off the resistor-divider when not in used. That means... we need two external resistors, one external MOSFET as switch and a pinout to control the switch... seems not good idea.

The ultimate solution is to use the resistor-ladder inside COMP_E module. The ladder can be used to divide VCC by 32 steps. So, we can get rough 100mV/step for 3.3V VCC and 62.5mV when VCC drops to 2.0V. The resolution looks good enough for battery monitoring purpose.

In FR68xx/FR69xx, the VREF output pin (VREF+) is the same as C1. C1 is the 2nd comparator input pin. So, we have to set REFOUT=1 so that the 1.2V reference is output at C1 which is the input of V- terminal of comparator amplifier. Then, set CEVREF as the output of VCC through resistor ladder. Let CEVREF outputs to V+ terminal of comparator amplifier.

Here is the code tested on MSP430FR6972IRGC:

void init()
    // Suppose we want to monitor if VCC < 2.3V.
    // 2.3V*(16+1)/32 = 1.22V
    // 2.3V*(15+1)/32 = 1.15V
    P1SEL0 |= BIT1;                 // VREF+ & C1 are at the same P1.1
    P1SEL1 |= BIT1;
    REFCTL0 |= REFOUT;              // Enable REFOUT. d
    CECTL0 = CEIMSEL_1|CEIMEN;      // C1 is set to V- terminal
    CECTL2 = CERS_1|CEREF1_16|CEREF0_16;    // CEREF(VCC) is set to V+ terminal

int checkVoltage()
    CECTL1 |= CEON;                 // Enable COMPE_E
    delay_us(1);                    // Wait for filter circuit to be stable
    int ceout = CECTL1 & CEOUT;     // Get result
    CECTL1 &= ~CEON;                // Disable COMP_E
    return ceout;
Now, we only need to call checkVoltage() once per second. It returns 1 if voltage is VCC > 2.3V and 0 if VCC < 2.3V. It is very easy to modify the above code to get the rough battery voltage by testing 32 ladder steps.