Sunday 8 November 2015

Lab Power Supply - Transition to KiCAD and PCB

In another post I talked about learning KiCAD and converting from Altium's Circuit Maker. So now I have the Lab PSU schematic fully in KiCAD and I have created footprints for all the components. I have a PCB design and have placed an order with Seeed studio! Exciting!

I made a couple of small changes and those were :

  • I created a circuit to detect CC mode and interfaced this with the micro controller. 
  • I moved to using a 24V relay as this way I could minimize the heat losses in the regulators feeding the relay circuit.

KiCAD Schematics

First up, here is the the power circuit as drawn in KiCAD
Things to note are the 24V relay I previously mentioned, the 24V regulator that is running off the bias rectifier and the move back to a TO-220 regulator for the 5V line. I worked out that in parallel mode the voltage on the rectified is about 28V which is easily enough room for a 24V regulator. In 40V mode we have even more room. The 24V relay also has a 1.4K coil resistance so this lowers the power loss by even more.

Otherwise the circuit is as before with a transistor switching the relay and another switching the bias regulator between 24V and 40V.

Next is the pre-regulator based on the black-dog design but with the changes to minimize the voltage when the load is low.


Now I have bypassing for the comparator. The circuit that subtracts 3V from the pre-regulator got moved a little as it was easier to draw. Otherwise this is unchanged from the previous design.

The voltage and current regulator design is pretty much as before. I added resistors between the Sense+ and V+ and between Sense- and V- outputs so if the sense lines aren't hooked up the supply will still work.

The other change was the addition of the transistor circuit attached to the output of the voltage controller. The first PNP  transistor (Q8) switches off when the output goes within 0.6V of the rail. This occurs when the current limiter has kicked in and the voltage controller is driving the output to the rail to try and get the voltage up to the set point. When the PNP turns off then this turns off Q9 which will send the CCMode line low. Q9 switches the 5V line so the CCMode signal is a 5V logic signal.

Finally the digital control circuit:

As suggested by people on the EEVBlog forum, I used lines to connect signals instead of using labels. I'm not sure this makes it clearer. Otherwise the only change is that I added more bypassing as per the datasheets of the components. This meant a *lot* of additional capacitors as components like the ADUM1201 need two for each side and the micro controller has one for each power pin.

I switched back to using a crystal instead of a ceramic resonator for the ADC as the stability may effect the readings. The MCP2200 USB chip and the ATMEGA328P still use ceramic resonators as they are very convenient.

I added a ferrite to join the digital and analog power nets. This is to stop the digital noise getting back into the current sense circuit (which is also 5V).

PCB

I feel like I have been designing the PCB in my head for weeks. Every time I read a datasheet that has layout guidelines or another paper on bypassing or noise I seem more of the picture.

First I needed to pick a PCB Fab house. PCBShopper helped a lot although in the end I went with SeeedStudio as they seem well supported and popular amongst hobbiest projects. I first made sure that KiCAD was configured with the rules  which actually weren't that stringent.


The main things that drive the PCB design are:
  1. The board needs to be no more than 80 or 90mm wide so I can fit 3 of them on my heatsink side by side.
  2. The MOSFETs and regulators need to go at the back to go on the heatsink.
  3. The output needs to go at the front
  4. The analog and digital sections need to be separate. ADCs and DACs need to be at the edge.
  5. No ground plane in the analog part - star ground from the current shunt. Ground plane for the digital part.
  6. No digital lines under analog chips
  7. Fat traces for current carrying connections.
I started by placing the output MOSFET and then the pre-regulator mosfets across the back and then the LM317s. Then I put the capacitors in as they are quite large and need to be close. I figured out the best place for the input connector was in the middle but close to the back and I placed the relay and diode bridge alongside. I put the output connector at the front and all the MOVs along the front edge.

Now I have a small space at the back between the bridge and the MOSFETs for the pre-regulator and power circuits and a larger space at the front for the analog and digital control.

I router the power traces and the pre-regulator. The fat traces proved to be hard. Ideally I would have 10mm traces but 6mm was about the biggest I could really fit.

The pre-regulator was not too hard to place and route. I took the approach of starting with the main component (like a comparator or an op amp) and then starting with one of the resistors/capacitors attached to it. I placed them one at a time and choose the next one connected as I go. I try and line them up in columns (on a 0.5mm grid).

Then I placed the op amps in the analog control circuit and placed/routed the associated components. I left power and ground until last.

I switched to the digital part and after some fiddling decided to place the processor and programming header close together toward the back, then place the USB, USB controller and isolator closer to the front corner. The ADC/DAC go toward the middle (nearer to the analog part).

The digital part was very hack-and-slash compared with the analog routing. I figured out how to make a copper pour and this looked ok. I have a separate copper pour for the isolated USB part also.

The through-hole USB connector was tricky as I needed a *very* fine track to get between the pads. If I don't go between pads then the trace length difference will be too big and it could effect the reliability. This was the one spot where I had to use the minimum track size.

So I stared at it for a few days and tweaked things. In the end I placed an order. Main things I am still not sure about are 
  • If the bypass capacitors are close enough to the chips. I think this is where using smaller parts would have helped.
  • (In hindsight) if I should have put the reference in the analog section away from the digital ground plane.
  • I probably should have done a top-side AND a bottom side copper pour in the digital section.
I found this guide useful when exporting the board ready for Seeed. I had no problems getting the fab to accept the board.

Here is the board. Output MOSFET at top left, then pre-regulator MOSFETs below that. The two LM317s for 5V and VCC at bottom and the bulk cap for those nearby. The input connector, relay and diode bridge are in the middle. USB at bottom right, MOVs and ground link above that. Output connector top right. Current shunt and fuse to left of output connector.


So I have ordered the boards and the remaining parts. Now I wait!





Thursday 5 November 2015

C++ Lightweight template based encoders

I recently had to implement an encoder that could translate an ActiveMQ MapMessage into a a small number of C++ object. The traditional approach is to create a class that knows how to decode various field types and derive all the message classes from this and have them decode themselves from a MapMessage, I wanted to avoid dragging all the baggage associated with encoding/decoding into each message class object and do it another way.

A while ago I experimented with creating classes that act as a sort of template that defines the encoding format for a message. The template object is static and really just directs an encoder/decoder so it know how to populate or encode the message object. I used a simple version of this technique to solve this problem and I thought it is interesting enough to describe here in case I need it another time.

The solution I came up with looks a lot like how you would do this in Java using reflection but uses C++ and templates.

Edit: Since writing this article I went through the process of porting the code to g++ (it was originally developed using Microsoft Visual Studio 2008). Unfortunately this highlighted quite a lot of deficiencies in Visual Studio's template support so I have amended the article to cover this.

Function Pointer

The problem is how can the template object modify or read the message object contents without exposing everything (without breaking encapsulation). The answer is to use function pointers to operate the accessor functions. Say we have a class like this:

class TestMessage
{
public:
    const std::string getName() const;
    void setName( const std::string& name );
};

Then we can provide access to the name field for any instance of this class if we know what functions to call. We can use a pointer to the getName() and setName() function to provide access to the name field of any instance of a TestMessage. It's like a key you can use to unlock this field from any TestMessage. So if we define two function pointer types like this;

typedef const std::string& (TestMessage::*GetterFunc)() const;
typedef void (TestMessage::*SetterFunc(const std::string&);

Now we can get the function pointer values by doing this:

GetterFunc getter = &TestMessage::getName;
SetterFunc setter = &TestMessage::setName;

Then say we have an instance of a TestMessage, we can get or set the name field like this:

TestMessage messageInstance;

std::string nameValue = (messageInstance.*getter)();
(messageInstance.*setter)(nameValue);

Say we had a message template class that store the setter and getter function pointer for each field, we could then use these to set the message content when decoding or read the content when encoding. The template class just has to store the function pointers and can apply them to each message instance it decodes or encodes.

The tricky part is that the function pointer type varies with the message type and with the field type. We need some way of unifying this all and being able to configure a list of fields to get/set per message.

MessageTemplate template

The answer is to create a MessageTemplate base-class that is a C++ template with the message type as a parameter. Some something like this:

template<class MessageType>
class MessageTemplate
{
public:
    virtual void toFields( 
        const cms::MapMessage& mapMessage,
        MessageType&           message  const;

    virtual void fromFields(
        cms::MapMessage&       mapMessage,
        const MessageType&     message) const;

    ....
};

Now to perform these two operations, this class needs to know how to translate a message field into a message class field (a field adapter). These will vary by field type but we need a base-class for all of these so we can stuff them into a list and then iterate over them all to perform the conversion. The base FieldAdapater will looks like this:

template<class MessageType>
class FieldAdapterBase
{
public:
    FieldAdapterBase(const char *fieldName,const bool optional) 
        : m_fieldName(fieldName),m_optional(optional)
    {
    }

    virtual void toField(
        const cms::MapMessage& mapMessage, 
        MessageType& message) const=0;

    virtual void fromField(
        cms::MapMessage&       mapMessage, 
        const MessageType&     message) const=0;

protected:

     const char *m_fieldName;
     const bool m_optional;
};


In addition to the field name, the FieldAdapterBase stores if the field is optional or not. This allows for fields that don't have to always be present. The class provides a common interface for converting a single field regardless of field type.

The next step is to extend this to provide the function pointer bindings and to allow this to vary with field type. Hence we define this class:

template<class MessageType,typename FieldType>
class FieldAdapter : public FieldAdapterBase<MessageType>
{
public:
    typedef const FieldType& (MessageType::*GetterFunc)() const;
    typedef void (MessageType::*SetterFunc)(const FieldType&);

    FieldAdapter( 
        const char *fieldName,
        GetterFunc  getter,
        SetterFunc  setter,
        const bool  optional ) 
            :   FieldAdapterBase<MessageType>(fieldName,optional),
                m_getterFunc(getter),
                m_setterFunc(setter)
        {}
    
protected:

    GetterFunc  m_getterFunc;
    SetterFunc  m_setterFunc;
};

Here we define the function pointer types and we store function pointers to allow conversion. There is still no conversion going on yet. This class just provides a convenient common base for all the converters so we don't have to define the function pointer type over and over.

One problem with this class is that returning or passing const references doesn't make sense for POD types (integers etc). To make this easier we also define a POD version of the FieldAdapter:

template<class MessageType,typename FieldType>
class PODFieldAdapter : public FieldAdapterBase<MessageType>
{
public:
    typedef const FieldType (MessageType::*GetterFunc)() const;
    typedef void (MessageType::*SetterFunc)(const FieldType);

    PODFieldAdapter( 
        const char *fieldName,
        GetterFunc  getter,
        SetterFunc  setter,
        const bool  optional ) 
            :   FieldAdapterBase<MessageType>(fieldName,optional),
                m_getterFunc(getter),
                m_setterFunc(setter)
        {}
    
protected:

    GetterFunc  m_getterFunc;
    SetterFunc  m_setterFunc;
};

A FieldAdapter for encoding string types into the ActiveMQ message would then look like this:

template<class MessageType>
class StringFieldAdapter 
    : public FieldAdapter<MessageType,std::string>
{
public:
    StringFieldAdapter( 
        const char *fieldName,
        typename FieldAdapter<MessageType,std::string>::GetterFunc  getter,
        typename FieldAdapter<MessageType,std::string>::SetterFunc  setter,
        const bool  optional=false,
        const CYBERTRUST::String& defaultValue =
            CYBERTRUST::String::emptyString) 
        : FieldAdapter<MessageType,CYBERTRUST::String(
              fieldName,getter,setter,optional),
          m_defaultValue(defaultValue)
    {
    }

    virtual void toField(
        const cms::MapMessage& mapMessage, 
        MessageType& message) const
    {
        if ( this->skipOptional(mapMessage) )
        {
            return;
        }

        try
        {
            std::string value =  
                  mapMessage.getString(this->m_fieldName);
            (message.*this->m_setterFunc)(value);
        }
        catch( const cms::CMSException& e )
        {
            handleMissingFieldException(e);
        }
    }

    virtual void fromField(
        cms::MapMessage& mapMessage, 
        const MessageType& message) const
    {
        std::string value((message.*this->m_getterFunc)());

        if ( !this->m_optional || (value != m_defaultValue))
        {
            mapMessage.setString(
                 this->m_fieldName,
                 value);
        }
    }

protected:

    std::string m_defaultValue;
};

As you can see I skipped a few details like handling exceptions. The exception handling function is actually part of the base but all it does is translates the exception to something meaningful to my application.

A few other notes on this code:

  • Initially the type of the setter/getter function pointer was just GetterFunc and SetterFunc. When I compiled the code on g++ I found that I had to use the full template name AND the typename keyword to make sure the compiler knew I was talking about a type. The problem is that the compiler doesn't fully compile the templates until instantiation.
  • Whenever the code refers to an inherited data member or function I have to use the 'this->' construct as (again) the compiler doesn't fully compile the code until later.
So now we need to go back to the MessageTemplate<> class to see how to make these field adapters work. The application can sub-class a MessageTemplate and register a field adapter for each field. We need to provide a means of registering each type of field and for stuffing all the adapters in a list and processing them all. So now the MessageTemplate<> class looks like this:

template<class MessageType>
class MessageTemplate
{
public:
    virtual void toFields( 
        const cms::MapMessage& mapMessage,
        MessageType&           message  const
   {

        typename FieldAdapters::const_iterator nextFieldAdapter;

        for(    nextFieldAdapter=m_fieldAdapters.begin();
                nextFieldAdapter!=m_fieldAdapters.end();
                nextFieldAdapter++ )
        {
            (*nextFieldAdapter)->toField(mapMessage,message);
        }
   }

    virtual void fromFields(
        cms::MapMessage&       mapMessage,
        const MessageType&     message) const

    {
        typename FieldAdapters::const_iterator nextFieldAdapter;
        for(    nextFieldAdapter=m_fieldAdapters.begin();
                nextFieldAdapter!=m_fieldAdapters.end();
                nextFieldAdapter++ )
        {
            (*nextFieldAdapter)->fromField(mapMessage,message);
        }
    }

protected:


    void registerStringField(
        const char     *fieldName,
        typename StringFieldAdapter<MessageType>::GetterFunc getter,
        typename StringFieldAdapter<MessageType>::SetterFunc setter,
        const bool     optional=false,
        const std::string& defaultValue=std::string() )
    {
        m_fieldAdapters.push_back( 
            new StringFieldAdapter<MessageType>(
                fieldName,
                getter,
                setter,
                optional,
                defaultValue));
    }

    ....


    typedef std::vector< boost::shared_ptr< FieldAdapterBase<MessageType> > > FieldAdapters;

    FieldAdapters m_fieldAdapters;
};

To apply this to our TestMessage class we would define a MessageTemplate class as follows:

class TestMessageTemplate : public MessageTemplate<TestMessage>
{
public:
    TestMessageTemplate()
    {
       registerStringField(
           "Name",
            &TestMessage::getName,
            &TestMessage::setName );
    }
};

Then to use use this we do something like this:

TestMessageTemplate testMessageTemplate;

TestMessage testMessage;
// Init the testMessage contents

cms::MapMessage *mapMessage = session->createMapMessage

testMessageTemplate.fromFields(mapMessage,testMessage);

Advanved Topics

Enumerated Types

A bunch of the fields were enumerated types so I created a converter to specifically deal with these. The code is common but the enum type will vary by field.

template<class MessageType,typename EnumType>
class EnumFieldAdapter : public PODFieldAdapter<MessageType,EnumType>
{
public:
    EnumFieldAdapter( 
        const char      *fieldName,
        typename PODFieldAdapter<MessageType,EnumType>::GetterFunc      getter,
        PODFieldAdapter<MessageType,EnumType>::SetterFunc      setter,
        const bool      optional,
        const EnumType  defaultValue ) 
        :   PODFieldAdapter<MessageType,EnumType>(
                fieldName,getter,setter,optional),
            m_defaultValue(defaultValue)
    {
    }

...

};

Note that this is derived from the PODFieldAdapter as enums wouldn't normally be passed by reference. Then in MessageTemplate we define a register function like this:

    template<typename EnumType>
    void registerEnumField(
        const char *fieldName,
        typename EnumFieldAdapter<MessageType,EnumType>::GetterFunc getter,
        typename EnumFieldAdapter<MessageType,EnumType>::SetterFunc setter,
        const bool optional=false,
        const EnumType defaultValue=(EnumType)0)
    {
        m_fieldAdapters.push_back( 
            new EnumFieldAdapter<MessageType,EnumType>(
               fieldName,
               getter,
               setter,
               optional,
               defaultValue));
    }

Then say we had methods like this in out TestMessage class

enum EnumType
{
   ENUM_VALUE1,
   ENUM_VALUE2
};

const EnumType getEnumValue() const;
void setEnumValue(const EnumType value);

In our MessageTemplate class we could register this field as follows:

registerEnumField<TestMessage::EnumType>(
    "Enum_Field",
    &TestMessage::getEnumValue,
    &TestMessage::setEnumValue);

Subclasses

In my case the message types had a lot of commonality and it made sense to define base message classes and sub-classes. For example all of the response messages had common fields for the status of the operation and for returning error codes if the operation failed.

Say we had a ResponseMessage class and then another SpecialResponse that derives from this, we want the SpecialResponseMessage template to covert both the ResponseMessage fields and the SpecialResponseMessage field.

To make this work I created a class for sub-class templates as follows:

template<class ParentMessageType,class MessageType>
class MessageSubClassTemplate : public MessageTemplate<MessageType>
{
public:
    MessageSubClassTemplate( 
        const MessageTemplate<ParentMessageType>& parentTemplate ) 
            :   MessageTemplate<MessageType>(),
                m_parentTemplate(parentTemplate)
    {
    }

    void toFields(
        const cms::MapMessage& mapMessage, 
        MessageType& message) const
    {
        m_parentTemplate.toFields(mapMessage,message);
        MessageTemplate<MessageType>::toFields(mapMessage,message);
    }

    void fromFields(
        cms::MapMessage& mapMessage, 
        const MessageType& message) const
    {
        m_parentTemplate.fromFields(mapMessage,message);
        MessageTemplate<MessageType>::fromFields(
            mapMessage,
            message);
    }

protected:

    const MessageTemplate<ParentMessageType>& m_parentTemplate;
};

The basics of it are:
  • The MessageSubClassTemplate knows the MessageType has a base-type and that base type has a MessageTemplate of its own.
  • MessageSubClassTemplate derives from MessageType to implement the sub-class field conversion.
  • MessageSubClassTemplate takes as a constructor parameter a reference to the parent message class template.
  • When converting the fields, the MessageSubClassTemplate first converts the base class fields and then converts the sub-class fields (as normal).
To use this you create the base class template as before and then you create the sub-class template like this:

class SpecialResponseTemplate 
    : MessageSubClassTemplate<ResponseMessage,SpecialResponse>
{
public:
    SpecialResponseTemplate(
        const MessageTemplate<ResponseMessage>& parentTemplate )
    : MessageSubClassTemplate<ResponseMessage,SpecialResponse>(
          parentTemplate)
     {
         // register the SpecialReponse fields
     }
};

To use the SpecialResponseTemplate you construct it passing in the parent template and then use it like normal.

ResponseMessageTemplate responseMessageTemplate;
SpecialResponseTemplate specialResponseTemplate(
                           responseMessageTemplate);

SpecialResponse message;
responseMessageTemplate.toFields(mapMessage,message);

More

Other things worth doing might be to implement aggregate messages where you can have some-fields within a contained object.

At the moment you have to know what type of message to expect but it would be nice to define some factory mechanism where the system figures out what to instantiate for you and then runs the conversion. Sort of like a container for templates that does the encoding.

Anyway that's it for now but I'm sure this technique could be applied to all sorts of encoding and conversion problems.

Friday 30 October 2015

KiCad EDA

So after a long struggle I gave up on Altium Circuit Maker and went back to KiCad, So far this looks a lot easier but there is still a learning curve.

Circuit Maker

Circuit Maker is the free hobbiest/student offering from the Altium. Altium generally make very high-end products that sell for literally thousands of dollars a copy. I do remember Protel. I used it many years ago to design an 8051 microcontroller board that interfaced a set of shaft-encoders and a keypad to a Sun Workstation (back in about 1993). That would be my one and only commercial hardware design ever and even that was essentially a one-off (was using in a military training simulator).

Circuit Maker promised a lot - it is a free version of a high-end professional tool after all. The compromise they made to open it up for free use seemed ok for me - basically everything you make has to be published as an FOSS project on the Circuit Maker community site. Even component symbols and footprints get shared so anything you make (or other people make) can be shared and re-used. I don't mind sharing my work and I thought getting access to footprints created by others would make things quicker.

The install is pretty large and relatively slow given my fast internet speeds. There were two or three updates during the months where I was using it and these took an age to install. The updates also introduced a few instabilities I had not seen before too.

The things that finally made me switch were:
  1. The documentation is minimal and worse - if you Google for answers you find documentation for their commercial products which are similar but not the same. This makes it even more confusing.
  2. The workflow seems ass-about. You can't just smack a component onto the schematic and figure it out later. You have to select the component from an online library (it was Clivia but later changed to Octopart) then if there isn't a 'model' for it you have to create a schematic symbol and a footprint. There are very few standard symbols so you end up searching for a similar component and copying that. Worse - there will be 10 versions depending on who drew it. This process doesn't matter too much if drawing up the schematic and designing the PCB are your final steps. In my case I was proto-typing and simulating the schematic and updating Circuit Maker as I went. The problem is you end up wasting a lot of work if you change your mind.
  3. I am very new to PCB design and yet here I was designing footprints and sharing them with other people. These purported to be footprints for well known components from the library but I've never tested if the footprints will fit. I have to commit them (which shares them) in order to add them to my schematic so I had no choice but to spread my junk.
  4. Having everything run off the net is fine if you are backed by infrastructure like Google's. To begin with the network speed was ok but it was very noticible when you saved or accessed libraries. The further I went into the trial and perhaps the more people that signed up, it got slower and slower. On one of the updates the part library tool would loose its mind every so often when the net access timed out and either crash or just return an error and not let you select the part. This problem was exaggerated when browsing the part library to choose a footprint or symbol. I'm not sure where they host the system but given they are an Australian company and I am in the same city as the developers you'd think it would be snappy.
  5. Ok it is a beta but the stability wasn't great. The last straw was when I tried to create this same 24V relay part 4 times in a row and it failed with an SQL error each time. Each time took ages because of the network slowness I explained above. At this point I had re-designed a big bit of my circuit and really couldn't face building everything again.

KiCad

KiCad has a rather primitive UI and limited documentation but there are lots of resources on the net including an extensive set of videos by Chris Gammel's contextual electronics channel.

KiCad is Mac/Linux/Windows, easy to install.

Multi-sheet Schematic

The Lab power supply I am developing really needs to be split into multiple schematic sheets. Initially I didn't see how to do this as there didn't seem to be a way to create new schematic files. Turns you have to work in a hierarchical fashion so you have a root schematic with symbols for each child schematic.

You can use the root sheet as a sort of a block-diagram by defining any interconnections as ports amd then connecting them in the root sheet. So the steps are
  1. In the root sheet select 'Create hierarchical sheet'. Click on the sheet, drag to size.
  2. Select a filename and sheet name for the sheet
  3. Right click the sheet and select 'enter sheet'. Now you are editing the sub-schematic sheet
  4. At some point you want to define nets that will appear on other sheets. You can do it two ways - you can create a  'hierarchical label' which is essentially a port into or out of your sheet or you can place a global label which can be seen anywhere. Say we create a hierarchical label for now
  5. Now leave the sheet to go back to the root sheet
  6. Right click the sheet and choose import sheet pins. Place there on the sheet symbol. Now you can interconnect the sheets via these pins.
If you don't care about the high-level block diagram just create the sheets and use global labels. All you will see in the root sheet is empty boxes but for a small project that probably doesn't matter.

Parts Libraries

So the second part I placed wasn't in the library. I think this is why I thought Circuit Maker would be easier when I was considering this before. I wanted to create an LT1639 quad op amp package. So the process is this:
  1. Open the parts library editor. Click the 'Load component to edit' button (unless you want to draw it from scratch - which I didn't). I picked another quad op amp package.
  2. Click the 'Create a new component from the current one' Fill in the details of the component
  3. One of the things it asks is the number of parts per package which is 4 in my case.
  4. There is a drop down on the top right that lets you go to each component (op amp) in the package. Check the pins assigned to each component are correct (they were not for me).
  5. Now the tutorial suggest creating a library for your project and saving everything into this. I want to be able to easily re-use these components in other projects so I didn't do this.
  6. Choose the open book symbol in toolbar called 'save component to new library'. This prompts you for a file name and away it goes.
  7. Now go back to the schematic editor, select the preferences->set active libraries menu. Select the project directory in the search path box at the bottom and then select the 'insert' button at the top right. Choose the name of the library you just created. Ok the dialog
  8. Now if you select the component tool you should be able to search for and locate your new component and place it on the schematic.
Easy! At some point I will have to create footprints for them all.

Other things I learned:
  • The round circle on the pins goes on the outside. This is where wires attach. The left/right pin thing seems backwards to me but meh
  • You can fill a box or poly-line easily. You close the shape and then right-click one of the lines and choose edit line. Then you select fill with either foreground colour (red) or background colour (yellow). I filled chip boxes with background but when I re-drew the SCR (as the one in the library was enormous! Like major hormonal problems large!) I filled the diode triangle in red.
  • Pins can have names, pin numbers and you can specify if they are input/output power etc. This is important for the electrical rules check.
  • In the parts library editor it is tempting to save by going to file->save current library as. If you do this then you will end up with a copy of whatever part you copied that also contains the part you created. I found this out the hard-way. To get out of this you click the save current component to new library thing and in the file dialog you delete the library and save to the same filename. 64KB down to 1KB - and much less confusion when selecting parts!
The editor is a bit clunky. Selecting things is a challenge. If you drag select something it assume you want to move it (not just select it). To delete something you aim your mouse carefully and hit the delete key. Really annoying if you want to delete a load of stuff - would be so much easier to drag-select and then hit del.

The M key is supposed to move but keep wires connected. I couldn't get this to work. It always broke the connections and so I had to re-wire them. Later I found out it is the G key that moves and maintains the connections. The M or G key only works for the item under the cursor though - if you want to move a block of stuff by dragging a rectangle around it, the default is to move without maintaining connections. It turns out if you hit tab after drag-selecting it is the same as hitting G (i.e. it will drag the block and maintain the connections).

The shortcuts are useful - w for wire in particular, a for add component, p for add power. I hit escape a lot to cancel the current mode.

Power

In my design I have an isolated USB interface so I have the USB power and ground which are different from any other power net. I needed to create a VUSB net and USBGND net but how to do it?

Turns out there is a library for power and ground symbols (power). In the library editor you can choose a 'part' from this library and copy/edit it as I described above for the op amps package. I saved this in another library.

When I went back to the schematic sheet I added the library but it didn't appear when I tried to add a power component. It turns out you have to select your custom power components via the parts libraries. Then they work as normal. Confusing? Yes very much so.

During this process I upgraded from 3.X to 4.0RC1 of KiCad and magically my custom power library started turning up when in the power device list.

Another mistake I made is that while I renamed the +5V power device, I didn't rename the pin (the power device is effectively a pin). This meant my VUSB power pin was connected to +5V which (thankfully) got picked up by the DRC. In the image below the blue righting identifies the part name but the grey writing is the pin name. If you right-click and edit the pin you can choose this to be what you want. If you copy another power symbol and don't change this then it will connect everything to the same net!


Footprints

Choosing the footprints all at once is *much* easier than selecting them as you go along. Most of the parts in my project had pretty standard footprints and I could just choose appropriate footprints from the library. I had to be a bit careful with the transistors as depending on the order of their leads there is a different schematic symbol (i.e. for ECB or BCE etc etc). Even the big 63V capacitors were easy as there was a standard footprint that fitted.

Oddly there was no SOT-223 footprint for the surface-mount LM317 I chose. I found a company called Ab2tech that published one on github. I couldn't figure out how to add their library from Git using either the wizard or manually. In the end I just pulled the one footprint I needed, copied this into my project directory and added it.

Many of the footprints I had to create were specified in millimetres. I wasn't sure what to do in regards making them comply with a grid so I decided to just specify their dimensions exactly from the data sheet. Soon find out if this is a problem!

I wasn't sure what size to make holes and pads for through hole parts. I found this guide that said to basically add 0.25mm to the lead diameter for the hole and then add 0.8mm for the pad size. In some cases the pads are carrying high current so I chose to make them a bit bigger again.

Board Layout

Once chose/created all the footprints I exported a net list and imported it into the PcbNew tool. I decided I am probably going to go with Seeedstudio as the board house so I looked up their specs and updated the design rules. The default rules were coarser than Seeed's so I generally left them as is (will change if I need to).

I need to make some of the tracks quite big to handle the current. If you start drawing a trace and then right-click there is a menu for changing the track width but it has no options to select. This is pretty confusing - so how do I change the track width?

Turns out in the Design Rules dialog KiCAD allows you to define 'classes' of nets and for each class you can define the track width, the via size etc. So I created a high-current, power and regular trace class. I assigned the nets as best I could and began work.



The thing is that not all of a net will have the same amount of current flow. For example the ground connection between the diode bridge and the bulk filter capacitor of a PSU or between the capacitor and the output will definitely need to be thick but the ground going to chip (consuming all of 10uA) will not. This doesn't work very well. Again when I try and change the track width there are no options and I can't.

Back to the design rules dialog - on the second tab (Global Design Rules) you can define 'Custom track widths' (you would think there are some standard track widths somewhere but apparently not). If you add some to this list then you can choose them when editing a track!

The next thing to do is to specify the board outline. Turns out there is a layer called 'Edge.cuts' and if you select this and then select the 'Add graphic line' tool (it's the diagonal dashed line symbol) you can draw the edge of the board.

You then load the netlist generated from the schematic which will dump all the components in a pile somewhere. I moved them off to one side so I could work.

The approach I took was to first place component that had to go in certain places - for example the MOSFETs and regulators that have to go on the heatsink need to be at the back etc. Then I would chose what part of the circuit goes where and slows place components one by one that are related. Basically start with a resistor etc, choose another one that connects to it and place that and so on.

To place a component you hit T and then type in the component designator (C33 for example) and that component appears under your cursor ready to plonk somewhere. Bit annoying if you accidentally pick one up you already placed but hey...

One part of my project is digital so I decided to use a ground plane in that area. There is a tool for this and when you select it and click somewhere it asks what net you want the plane to be and what layer to use. Then you draw the outline of the ground plane and hit end. To begin with nothing happened and after a while I realize it was because there was no ground track on that layer in the region. Just by adding a track into that region it then filled the rest. I make the bottom layer ground plane and the top signals (mostly). Then I added short tracks and via from any components that needed to connect to ground to attach them onto the ground plane. Easy!

Monday 12 October 2015

Lab Power Supply - Re-designed Pre-Regulator Testing

The new pre-regulator design turned out to be a good move overall in that I can now reach the full output power of the supply and the pre-regulator noise on the output has gone. It wasn't straight forward however and I still haven't sorted out how to make it work better in current limit mode.

Unfortunately I didn't capture too many pictures so you have to take my word for it!

Output Instability

After the usual small construction errors I got the circuit basically running  This looked pretty good and then I enabled a 1A load. Even with just 1A the output went into oscillation. Also the transformer would make a distinctive hum also. At this point I was really stuck - was the pre-regulator inducing a noise in the Gate bias supply? Was the pre-regulator affecting the voltage when it is sampling the current output voltage? I had a million thought - none good.

I fiddled with different voltages and noted that it didn't seem to occur as much at higher output voltages. It was worse when I increased the load however. At some point I managed to get a scope trace of the capacitor voltage and the output at the same time and saw that when the capacitor voltage fell to within a few volts of the output I got oscillation!

I experimented with boosting the pre-regulator voltage higher above the output and this worked but again when I try and run the supply at a higher load and or at a voltage closer to the maximum it would oscillate. The voltage difference wasn't small either - 4V. I thought a MOSFET would have a much lower dropout than that. Also the amount I had to boost the pre-regulator meant it again would not work at higher loads close to 14V.

I tried experimenting with the output capacitor. I increased the capacitor and found the instability went away (at least until the voltage difference was much smaller). Then I increased it to 2uF (from 0.1uf) and now the instability went away entirely.

I checked the transient performance and it was still well within spec - less than 20us to recover from 0 - 80% load. I call this a win!

I also experimented with changing the capacitor across the base-collector junction of the transistor that turns on the MOSFET to try and reduce the transformer noise. If I increase this the transformer makes less of a hum but then the MOSFETs get a lot hotter. I decided to leave it as it is (1nF).

Tuning

So then I went back to tuning the pre-regulator voltage based on the load and the output voltage. I realized that making one of the resistors in my summing amplifier bigger wasn't working the way I expected so I went back to making them equal. 

I experimented with the zener diode used to set how high the pre-regulator is above the output (with no load) and found 3.3V worked pretty well. This kept the pre-regulator close to the output and boosted enough to stop it getting caught short when the load ramped up quickly. 

The snapshot below shows the AC waveform (yellow), the bulk-capacitor voltage (blue), the ouput (pink) and the output of the comparator (that triggers the SCR to turn off the MOSFETs and stop charging the capacitor) in green. The capacitor is maintained a modest voltage above the output and the charging is consistent.



In this trace the output has been set for 14V and the load set for 3.8A. Here you can see it is charging for much longer into the cycle. The output is still very clean. The ripple is now over 5V.

I also looked at how the pre-regulator handled current limiting. In the trace below the load was set for 3.8A pulsing at 50Hz but the power supply was set for 1A max. You can see the  pre-regulator voltage is getting very low by the end of the 50Hz cycle.

The wheels really fall off when the output is low at the start of a couple of AC cycles. Then the capacitor voltage runs down to the minimum and when the cycles lose sync (right hand side) you can see the output spike back up to the set voltage again.

 While this looks pretty ugly I think it is ok. Current limiting is not a normal mode of operation but a safety feature. The output isn't overshooting the set point so there is no risk of damaging something connected to the output. I experimented with adding a peak-detector but I couldn't get this to work satisfactorily. Right now I don't see this as an issue.

Even at 3.99A (highest my dummy load will go) the output was clean.


And here is the current pre-regulator schematic



Thursday 8 October 2015

Lab power supply project - Pre-regulator re-design

The power supply design is now pretty close however I still have a few problems. I noted that at more than about 10V I can't get more than 4A of current before the output oscillates. I think the problem is that the maximum voltage the SCR pre-regulator's can achieve on the bulk capacitor is significantly less than the peak output of the transformer.

Also, no matter how hard I try to stomp on the ground issues I can't get rid of the last bit of noise on the output. The noise is a 1mV bump that occurs when the SCR fires to charge the bulk capacitor. The current flow causes the ground point to jump up a tiny bit and the output voltage to effectively drop by the same amount.

A while ago there was a discussion about low noise pre-regulators for linear supplies on the EEVBlog forum. A contributor called Blackdog described a pre-regulator that uses a P channel MOSFET as the pass element here on the EEVBlog forum. This design was picked up by another contributor Prasimix who is developing a 0-50V 3A supply here.

The Blackdog pre-regulator has a few advantages over what I am doing and may resolve some of my issues.

Blackdog Pre-regulator

The blackdog pre-regulator circuit is shown below:
The way it works is quite simple:
  • Two P channel MOSFETs (Q2, Q4) are used to turn on or off current to the main bulk capacitor.
  • The two AC inputs are combined and passed through an SCR (T1) and a resistor in series. The voltage on the SCR controls the voltage at the base of an NPN transistor (Q1) that drives the MOSFET gate. When the SCR fires the base of Q1 goes low.
  • A PNP transistor (Q3) with a voltage divider on its base turns on when the bulk capacitor voltage reaches a certain proportion above the voltage regulator output.
  • When Q3 turns on it fires the SCR which lowers the voltage at the base of Q1 and switches the MOSFETs (Q2, Q4) off.
  • The capacitor between the base and collector for Q1 causes the gate voltage to ramp down instead of suddenly dropping. This helps by to reduce noise.
  • When the voltage on the SCR falls (when we move to the next AC cycle). The SCR resets (commutates) which turns on the MOSFETs again and repeats the cycle.
So basically the circuit turns on the power to the capacitor at the start of each AC cycle and then turns it off when the capacitor voltage reaches the desired level. This has a lot of advantages over a traditional SCR pre-regulator
  • The voltage/current ramps up with the AC waveform. The peak current flows when the bulk capacitor voltage is at a minimum and the transformer voltage is ramping up and charging the capacitor. The traditional SCR pre-regulator turns on when the transformer voltage is high and the bulk capacitor is low and creates a significant current spike. I think it is this spike that is creating the unwanted output noise in my current design.
  • At the point where the MOSFET turns off, the capacitor has partially charged which means the current is lower than it would have been at SCR switch-on in the SCR design. The drop in current is changed to a ramp by the capacitor on Q1 which further reduces noise.
  • It is much easier to figure out when to turn power to the bulk capacitor off than it is to figure out how long to delay turning it on. This makes the circuit much simpler.
  • The Rds of the MOSFET is very low and results in a much lower voltage drop than the drop across the SCR.

Managing the Pre-regulator Voltage

The Blackdog circuit essentially sets the pre-regulator to a voltage that is some proportion above the regulator voltage. The thing is thought that the pre-regulator needs to be a constant voltage above the output regardless of the output voltage. The amount it is above the output is related to the maximal current demand and the bulk capacitor size as this will determine how much the voltage ramps down within a cycle.

In my version of this circuit I used one of the LT1716 comparators to compare the pre-regulator voltage with the output. I used a zener to set the pre-regulator voltage a few volts above the output.

It occurred to me that I needed this to be 5-6V above the output to ensure I could deliver 5A. If however the supply is not delivering this amount of current then the excess voltage just ends up as heat on the voltage regulator MOSFET. The bulk capacitor needs to he 1.06V above the output per 1A of current delivered. If instead we set the voltage to be some nominal amount above the output (say 1-2V) plus 1.5V per 1A (for safety) then I could massively reduce the dissipation.

The solution is to add a summing node to set the desired pre-regulator voltage and then use a comparator to fire the SCR.


The summing node adds 1.5 times the current to the required output voltage and will keep charging the bulk capacitor until the pre-regulator is another 1.4 (two diode drops) above that. Even going from 0 to 5A on the output this provides enough headroom to keep the output smooth.


The green trace above shows the current flowing (0-5A), the red is the output voltage (set to 14V) the blue is the pre-regulator voltage. You can see the pre-regulator voltage increase as the load increases and you can see the sawtooth waveform get taller as the current discharges the capacitor more per cycle.

One case where this didn't work as well was when the supply went into current limit mode.

In this case the voltage took one cycle to get back to the set point as the pre-regulator would discharge too low. I think this is acceptable however as current limiting is not a normal mode of operation but more a catch-all to prevent damage in case of operator error.

The power dissipation is relatively modest. With the output set to 14V and the load drawing 5A, the dissipation through each MOSFET is a series of short 12W spikes. This dissipation across the main pass transistor is around 22W (averaging about half that).


Conclusion

This pre-regulator looks like a winner. The next step is to build it up on my bread-board arrangement and test it out. 

Till next time!