Select Page

We’ve been working on a new project based on the Particle platform (Photon and P1). Have a look at if you aren’t familiar with the Particle family. It’s built on the ST32 microcontroller family and as a module, offers a drop in IoT solution for many applications.

Particle P1 Module with integrated WiFi and Antenna

In this particular project, we’re using the 12-bit DAC output from the microcontroller to control a current source. The current source is a common circuit, based on a low-side mosfet and a sense resistor. This article presents a great example. When the DAC is set to zero, the load current IL should be zero. When the DAC is set to 4095, the load current should be 3.3V / R where R is the value of the sense resistor. For reference, the other resistor shown on the output of the DAC below is just used as a pulldown to tie that node to ground during startup.

Cartoon Schematic: DAC drives an op-amp and mosfet to control the current through a load using a voltage.

The Problem

Initial testing was going great… until we tried to set the load current to zero. For some reason, the smallest current achievable was on the order of 250uA. Inspecting the voltage coming out of the DAC revealed a value of about 52mV, even with the DAC code set to zero. Looking into the Particle data sheet, we found this gem:

NOTE: This output is buffered inside the STM32 to allow for more output current at the cost of not being able to achieve rail-to-rail performance, i.e., the output will be about 50mV when the DAC is set to 0, and approx 50mV less than the 3V3 voltage when DAC output is set to 4095.

Well, that’s not going to work for us! We need true rail to rail performance if we’re going to accurately control our current source.

The Solution

The Particle devices are based on the ST32 microcontroller. Looking at the device data sheet and application notes for the DAC, you can find references to the aforementioned output buffer along with the ability to turn it on and off. The equivalent circuit is as follows:

STM32 DAC Equivalent Internal Circuitry

The output buffer shown in that circuit is running on the internal 3.3V supply. As with most op-amps running on a single supply (as opposed to +/- dual supplies) the output swing will never truly hit the rails. As shown in the circuit however, there are two internal switches (S1 and S2) that can be controlled via registers. Opening them both will directly connect the “DACINT” signal to the “DACOUT” pin, with two resistors in series (Ra and Rb). For reference, Ra+Rb is about 15k.

So, how do we get at the low level registers to turn off the DAC output buffer? For an experience Arduino / Particle developer, this is probably a common task. For the novice, there isn’t too much to go on. We found one of the most valuable resources is the Particle OS source code itself. Luckily, this code is all publicly available here. Navigate to device-os/hal/src/stm32f2xx/dac_hal.c and at the very end, you’ll find a function called HAL_DAC_Enable_Buffer. Bingo!

So now, all we have to do is call that function in our main setup() routine. It looks something like this:

void setup() {    
    pinMode(V_CONTROL, OUTPUT); //setup the voltage control DAC
    HAL_DAC_Enable_Buffer(DAC, 0);  //turn off the output buffer on the DAC to allow full swing to the rails (sacrifice drive current)
    analogWrite(V_CONTROL, 0);

The order DOES matter. The buffer must be turned off AFTER the pinMode is set. The output is truly rail to rail now, and we can control our load current perfectly.

One thing worth noting: with the output buffer off, the output impedance of the DAC is in the realm of 15k. So if you’re trying to drive anything with it that draws even a few uA of current, you will see a voltage drop and “wrong” output values. Just add your own buffer on the output with true rail-rail performance and you’ll be all set.