Sunday, April 06, 2014

IC Design Interview 6: Op-amp Circuits

You must know your op-amp circuits to do analog circuit design! During an interview, you even have to derive the operation equations. Each of these derivations starts with the result in bold (because you must just know that) followed by the derivation.

Inverting Op-Amp

Vout = -(R2/R1)Vin

Vin/R1 = -Vout/R2
-(R2/R1)Vin = Vout

Non-Inverting Op-Amp (Buffer)

Vout = Vin(1+R1/R2) = Vin((R2+R1)/R2)

V- = Vout R2/(R2+R1)  [Voltage Divider]
Assume V- = Vin
Vin = Vout R2/(R2+R1)
(R2+R1)/RVin = Vout
The special case of R2 being open (infinite resistance) creates a Unity Gain Buffer

Difference Amplifier

Vout = R2/R1 (VB-VA)

Assume V- = V+
V+ = VB R2/(R1+R2)   [Voltage Divider]
Since I1=I2                 [Kirchoff's Current Law]
(Vout-V-)/R2 = (V--VA)/R1
Solve for V-
R1Vout+R2VA = V-
Which is the same as V+, so
R1Vout+R2VA = VB R2
      R2+R1             R1+R2
Which can be solved for Vout
                                                                                         Vout = R2/R1 (VB-VA)

Friday, March 21, 2014

Applied Power Electronics Conference and Exposition (APEC) 2014

One way to learn is to hang out with very smart people and try to keep up.

I recently attended the IEEE APEC in Fort Worth, TX. Since I live close to the convention center, I could attend without having to pay for a hotel or airline flight. Since I am currently between contracts, I had the week free to go. I haven't attended this conference before, but it seemed like a great opportunity. I don't attend many conferences. In fact, the last major conference I attended was ISSCC in 2002. These two conferences were very different. 

Some random comments.

  • They tell you the rooms are often cool so you should bring a sweater or jacket. Boy, are they right. Don't bring a pull-over (the mistake I made Monday) because there will be rooms where you don't want to where it. 
  • They feed you! Lunch was available for purchase on-site Sunday and Monday. Lunch was available for free during the industry exposition and during the poster session. This was cheaper, of course, but it was also incredibly convenient. 
  • There were lots of tracks, sometimes as many as twelve. It was sometimes hard to choose which session to attend. 
  • They kept the speakers on the time schedule. Period. That sometimes meant cutting questions short, occasionally meant cutting a speaker short, and once it meant waiting a few minutes before letting the next speaker begin. Keeping to the strict schedule allowed participants to skip between sessions to catch paper presentations in several tracks. 
  • The conference was very well organized. Presentations were pre-loaded before the sessions. Professional AV people were in every room to adjust the audio and solve problems as they occurred.
  • I was handed a USB stick containing all papers at registration. Fantastic.  
  • It was a very international conference. No real surprise there. 

Compared to the ISSCC 2002, I surprised myself by preferring this conference. 

  • The questions were requests for clarifications not attacks on the paper presented. 
  • Speakers were kept strictly to their times. 
  • APEC was more appropriate for the working engineer
    • There were many industry presented papers.
    • Companies were allowed to make product presentation. They were clearly labeled as such and were often interesting. 
    • There was a large (more than 1,000 booths) industry exposition. 
    • I actually heard the question asked after a paper was presented, "What do you see as the application of this circuit?" This particular paper had some odd input and output goals but the presenter did, in fact, have a real-world application in mind. 

Comments based on presentations

Packaging is a big deal for high speed, high power, and high temperature. SiC and GaN transistors intended for large power supplies are all three. Packaging was discussed a lot. 

It sounds like SiC is really coming into its own. My master's thesis way back in 1993 concentrated on characterizing a particular SiC type (6-H p-type substrate) so I glad that 20 years later that industry is getting some traction. 

Intersil discussed an interesting all digital control loop that eliminated the need for compensation. I haven't managed to get my hands the white paper where it is described in more detail. 

V2 control of DC-DC converter loops was mentioned several times. I need to figure out how that works. Maybe I can make it a future topic for this blog. It looks like it has faster transient response but adds more complexity. 

I am excited by the paper "Capacitor-Less Photovoltaic (PV) Cell-Level Power Balancing Using Diffusion Charge Redistribution". It describes a simple way to keep partial shading on a single cell from significantly lowering the yield from the entire string. I think I could make the controller for less than one dollar per cell. I liked the convergence between solar cells and switch capacitor converter. Some smart work. 

I finally really understand Power Factor Correction (PFC). I knew the circuits, of course, but the point of the exercise was lost on me. Dhaval Dalal made the simple statement, "PFC is meant to control input current not regulate output voltage." That was probably obvious to everyone but me. Now I get it too. 

The linear regulator isn't dead yet. There were no papers presented on them but I recall three times when it was mentioned that a linear regulator wouldn't be much less efficient then a presented buck regulator when the output voltage was close to the output voltage. The Power Supply on Chip guys seem to be holding linear regulators as a real competitor in size and power density. 

I will spare you all of my notes from the 55 sessions I attended. 

The APEC 2014 was very much worth attending. I don't know that I'll make it North Carolina next year. Cost and time may become too much of a problem. 

Bruce McLaren

Wednesday, February 05, 2014

Trailer Lights Version 3.1 Software

The electronic hardware for the improved trailer lights was described in the last post. I got the boards in and soldered it together. It works! Now it needs some software. I chose a Microchip PIC12F609 as the brains.

I was surprised how little example PIC code I found that included interrupt handling and I found no usable example code in assembly language. I also got tripped up on the oscillator shutting down during sleep. I know it makes sense to save power, but it makes waiting for a given time period impossible while in sleep mode. Further, since the interrupt returns to the command that was loaded when the interrupt occurs, I can't get away with something simple like
 goto $ ; wait for interrupt
 commands to do after interrupt
because the commands to do after the interrupt will never occur. I know that isn't the traditional way to use an interrupt, but in this case it isn't just non-traditional--it's impossible. So I put in a tight two command loop that checks for an interrupt to have happened. It feels like a hack, but it works.

The state diagram this program implements is shown in figure 1. Rather than an entirely interrupt driven approach, I could have interrupted only on the button changes and had the timing as part of the main code. I like this approach better.

Figure 1. State diagram for trailer lights controller.
I always have a bit of trouble explaining code, so here it is. Additional explanation is mixed in with the code in a different font. I am also fighting with Blogger to get it to post code without mangling it. I've got it down to just mangling comments. I'll edit this later if I can figure how to make it mor readable. In the mean time, I'm afraid you'll have to deal with it.

; Trailer Boost 3.1
; Bruce McLaren
; nanoDragon LLC
;  9 Dec 13 - 5 Feb 14
; Hardware notes:
;  PIC12F609 runnimg at 32kHz using external crystal in LP mode
; GP0 (GP0)   : Output           - Toggles at interrupt    TEST NOT USED IN APP
; GP1 (CIN0-) : Analog, POWFB    - 20% of Trailer Battery Voltage
; GP2 (GP2)   : Output, LIGHT    - A high turns LEDs on
; GP3 (GP3)   : Input,  BUTT     - Button, low when button pressed (external pull-up)
; GP4 (OSC2)  : OSC,             - crystal Oscillator (LP mode)
; GP5 (OSC1)  : OSC,             - crystal Oscillator (LP mode)

#include < >

; LP oscillator: Low-power crystal on GP4/OSC2/CLKOUT and GP5/OSC1/CLKIN
; WDT disabled and can be enabled by SWDTEN bit of the WDTCON register
; PWRT enabled
; MCLR pin function is digital input, MCLR internally tied to VDD
; Program memory code protection is disabled
; BOR disabled

; errorlevel -302  ; suppress "not in bank0" warning

; Constants
LowBatMax     equ .15 ; Number of Low Battery before shutdown: must be <255 comment-255--="">
OnTime        equ .30 ; Minutes LEDs on: must be <255 comment-255--="">
ShortTime     equ  .9 ; Minutes LEDs on if Low Battery Condition: must be <255 comment-255--="">
LongFlash     equ .29 ; Seconds LEDs flash for normal off: must be <59 comment-59--="">
ShrtFlash     equ .12 ; Seconds LEDs flash for low battery off: must be <59 comment-59--="">

; STATE bits
StateInit     equ O'0' 
StateWait     equ O'1'  ; never checked in program
StateLongOff  equ O'2'  ; never checked in program
StateShortOff equ O'3'  ; never checked in program
StatePwrDown  equ O'4'  ; never checked in program

; BUTTON bits
Pressed       equ O'0'  ; Set when button pressed,  cleared after processing never checked in program
Released      equ O'1'  ; Set when button released, cleared after processing

; Variables
CBLOCK 0x40          ; 64 bytes RAM in BANK0
    INTERRUPT        ; FF at end of interrupt routine
    STATUS_TEMP      ; STATUS save during interrupt
    W_TEMP           ; W      save during interrupt
    TENTHS           ; tenths of seconds counter
    SECONDS          ; seconds counter
    MINUTES          ; minutes counter
    LOWBATCNT        ; Low Battery Counts - inc when battery<10v dec="" when="">10V.
                     ;    Saturates at FF and 00. 
    BUTTON           ; Lower two bits contain button information
    STATE            ; Used to aid debugging 
                     ; 00000001 = Init     (STATE, StateInit)
                     ; 00000010 = Wait     (STATE, StateWait)
                     ; 00000100 = LongOff  (STATE, StateLongOff)
                     ; 00001000 = ShortOff (STATE, StateShortOff)
                     ; 00010000 = PwrDown  (STATE, StatePwrDown) Program doesn't set this

    goto Init                 ; start
    nop                       ;
    nop                       ;
    nop                       ;
    ; Save w, status (including BANKSEL) to STATUS_TEMP
    movwf   W_TEMP            ;
    swapf   STATUS, W         ;
    movwf   STATUS_TEMP       ; 

The W and STATUS register save is copied straight from the PIC12F609 data sheet.

    banksel    PIR1              ; Bank0
    btfss    PIR1, TMR1IF      ; was this a timer interrupt?
    goto      ButtCheck         ; if not, skip to button check
    bcf     PIR1, TMR1IF      ; clear timer interrupt
    ; Timer re-seeded with 65536-(32000/10+20)=62316 (F36C)
    bcf      T1CON, TMR1ON     ; TIMER1 disable
    movlw    H'F3'             ;
    movwf     TMR1H             ;
    movlw    H'6C'             ;
    movwf    TMR1L             ;
    bsf      T1CON, TMR1ON     ; TIMER1 enable 

I want an interrupt every 1/10 of second. It is a 32kHz crystal. The timer is disabled for five commands, which consume 20 clock cycles. Checking timing on the oscilloscope shows it to be about 2% too slow. It my really be a 32,768kHz crystal or my oscilloscope that hasn't been calibrated in five years may have drifted a bit. An initial timing error of 2% meets the application requirement so I'm not tuning it.

    ; If (MINUTES, SECONDS, TENTHS) == (255, 59, 9) Then don't inc (saturate)
    movlw    .9               ; Load 9 into W
    subwf    TENTHS, W        ; W = TENTHS - W
    btfss    STATUS, Z        ; If Z clear, don't trap
    goto     IncTime          ; TENTHS not 9, handle normal
    movlw    .59              ; Load 59 into W
    subwf    SECONDS, W       ; Compare W to SECONDS
    btfss    STATUS, Z        ; If Z clear, don't trap
    goto     IncTime          ; SECONDS not 59, handle normal
    movlw    .255             ; Load 255 into W
    subwf    MINUTES, W       ; Compare W to MINUTES
    btfss    STATUS, Z        ; If Z clear, don't trap
    goto     IncTime          ; MINUTES not 255, handle normal
    goto     LowBatCheck      ; Skip increment time

All that to make sure the time saturates even though it should never get to that point. Call it paranoid. If I was running out of program space, I would delete this code.

    incf     TENTHS, F        ;
    movlw    .10              ; Load 10 into W
    subwf    TENTHS, W        ; W = TENTHS - W
   btfss    STATUS, Z       ; If TENTHS!=10 (Z clear) move on, otherwise rollover TENTHS
    goto     LowBatCheck      ;
    clrf     TENTHS           ; Rollover TENTHS
    incf     SECONDS, F       ;
    movlw    .60              ; Load 60 into W (60 seconds in a minute)
    subwf    SECONDS, W       ; Compare W to SECONDS
    btfss    STATUS, Z        ;
    goto     LowBatCheck      ;
    clrf     SECONDS          ; Rollover SECONDS
    incf     MINUTES, F       ;
LowBatCheck:                  ; 
    ; The battery level is checked on the timer interrupt, i.e., every 0.1 seconds
    btfss    CMCON0, COUT      ; check comparator
    goto    BattHigh          ;
;;    bsf     GPIO, GP0         ;;; battery low

Uncommenting the bsf GPIO, GP0 line was useful in debugging the battery voltage check. There is a corresponding bcf line below that also gets uncommented and the xorwf GPIO, F that otherwise toggles the pin every interrupt needs to be commented out. The comparator is not handled well in the simulator. 

    incfsz  LOWBATCNT, F      ;
    goto    ClearTime1Int     ;
    decf    LOWBATCNT, F      ; If it incremented to 0, decrement will re-saturate
    goto    ClearTime1Int     ;
    movf     LOWBATCNT, F      ;
;;    bcf     GPIO, GP0         ;;; battery high
    btfss   STATUS, Z         ; If LOWBATCNT is already 0, don't dec
    decf       LOWBATCNT, F      ;
    bcf      PIR1, TMR1IF      ; clear timer1 interrupt
    btfss    INTCON, GPIF      ; if not a pin interrupt,
    goto      InterruptFinish   ; skip to InterruptFinish
    btfsc    GPIO, GP3         ;
    bsf     BUTTON, Pressed   ;
    btfss   GPIO, GP3         ;
    bsf     BUTTON, Released  ;
    bcf       INTCON, GPIF      ; clear pin interrupt
    movlw    b'00000001'       ;
    xorwf    GPIO, F           ; Toggle GP0 each interrupt for testing

Toggling the "unused" output made debugging much easier. It helped both with hardware debugging and simulation debugging. 

    clrf    INTERRUPT         ; ensure INTERRUPT clear
    comf    INTERRUPT, F      ; set INTERRUPT to FF
    ; Restore STATUS and return
    swapf    STATUS_TEMP, W   ; Swap STATUS_TEMP into W
    movwf    STATUS           ; Move W into Status
    swapf    W_TEMP, F        ; Swap W_TEMP
    swapf    W_TEMP, W        ; Swap W_TEMP into W
    retfie                    ; Return from interrupt
    nop                       ;

    banksel    STATE             ; Bank0
    clrf    STATE             ; clear STATE
    bsf     STATE, StateInit  ; STATE = Init
    ; GPIO setup
    clrf    GPIO              ; clear outputs
    banksel ANSEL             ; Bank1
    clrf    ANSEL             ;
    bsf     ANSEL, GP1        ; GP1 is analog
    clrf    TRISIO            ;
    bsf      TRISIO, GP1       ; GP1 is an input
    bsf       TRISIO, GP3       ; GP3 is an input
;    clrf    WPU               ;
;    bsf       WPU, GP3          ; GP3 has weak pull-up NO, IT CANT

As mentioned in the previous post, I messed this up.GP3 cannot have an internal weak pullup unless it used as the pin is configured as MCLR. It is a pretty clear footnote in the data sheet, I just plain missed it. I had to add an external pull-up to the pin.

    clrf    IOC               ;
    bsf     IOC, GP3          ; GP3 interrupts on change
    banksel    INTCON            ; Bank0
    bsf     INTCON, GPIE      ; GPIO Change Interrupt Enable
    ; Timer setup Timer seeded with 65536-(32000/10)=62336 (F380)
    movlw    H'F3'             ;
    movwf     TMR1H             ;
    movlw    H'80'             ;
    movwf    TMR1L             ;
    clrf    T1CON             ; No gate, No prescale, timer1 disable
    bsf     CMCON1, T1ACS     ; FOSC
    clrf    BUTTON            ; clear button
    ; comparator setup (not enabled until after wakeup)
    clrf    CMCON0            ; disabled
    bsf     CMCON0, CMR       ; CMVin+ connects to CMVref output
    bsf     CMCON1, CMHYS     ; hysteresis on
    clrf    VRCON             ; Voltage Reference disabled
    bsf     VRCON, FVREN      ; 0.6V Reference Enable
    ; Interrupt setup
    bsf     INTCON, GIE       ; GPIE already set
    sleep                     ; wait for pin interrupt

I can use sleep here because this first wait is waiting for the button to be released, there is no timing and no clock. This is the low power wait until someone pushes (and releases) the button state. 

    nop                       ;
    ; Next state logic
    btfss     BUTTON, Released  ;
    goto     InitSleep         ; If button not released, go back to sleep and wait
    bsf     CMCON0, C1ON      ; enable comparator
    bsf     VRCON, FVREN      ; enable voltage reference
    bsf      T1CON, TMR1ON     ; TIMER1 enable

    banksel STATE             ; Bank0
    clrf    STATE             ; clear STATE
    bsf     STATE, StateWait  ; STATE = Wait
    clrf    TENTHS            ; clear time
    clrf    SECONDS           ;
    clrf    MINUTES           ;
    bsf     GPIO, GP2         ; GP2 high (LEDs on)
    bcf      BUTTON, Released  ; "process" BUTTON, Released
    clrf      PIR1              ; clear peripheral interrupts including TIMER1 and Comparator
    banksel PIE1              ; Bank1
    bsf      PIE1, TMR1IE      ; Enable TIMER1 interrupt
    banksel    INTCON            ; Bank0
    bsf     INTCON, PEIE      ; Enable Periperal interrupts
    clrf    INTERRUPT         ; ensure INTERRUPT clear
    btfss    INTERRUPT, 0      ;
    goto    WaitLoop
    clrf    INTERRUPT         ; ensure INTERRUPT clear
    ; Next state logic
    ; If Released  goto LongOff
    banksel BUTTON            ; Bank0
    btfsc    BUTTON, Released  ;
    goto      LongOff           ;
    ; If Minutes > OnTime goto LongOff
    movlw    OnTime            ;
    subwf    MINUTES, W        ; W = MINUTES - OnTime
    btfsc    STATUS, C         ; If C==0, W>f
    goto    LongOff           ;
    ; If LowBatCnt > LowBatMax & Minutes > ShortTime goto ShortOff
    movlw    ShortTime         ;
    subwf    MINUTES, W        ;
    btfss   STATUS, C         ; If C==0, W>f

This check has to be against C instead of Z because the bettery can become too low after the ShortTime is complete but before OnTime is complete. Making this a Carry check ensures the shorter on-time and the quick flash that warns the user the battery is low. 

    goto     WaitLoop          ; else repeat
    movlw   LowBatMax         ;
    subwf    LOWBATCNT, W      ;
    btfsc    STATUS, C         ; If C==0, W>f
    goto    ShortOff          ;
    goto    WaitLoop          ; else repeat

    banksel STATE             ; Bank0
    clrf    STATE             ; clear STATE
    bsf     STATE, StateLongOff ; STATE = LongOff
    bcf      BUTTON, Released  ; "process" BUTTON, Released
    clrf    TENTHS            ; clear time
    clrf    SECONDS           ;
    clrf    MINUTES           ;
    clrf    INTERRUPT         ; ensure INTERRUPT clear
    btfss    INTERRUPT, 0      ;
    goto    LongOffLoop
    clrf    INTERRUPT         ; ensure INTERRUPT clear
    bcf      GPIO, GP2         ; GP2 low (LEDs off)
    btfss    SECONDS, 0        ;
    bsf     GPIO, GP2         ; GP2 high (LEDs on) on even seconds
    ; Next state logic
    ; If Released  goto Wait
    btfsc    BUTTON, Released  ;
    goto      Wait              ;
    ; If Seconds > LongFlash goto PowerDown
    movlw    LongFlash         ;
    subwf    SECONDS, W        ;
    btfsc    STATUS, C         ; If C==0, W>f
    goto    PwrDown           ;
    goto    LongOffLoop       ; else repeat

    banksel STATE             ; Bank0
    clrf    STATE             ; clear STATE
    bsf     STATE, StateShortOff ; STATE = ShortOff
    bcf      BUTTON, Released  ; "process" BUTTON, Released
    clrf    TENTHS            ; clear time
    clrf    SECONDS           ;
    clrf    MINUTES           ;
    clrf    INTERRUPT         ; ensure INTERRUPT clear
    btfss    INTERRUPT, 0      ; wait for interrupt
    goto    ShortOffLoop
    bcf      GPIO, GP2         ; GP2 low (LEDs off)
    btfss    TENTHS, 0         ;
    bsf     GPIO, GP2         ; GP2 high (LEDs on) on even tenths
    ; Next state logic
    ; If Released  goto Wait
    btfsc    BUTTON, Released  ;
    goto      Wait              ;
    ; If Seconds > ShrtFlash goto PowerDown
    movlw    ShrtFlash         ;
    subwf    SECONDS, W        ;
    btfsc    STATUS, C         ; If C==0, W>f
    goto    PwrDown           ;
    goto    ShortOffLoop      ; else repeat

    banksel INTCON            ; Bank0
    bcf       INTCON, GIE       ; disable interrupt
    clrf    STATE             ; clear STATE
    bsf     STATE, StatePwrDown ; STATE = PowerDown
    bcf     GPIO, GP2         ; not LIGHT
    bcf     T1CON, TMR1ON     ; disable Timer 1
    goto Init                 ; start over


So much for my posting every week to get this done quickly. On the other hand, I've been working so I can't complain. The next post will either be the 3d printed case or how to replace the headlight case and rim on a Honda Shadow. 


Thursday, January 02, 2014

Trailer Lights Version 3.1 Schematic

I am revisiting the trailer lights explained in several previous posts. I am implementing a few improvements. 
  • Twice as many LEDs. 
  • Real Lead-Acid battery charger built in. 
  • Lower "burden" current. 
The appropriate data sheets are linked to throughout this post. Figure 1 shows the version 3.1 schematic.

Figure 1. Trailer lights complete schematic.

Let's start with the input circuit as zoomed in on in figure 2. A 5A fuse protects the trailer battery from any short circuits. The boost switch-mode power supply at the input will convert the truck battery that may be between 10V and 16V to a steady 18V. If the truck battery is higher than expected, it will effectively pass through the boost circuit. A LM2587-ADJ is used in its default configuration for the boost. The Schottky diode (D1) in the boost regulator also forms a nice protection from too much voltage somehow getting produced on the circuit side feeding back into the truck battery. The parallel 3kΩ resistors (R18 and R19) were just to create a 1.5kΩ resistor and avoid getting yet another value of resistor.

Figure 2. Input boost regulator schematic.

A UC3906 forms the base of the charger section highlighted in figure 3. The two parallel resistors R20 and R21 set the maximum charging current. I couldn't find a reasonably priced ⅛Ω 2W surface mount current sense resistor, so I am using two ¼Ω 1W resistors instead. Note that 2A through a ⅛Ω resistor is ½W of continuous power dissipation; I think quadruple that is a reasonable safety margin since I want to avoid self-heating effects. The MJE15035G Bipolar (Q1) may drop up to 8V in the 2A charge state. Since that's 16W, a pretty hefty bipolar was chosen. The resistors are sized per the UC3906 data sheet with modifications from the application note. The Schottky diode D5 and connecting the bottom of the resistor string to the PWRIND (pin 7) pin instead of ground are hints from the application note to save power when the truck battery is not present.

The sense and power leads to the trailer battery are separate in the plug. The connection to the battery positive lead can be a single or double wire depending on how much trouble I feel like taking when constructing wiring harnesses. Given the effort needed to connect three wires to a four wire socket, I'll probably not run a separate sense lead all the way to the trailer battery, but the option is there. The fuse is in the power lead, of course, but this means the sense input to the charger controller is on the sense side of the fuse. If somehow the fuse blows but the trailer battery voltage is low enough for the charger controller to try to charge the battery but not so low that it senses an error (between about 10V and 13.8V), then the pass transistor Q1 could be turned on pretty solidly. If the truck battery is attached, this would drive the BATTRL power rail to about 17V (18V from the boost regulator minus a bipolar drop and a Schottky drop). This condition is not ideal, but all of the components connected directly to that rail are rated for continuous operation at that voltage.

Figure 3. Charger schematic.

The digital control section is zoomed in on in figure 4. I am using a TPS70950 linear voltage regulator because it has a 2μA bias current and is stable even when supplying less than 100μA. The good old LM7805 has a 6mA bias current and is not happy supplying less than 10mA current. The Microchip PIC12F609 run with a 32kHz crystal may consume only 60μA (2μA when asleep); since this is in the neighborhood of the battery's self-discharge current, it won't effect the working time between charges much. R1 and R2 are really just pads and holes to allow for any tuning needed to get the crystal oscillating. The resistor divider formed by R7 and R4 will force POWFB to 0.6V when BATTRL is 10V. A ±1% variation in R7 and R4 will mean 10.27V to 9.87V will cause the sense voltage of 0.6V. There is an additional ±50mV in the PIC reference voltage and ±10mV in the PIC comparator. This inaccuracy (call it ±10%) is acceptable since I'm just concerned with warning the user when the trailer battery is getting low. The bipolars Q3 and Q4 are a standard low current power switch. I'll discuss the program in the microcontoller in the next post.
The sharp eyed among you will notice the PIC12F609 cannot be configured with GP3 (pin 4) as a general purpose digital input and have the internal weak pull-up enabled. This is only true for GP3 (pin 4). So 1MΩ or so pull-up resistor will be "blue-wired" between BUTT and DIG (5V power). This was an oversight on my part that I didn't catch until after the PCBs were layed out and ordered. 

Figure 4. Digital section schematic.

Finally, figure 5 zooms in on the LED power supply. Another LM2587-ADJ boost controller is configured as a current regulator. The lower current (and slightly cheaper LM2585-ADJ could be used, I just wanted to keep my parts list a little simpler and use the same boost controller that was used on the input. When R15 is 40Ω, about 30mA will be directed through an eight LED string. This current is also mirrored to the other eight LED string because of the mirror formed by Q4 and Q5. This current mirror is a cheap mirror, not a nice single package matched pair. In this application a few percent variation in current just isn't that big of a deal. The zener diodes D2 and D3 have a 36V breakdown. They keep the boost circuit from running away if the LEDs are not plugged in when the circuit is on or if either LED string has an open circuit because of a broken wire or smashed LED or any other reason. The resistors R12 and R13 with a value of "unpop" are not meant to be populated on the board but they do allow lowering the resistor value (and thus increasing the LED current) after the board has been populated. 
Figure 5. LED driver schematic.

The PCB for building this circuit is shown in figure 6. The bottom layer ground plane isn't shown for clarity. I am sticking with 1206 packages for resistors and small capacitors because they are easy for me to solder by hand. I ended up using through hole inductors because they are physically large devices and the through hole versions can be oriented vertically, taking up significantly less board space. The Q1 bipolar is a TO-220 package for power dissipation reasons so it is also through hole. The huge 1500μF capacitor C12 is meant to be leaned over the board, covering the microcontroller as shown in the 3d model in figure 7. The boards are on order and not expected until the end of the week, so I won't have a picture of an assembled board for a couple of posts.

Figure 6. PCB layout.
Figure 7. 3d model of PCB.

There's $88.72 worth of components in this project. The largest cost is
  • $22.89 GP1272F2 Sealed Lead Acid Battery 12V 7.2Ah .250" Faston tabs 
  • $17.78 (2@$8.89) LM2587S-ADJ/NOPB Switching Regulators 5A FLYBACK REG
  • $7.43 UC3906DW Battery Management Lead-Acid Linear Charge Mngt IC
  • $5.02 (16@$0.314) CP41B-WGS-CK0P0154 LEDs Through Hole 90DG C-WT STNDOF P4 LED 9000K 3.6V
  • $4.02 (2@$2.01) 0154005.DR  Surface Mount Fuses Fuseblock w/ fuse 5A OMNI BLOK 154
  • $3.35 RP-SPNS  Pushbutton Switches PUSHBUTTON SWITCH SPST 1A 120VAC 28VDC
  • $3.01 2210-V-RC  Fixed Inductors 56uH 15% Vertical
  • $2.64 (3@$0.88)  STPS5L60S  Schottky Diodes & Rectifiers PWR Schottky rectifier
  • $2.50 2200HT-102-V-RC  Fixed Inductors 1.0mH 15% Vertical
Six prototype boards from Silver Circuits run $105 including shipping ($17.50 each).

Now that I am writing this review I see one thing I should have done differently. I should have provided a 1MΩ in parallel with output capacitor C8 to bleed it off when power is removed.

I also wish I had found some way to move the big bipolar Q1 away from the electrolitic capacitor C12. That bipolar is going to run hot and I would prefer to keep hot components away from electrolitic capacitors.

My next post will cover the PIC program.
The post after that will discuss the case design and printing.
I may do a final post to wrap everything up and show the installation.
I will try to do a post every week so this project is complete by the end of January.

Bruce McLaren