MicroNIMO ADC

The ADC code builds upon the USBVcom tutorial, which is recommended reading if you haven’t already. In this tutorial, we will make use of the onboard potential divider to read the voltage present at the battery connector. If you have a battery connected then this will be the current battery state, if not then it will show the open-circuit voltage of the charge circuit ~4.2V. The voltage will be read once every two seconds and reported via the USB port.

The full code can be found in our GitHub repository.

Bill of materials

MicroNIMO module

File structure

As with the other projects thus far, this is a simple project and as such will only require a umakefile and main.c. For more information about the file structure, refer to the microBlinky tutorial.

Required files

  • umakefile
  • main.c (the specific filename can be configured in umakefile)

Lets go…

By now you should be familiar with the creation of simple umake projects, so we’ll dive right into the code.

umakefile

The makefile is almost identical to the USBVcom project, except for the addition of the adc driver on line 23.

{
    "target": "usbVcom",
    "microcontroller": "m032lg6ae",
    "toolchain": "arm-none-eabi",
    "ucLib": "nimolib-m032",
    "c_sources": [
    	"main.c"
    ],
    "includes": [
  	"./"
    ],
    "buildDir": "./build",
    "libraries": [
	{
  	    "libName": "nimolib",
	    "libPath": "https://github.com/nimo-labs/nimolib.git",
	    "books": [
		"microNimo",
		"gpio",
		"delay",
		"usbVcom",
		"printf",
		"adc"
	    ]
	},
	{
	    "libName": "nimolib-m032",
	    "libPath": "https://github.com/nimo-labs/nimolib-m032.git"
	}
    ]
}

nimolib.h

This file is required when using the standard Nimo libraries and contains configuration information for the various books. For this project, we configure the main clock to 48MHz, specify buffer sizes for the usbVcom driver and printf, as well as configure printf to forward its output to the USB port.

/* usbVcom */
#define UP_CLK 48000000

/* usbVcom */
#define USB_BUFFER_SIZE 64
#define SIMPLE_VCOM_TX_BUFSIZE 100 /* TX buffer size */

/* Printf */
#define PRINTF_BUFF_SIZE 100
#define PRINTF_UART PRINTF_USB_VCOM

main.c

This is the entry point for our program, it contains the standard C main function which is the beginning of all C programs.

/* Project configuration */
#include "nimolib.h"

/* Books */
#include <microNimo.h>
#include <delay.h>
#include <usbVcom.h>
#include <printf.h>
#include <adc.h>

void main(void)
{
    uint32_t battV = 0;
    uint32_t loopLastTicks = 0;

    delaySetup(DELAY_BASE_MILLI_SEC); /*Clock timer at 1mS*/
    usbVcomInit();
    adcInit();

    delayMs(2000);

    printf("microNimo ADC example\r\n");

    loopLastTicks = delayGetTicks();

    while (1)
    {
        if(delayMillis(loopLastTicks, 2000))
        {
            battV=adcReadChanSingle(MN_BATTV_ADC_CHAN);
            battV = (battV * 3298) / 4096;
            battV *= 126;
            battV = battV / 100;

            loopLastTicks = delayGetTicks();
            printf("Battery voltage: %ldmV\r\n", battV);
        }
    }
}

In order to build correctly, we have to include some standard header files, nimolib.h is standard for all projects. In addition, we have to include a header file for each book we are using, in this case delay.h, usbVcom.h, print.h and adc.h.

Inside the main function, we Initialise the books we would like to use, delay, usbVcom and the adc (lines 16,17 and 18) and wait for 2 seconds before printing our welcome message. The 2-second delay is optional, however, depending on how long your host computer and terminal software take to detect and configure the USB port, the welcome message may be missed without the delay. A 2-second delay should be fine for most systems, however, if you find that you don’t see the welcome message then increasing the delay on line 20 would be a good starting point.

The while(1) statement on line 26 creates an infinite loop that runs the same short block of code forever. For this tutorial, we will read the ADC port (line 30), scale the raw reading to match the actual battery voltage (lines 31 – 33) and print the result via the USB terminal (line 36).

Line 35 is simply a housekeeping task that resets the delay routine, without it the delay would be almost instantaneous.

There are a couple of interesting points to note about line 30, first of all, we use the adcReadChanSingle function. This takes a single reading from the ADC channel and returns it directly to the user without any averaging. When working with data that changes slowly such as battery voltage, it is generally helpful to average multiple readings to smooth out any noise that may be present in the system. You might like to try averaging different numbers of readings to see the difference in stability of the readings.
Also on line 30, we have used the MN_BATTV_ADC_CHAN define, this is provided for us by microNimo.h and defines the ADC channel that the battery sensing circuitry is attached to.

ADC scaling

As mentioned above, before we can present the ADC data in a meaningful format we have to scale it.

Whilst an ADC peripheral reads the voltage presented to the pin, it doesn’t report that as a voltage. Instead, it reports the number of “counts” which is a number between 0 and a maximum which is defined by the resolution of the ADC peripheral itself. By default, the ADC within the microNimo board is configured to 12bit resolution which gives a total of 4096 different values, in the range 0 – 4095.

Due to the way that the ADC presents the data it measures, these “counts” need to be converted to a voltage, this is done at line 31. First of all, we multiply the measured value (in counts) by the voltage present on the 3.3V rail of the PCB, in this case, 3.298 volts. This is a good starting point, however, you may wish to measure this value on your board for increased accuracy. Finally, we divide this value by the resolution of the ADC in order to bring the value back into the required range.

At this point, we have a value between 0 and ~3.3V, however, a lithium battery has a range between 0 and 4.2V. Electrically, this is compensated for by a resistor divider on the PCB (R15, R16 and C11 on the schematic).

Due to this electrical scaling, we need to account for the reduction in voltage by multiplying by a constant that relates to the two resistors selected. This occurs at line 33.

Build it!

If you haven’t built a umake project before then we recommend that you read the microBlinky tutorial, otherwise running umake followed by make should build the project for you.

Burn it!

At this point, we are ready to test our new code. Fire up a new serial terminal (follow the usbVcom tutorial if required), put the board into bootloader mode and run make program from the terminal in order to burn the code to the microNimo board.

Once the firmware has been successfully written to the board, there will be a delay of 2 seconds followed by the welcome message and a readout of the battery voltage every two seconds.

microNimo ADC example
Battery voltage: 3280mV
Battery voltage: 3275mV
Battery voltage: 3288mV
Battery voltage: 3283mV
Battery voltage: 3287mV
Battery voltage: 3288mV
Battery voltage: 3286mV
Battery voltage: 3286mV
Battery voltage: 3285mV
Battery voltage: 3284mV
Battery voltage: 3252mV

As noted in the introduction, the actual battery voltage reported will depend on whether a battery is connected and if so, its current state of charge.

share post: