Tuesday 5 April 2016

Lab Power Supply - Raspbery Pi Control

So finally I got round to building some code to implement a basic GUI for the power supply. This showed up an anomaly in the current readings that lead me on a hunt to somewhere I didn't expect.

Control Interface

So a while back I bought a new Raspberry Pi (PI 2B) and the official Raspberry Pi touch screen. The plan has always been to make the Pi a touch based user interface for the power supply. I found a Python GUI library called Kivy that works on Windows. Mac and Raspberry Pi and which provides pretty much everything I might need to implement the user interface.

Kivy is really focused on 2D and 3D graphics more than user-interfaces but it does provide buttons and input fields. I am pretty sure that this is all I need plus some colour and maybe later I might use the 2D primitives to do some current graphs.

Being Python I started by writing the code on my Mac and then moved to the Raspberry Pi.

Kivy comes with its own language that you use to describe the graphical layout (in a .kv file). These then get bound to Python classes at runtime. 

Field Binding

You can bind fields in the display to data members in the classes and if the data member changes, the GUI value will be updated. You can even use conditional expressions in the kv language to control fields. For example in my application I use an expression to change the colour of the text to grey if the power supply channel is disabled or in current limit.

Initially I had some trouble with this as I set the value of fields based on regular functions or data in my class. The problem with this is that the Kivy runtime can't 'observe' those functions and so the values would not change in the GUI when they were updated in the class. Instead you have to create members that are of type ObjectProperty and set/get these.

Layout

So you can create a class that is essentially a canvas that you can compose into a bigger window. I created one panel for each power supply channel and then created an overall window that contained three instances of the channel (one for each PSU channel).

I used quite big text for everything as it had to be fat-finger driveable. I figured the most important things are
  • The output voltage (measured by the PSU)
  • The output current (ditto)
  • The set voltage
  • The current limit
  • Enabling/Disabling the channel
  • An indication of if the channel is enabled/disabled
  • An indication of if the channel is in current limit
  • (Nice to have) The output power
The output voltage, current and power are the biggest font. The text goes green if the channel is enabled, grey if disabled and red if in current limit. This is no good if you are colour blind so I may change this scheme to something else later.

The set voltage/current is in small text with a button to bring up a dialog to set it.

There is a big enable/disable button at the bottom for each channel. If I can I will align the binding posts for each channel with the screen and these buttons.

Here is how it looks running on the Raspberry Pi touchscreen and communicating with the lab supply. The numbers are a bit off as it needs to be calibrated.


Here is the dialog for editing the output voltage. The same dialog with different labels is used to set the current limit.


The dialog needs some work I think :
  • The buttons are too small for fingers
  • The V/mV buttons are not worth it. Just have V
  • You have to back-space to reset the value. If you miss the DEL button is dismisses the dialog and you have to start again.
  • Really need some mechanism to be able to slowly sweep the voltage up. For example either a physical dial or a dial/slider on the GUI somewhere (ideally without leaving the main screen).

Updating

The code uses the Kivy Clock class to schedule updating of the values. The first thing I noticed was how stuttery the dialog was when I enabled the updating. This was a simple fix as I just disable the scheduler when the dialog is open and re-enable it when the dialog is dismissed.

It quickly became apparent that the update rate is pretty slow when running at 9600 baud. I plugged the USB cable into a Windows machine where the MCP2200 utility was present and changed the baud rate to 115200.

I then went to change the baud rate in the firmware and remembered how much trouble I had setting this in the first place, The calculations for setting the baud were pretty far off. After some Googling I figured out that there is a fuse that is set by default and that sets the internal clock speed to the crystal frequency divided by 8. Not even sure why they do this.

This program has been interrupted to bring you this message...

And that's when everything went wrong. I have been having intermittent problems with programming the chip and at some point the device simply stopped responding. It could be that the fault meant the fuse bits got whacked to some bad value. The device was essentially bricked,

One thing I noticed was the output from the micro controller during programming (the MISO line) looked like it was fighting with some other voltage. I figured out the state of the chip select for the AD7705 was low which meant it could be trying to control the bus. I figured out that what I should have done is tied the reset line of the AD7705 (and the AD5689) to the microcontroller's reset line so that during programming they won't try and control the bus regardless of the state of their select lines. I hacked the board to make this the case but still it wouldn't go. The MISO line looked clean however.

I de-soldered the micro-controller and soldered a new one on. A task made much easier with the recent purchase of a new toy (more on this later).

This got me back on the road and I was able to program and communicate with the board again.

Python Serial

Up until this point I have been communicating with the board via Python by simply opening the device (/dev/ttyACM0) as a file. The default baud rate was 9600 baud so this worked fine but now that I changed the baud rate I needed to do a fcntl() on the file descriptor to change the baud when I open it. To make matters worse the fcntl() parameters are different between Mac and Linux (Raspberry Pi) and messy.

I found this cross platform library called pySerial that could do all this for me. Further more, it implemented a timeout mechanism in case the device doesn't respond (which was a problem I hadn't solved with the file interface). The library was available for all the platforms I wanted and this worked quite well.

Weird Current Readings

So with all the soldering/de-soldering, the calibration was a tiny bit off. Furthermore I haven't really tried to calibrate the current yet so I wasn't surprised to see the readings were wrong.

When the power supply was running with 10V output and zero output current the reading was around 22mA. I just assumed this was an offset error but I noticed that as the voltage increased so did the zero reading (pretty much linearly). Interestingly the current measured when a load was placed on the output looked pretty close.

I assumed that I had a current leak but I really couldn't find a possible current path. Sure the differential amplifier measuring the output voltage will take some current but it is tiny compared with this.

I found another small ground problem for the amplifier that measures the current but it was pretty small (few hundred micro-volts). I measured the voltage across the shunt and it was tiny - far smaller than the reported value.

Being quite stumped at this point I went back to the simulation and found that it too had a discrepancy. This was masked by the switch model I used for the output load as even when the switch was off a few mA flowed. When I disabled this I noticed that there was a discrepancy there too.

I was looking at the output of the amplifier that senses the voltage over the shunt. I realized this voltage was also used in the summing amplifier inside the pre-regulator. The summing amplifier boosts the bulk capacitor voltage when there is output load. The summing amplifier looks like this:

Then it clicked - as the resistor in this amplifier were only 10K, the Voutmon was affecting Ioutmon and this is why the current reading was high when the output current was low (or zero).

To test this I cut the track to R46 from Ioutmon and sure enough the offset went away.

I went back to the simulation and tried changing the 10K resistors to 100K and while this massively reduced the effect it created ringing and other dynamic stability problems in the summing amplifier.

I think to fix this I'd have to buffer the output with another amplifier. The current measurement is likely effecting the output voltage measurement when there is load on the supply. I probably need to buffer both.

I have one spare op-amp on one of the LT1639 chips. My plan is to swap the LTC2050 used to measure the output current for a dual opamp package (LTC2051). This unit has the same performance specifications but contains two amplifiers in the same footprint. Then I can use one of these to buffer the current and the spare LT1639 op amp to buffer the voltage and that should be that.

Next

There is still lots of work to do on the GUI but the board is getting to the point where I am not sure I want to hack it any more. It might be time to spin a new PCB to fix all the problems.

No comments:

Post a Comment