# A simple digitally controlled small current source

14 Oct 2022 - tsp
Last update 06 Nov 2022
11 mins

The following blog article describes a small and pretty simple digitally controllable current source that is capable of outputting up to $500 mA$ at voltages up to $12V$ (this can simply be extended by choosing a proper MosFET and other sense resistor up into the $\approx 30A$ range though - but it stays a linear regulation circuit so is limited by supply voltage and heat production inside the MosFET). This has been designed for a particular application in which the current controller had to be able to:

• Control the outputted current via a digital control system
• Monitor the actual current using an ADC (this has been mainly used to detect situations in which the supply is not able to supply the requested current any more)
• The controller had to be biased to high potential (around 2 kV more negative than the control system and environment). Thus the serial interface had to be isolated - this has also lead to the decision to use a rather large microcontroller on the high voltage side to have some more GPIOs and analog digital converters available for different purposes.
• This controller belongs to the slow control side (so no real time control with nanoseconds or milliseconds of resolution) of an experiment

• The hardware
• The PCB
• The software side

## The hardware

To solve that problem one of the simplest OpAmp based solution has been used - a cheap LM358 operational amplifier drives an IRF540N (or similar) n-channel MosFET to which the load is attached on the high side. The current flows over a small sense resistor to ground - for the desired current range and a control voltage in the range from 0 to 5V a 10 Ohm resistor has been chosen. Depending on the desired output current one can simply choose the sense resistor according to

[ U = R * I \\ R = \frac{U}{I} \\ \to R = \frac{5V}{500 mA} = \frac{5}{0.5} = 10 \Omega ]

Note that this solution does not compensate for thermal drift of the sense resistor which is required for larger loads or higher accuracy requirements. There is a simple and fascinating solution to that problem that one should prefer in this case.

The two $100 \Omega$ resistors one sees at the output of the LM358 into the MosFETs gate as well as in the feedback path to the inverting OpAmp input in theory have no effect since one usually assumes no current is flowing there. They’re there to prevent transient over current situations during loading of the MosFETs gate - this of course limits response time of the circuit also in case of highly adaptive loads - and to limit leakage currents into the OpAmp.

Note that the MosFET requires a heat sink for sure (calculate the thermal load in case) when operating at currents above $100 mA$ at a supply voltage around or above $12V$. Check with the MosFETs datasheet as usual. The heat dissipated can be estimated in the worst case - when one assumes that the whole power is dumped into the MosFET, i.e. $P_{worst} = U_{Vcc} * I_{max}$.

To measure the current using the ATMegas internal analog to digital converter (ADC) the analog input has been directly attached to the current sense resistor. This works despite the 12V input voltage on the load since the OpAmp drives the gate of the MosFET in a way that the voltage over the sense resistor is always as large as the voltage on its non inverting input provided by the DAC. Since the DAC can only output to $\approx 5V$ it’s guaranteed that the voltage at this point never exceeds 5V. Note that when using the OpAmp in an amplifying configuration (to achieve higher voltages over the sense resistor) one would have to provide a high impedance voltage divider in parallel to the sense resistor.

The output current is regulated by selecting the input voltage on the non inverting input of the operational amplifier. The outputted voltage (as long as the power supply is not saturated) is given by:

[ I = \frac{U}{R_{sense}} \\ I = \frac{U}{10} ]

To provide the reference voltage a cheap MCP4822 14 bit digital to analog converter (DAC) has been used. It’s 14 bit resolution in theory allows one - for the $500 mA$ configuration - to select the current with about $30 \mu A$ resolution. The second DAC channel has not been used. The MCP4822 is pretty easy to use - it’s just attached to an SPI port (only using a write only interface). The chip select has been pulled high by a $10 k\Omega$ resistor to disable the SPI logic while the microcontroller is in reset since the AVR used in this project is also programmed via it’s SPI pins. The decoupling capacitors on the power supply rail as well as on the output have to be mounted as close to the chip package as possible.

The LDAC line could in theory also be pulled to ground in case one wants to immediately update the output voltage after one has written a DAC register. The usage of this line is usually interesting when one wants to update two channels at the same synchronous time or have better control over timing - though I had enough pins available on the used ATMega328P so I’ve just routed the pin to a GPIO port.

The output line VA has been directly connected to the non inverting input of the LM358 OpAmp.

Power supply for logic and microcontroller has been done using a simple LM317 linear regulator. This is feasible since the input voltage is around 12V (with some neglectable ripple). The 12V are directly derived from a 230V to 12V transformer, a bridge rectifier built out of Schottky diodes and an about $10 mF$ large capacitor bank (this has been required due to other constraints on the load side of the setup). Note that of course also a fuse is part of this transformer assembly. Since the required supply voltage was 5V this of course means that the linear regulator will burn $\approx 60$ percent of power as thermal load - but since the current required by the OpAmp, DAC and microcontroller is pretty low the regulator does not even require a heat sink in this configuration.

Again place the capacitors as close to the regulator as possible or it will start to oscillate.

The last part is the microcontroller itself. A ATMega328P has been chosen (even if it’s a little bit of overkill). Communication with the outside world is handled by it’s USART - a serial port. This has been isolated using cheap PC816 opto couplers. Note that those are cheap but not the best choice for serial port isolation. It works for low BAUD rates though. The controller could be used with it’s internal RC oscillator (in this case one can leave out the 16 or 20 MHz quartz) and only requires a single additional reset network and decoupling capacitor on the AREF pin.

The remaining pin mappings that have been used are:

Pin on AVR Usage
AVCC, VCC 5V voltage supply
AREF Tied to ground via $0.1 \mu F$ ceramic capacitor
GND Ground reference pin
nRESET/PC6 Tied to 5V line via $10 k\Omega$ and ground via $0.1 \mu F$ to provide a reset pulse during power up
XTAL1/XTAL2 Connected to the quartz (if used)
PC0 This is the first ADC input so it’s connected to the voltage divider in parallel to the sense resistor
PD1 USART Transmit pin
PD2 Attached to LDAC to latch new DAC values
PD3 Chip select of the DAC tied to 5V to disable the DACs select while the ATMega is in tristate
PB5 Serial SPI clock for programming and DAC
PB4 SPI MISO (attached to programming interface)
PB3 SPI MOSI (attached to DAC and programming interface)

Of course the serial programming interface can only be used while the controller is not biased to it’s $-2 kV$ potential and serial communication via the opto couplers works only pretty slow.

The full schematic looks like the following (note that this assumes about $100 \Omega$ pull downs on the low voltage side of the serial interfaces receive path or the opto couplers won’t even be fast enough for 2400 bits per second BAUD rate)

## The PCB

The following PCB is a simple realization for a low current version of the controller board. As one can see it:

• Uses standard wire-wound or carbon film resistors in through hole technique. One could use SMD parts for everything except the sense resistor. A better higher quality version would use TO-220 packaged high precision resistors on the edge of the PCB with a heatsink. Thouse should be rated at least twice the target current in this case.
• Electrolytic and ceramics capacitors also in through hole format
• an DIP ATmega328P since I had those available. Using a SMD package would allow one to build that PCB way smaller
• A cheap LM358 OpAmp in through hole technique too since I have a bunch of them lying around and their noise level is acceptable for the given application
• A through hole 3 pin resonantor including the capacitance against ground required by the AVR. In theory one could use the on chip oscillator but it helps for the stability of the serial port to use an external oscillator anyways.
• The through hole PC817 optocoupler - slow speed but really cheap and sufficient

The layout of the PCB facilitates a copper filled ground plane on the high voltage and logic side. The PCB has been milled below the optocouplers as usual to prevent any residual solder or leakage currents from the high voltage to the low voltage side. One usually also does this between line power and low voltage sections for the same reason. Usually one could also have reduced the material amount between high and low voltage side further in the orthogonal direction above.

The connectors are standard raster size for all common types of screw clamps or pin headers.

Note that the mounting screws are close to the high voltage grond plane - i.e. when mounting to some non biased case you’d have to use Nylon screws and enough spacing.

The design files that have been used to order the PCB at PCBWay have been generated using the Gerber export method of KiCad. They are available in the GitHub repository. PCBWay has been choosen as a manufacturer because they offer a pretty cheap but high quality prototyping service - without shipping you can get for example 5 dual layer FR4 PCBs for about 5\$ with 24 hours of manufacturing time. The PCBs still offer all features like high quality prepregs, uniform copper coating with the specified thickness, supported spacing down to BGA packages, different solder mask colors, printed silkscreen and passivation surface finish. The process of getting them ordered just takes a few minutes - enter the size of the PCB and requested properties at the intsant quote section, upload the ZIP file containing the exported Gerber files (make sure to not use extended V2 format, use minimal header, PostScript map file for the Excellon drill file and suppress leading zeros there) and you’re ready to go. After uploading the ZIP the PCB is manually reviewed by skilled engineers - when you request manufacturing that violates design rules, etc. you get a pretty quick response and when everything is ok the PCB goes into production usually within less than one or two hours. After at most 24 hours the PCBs get shipped so you can build them pretty fast (depends on the selected shipping method and your local customs though, that’s the main bottleneck).

## The software side

The controller software has been developed in ANSI C, compiled with avr-gcc, and annotated using ACSL for static analysis with Frama-C as usual. All tests are automatically executed using a Jenkins pipeline though programming using avrdude is not automated using a pipeline due to the physical connection needed in this case.

The source code for the firmware is available on GitHub together with a Python library that allows one to invoke the functions of the microcontroller using a simple USB to TTL serial adapter.