A digital DC power supply -- part 2: the software

ArticleCategory: [Choose a category, do not translate this]


AuthorImage:[Here we need a little image from you]

[Photo of the Author]

TranslationInfo:[Author + translation history. mailto: or http://homepage]

original in en Guido Socher

AboutTheAuthor:[A small biography about the author]

Guido likes Linux because it is a really good system to develop your own hardware.

Abstract:[Here you write a little summary]

This is the second part in the series about the digital power supply. You might want to read the first part first.

There will be a third part where we add i2c communication to control the power supply via command from the PC and maybe a fourth part where more fancy things are added. I am thinking of not only producing DC voltage but also DC + pulses and spikes. This way you can test circuits to make sure that they are resistant to noise and variations in power.

A kit with the board and parts for this article is available from shop.tuxgraphics.org.

ArticleIllustration:[This is the title picture for your article]


ArticleBody:[The article body]


Using a clever microcontroller based design we can build a power supply which has more features and is a lot cheaper than traditional power supplies. This is possible because functions which are traditionally implemented in hardware are moved into software.

In this article we will do two things:

A word of warning

This article will give you insights as to how the software works and you can use the knowledge to do modifications. However be aware that the short circuit protection is also only software. If you make a mistake somewhere then this protection may not work. If you then cause a short circuit on the output your hardware may go off in a could of smoke. To avoid this you should use a big resistor (e.g bulb from a car front light) which will draw enough current to trigger the protection (e.g 6A) but not enough to destroy the hardware. This way you can test a short circuit without any danger to loose the hardware.

The structure of the software

When you look at the main program (file ddcp.c, download at the end of this article) you will see that there are only a few lines of initialization code executed at power on and then the software enters an endless loop.
There are really 2 endless loops in this software. One is the main loop ("while(1){ ...}" in file ddcp.c) and the other one is the periodic interrupt from the Analog the Digital Converter (function "SIGNAL(SIG_ADC){...}" in file analog.c). During initialization the interrupt is configured to execute every 100μ Sec. All functions and code that is executed runs in the context of one of those tasks (task the name for a process or thread of execution in a real time OS, so I use this word here even if there is no OS).

The interrupt task can stop the execution of the main loop at any time. It will then execute without being interrupted and then execution continues again in the main loop at the place where it was interrupted. This has two consequences:
  1. The code in the interrupt must not be too long as it must finish before the next interrupt comes. What counts here are the amount of instructions in machine code. A mathematical formula, which can be written as just one line of C-code may result in hundreds of lines of machine code.

  2. Variables that you share between interrupt code and code in the main task may suddenly change in the middle of execution. This is also valid when you hand more than one byte of data from the interrupt to the main task. The copying of two bytes will require more than one instruction and then in can happen that the first byte is copied before the interrupt while the second byte is copied after the interrupt. What to do? In most cases it is not a problem because the measurement results from the ADC will not differ too much between two interrupts. In cases where you can not afford this type of occasional fault (it may happen only once every hour) you have to use a flag which you can check to see if your code was interrupted during the copying.
All this means that complex things like updating of the display, checking of push buttons, conversion of ampere and volt values to internal units etc ... must be done in the main task. In the interrupt we execute only things that are time critical: Current and voltage control, overload protection and setting of the DAC. To avoid complex mathematics all calculations in the interrupt are done in ADC units. That is the same units that the ADC produces (integer values from 0...1023).

Here is the exact logical flow of operations that we do in the main task:
1) Copy the latest ADC results from the interrupt task
2) Convert them into display values (ampere and volt)
3) Convert the wanted ampere and volt values (what the user has set)
   to internal equivalent ADC values
4) Copy the wanted equivalent ADC values to variables such that
   the interrupt task can use them.
5) Clear the LCD display
6) Convert the numbers which we want to display on the LCD into
7) Write voltage values to the display.
8) Check if the interrupt task regulates currently voltage or current
   (current limitation active)
9) If voltage is the limiting factor then write an arrow behind
   voltage on the display
10) Write ampere values to the display
11) Check if the interrupt task regulates currently voltage or current
    (current limitation active)
12) If current is the limiting factor then write an arrow behind
    current on the display
13) Check if a button was pressed. If not wait 100ms and check again.
    If a button was pressed then wait 200ms. This is to have a good
    response of the buttons and not too fast scrolling if they are
    permanently pressed.
14) Go to step 1).
The interrupt task is much simpler:
1) Copy the results from the ADC to variables
2) Toggle the ADC measurement channel between current and voltage
3) Check if excessive current is measured. If so set the DAC immediately
   to a low value (It does not have to be zero since the voltage 
   amplifier circuit works only from 0.6V on (0.6 volt input
   produce still 0 volt output)).
4) Check if voltage or current needs to be regulated
5) Check if the DAC (digital to analog converter) needs updating
   according to the decision from 4).

This is the basic idea of the software. I will also explain what you find in which files and then you should be able to understand the code (given that you are familiar with C).

Which file contains what

ddcp.c -- this file contains the main program. All initialization is
         done from here.here.  The main loop is also implemented here.

analog.c -- the analog to digital converter and everything that
         runs in the context of the interrupt task can be found here.

dac.c -- the digital to analog converter. Initialized from ddcp.c but
         used only from analog.c

kbd.c -- the keyboard code

lcd.c -- the LCD driver. This is a special version which will not need
         the rw pin of the display. It uses instead an internal timer
         which should be long enough for the display to finish its task.

New functionality: store settings

The new functionality we add in this article is not much since I spent already a part of this article to explain how the software works and I don't what to make the article too long.

Still the function we add now is essential: Store the setting such that the voltage and current must not be set again after the next power on. We store those values in the eeprom of the microcontroller. All eeproms (including usb-sticks) have limit as to how often a eeprom storage cell can be written. For the Atmega 8 this is 100000 times. After that the eeprom is warren out and may not keep the values any longer. A trick to get longer life time is to write over several cells but let's first calculate what this means for us. 100000 write cycles corresponds to storing 10 times a new setting per day for 25 years. This is more than enough. We can therefore just use the simplest solution and store into one eeprom address.

So how do you store/read something to/from the eeprom? There are two instructions eeprom_read_word and eeprom_write_word to read or write 16bit integers into the eeprom. eeprom addresses start from zero and count in bytes.

One complication is that the eeprom is erased when we upload new software. So we need to be able to know if we have read some garbage from the eeprom (because the software was previously flashed) or if we have valid ampere and voltage values in the eeprom. We do this by writing a magic number into the eeprom. In other words we store every time 3 things: ampere limit, voltage limit, magic number. If we read after power on the eeprom then we check first for the magic number. If it is our number then the values for ampere and volt are correct. The magic number can be anything which is not likely to be there by default (e.g 19).

To see the exact code look at the function
store_permanent() in ddcp.c (download at the end of this article).

The software for this article is digitaldcpower-0.3.X where X is the revision which I plan to step if there are updates needed (the software for the previous article was (digitaldcpower-0.2.X).

Have fun! ... The next article will add I2C communication to the power supply from the PC. So you can not only press a button on the power supply to change something but you can do it via command.

I am looking for people who can port the i2c host programs to different operating system. Let me know if you can help here. You need some knowledge about control of the rs232 interface and a compiler. The actual change affects probably only one line of code (the ioctl function).

The whole circuit with all parts and a printed circuit board is available from shop.tuxgraphics.org (see below).