Wednesday, December 12, 2012

PIC 16F628 PWM setup

As the primary detector sensors I wanted to use IR detectors as I had in previous robots.  Key to this is the generation of a 38khz square wave (50% duty cycle) which the IR detectors are tuned to.  In other robots I had used the circuit described in David Cook's Intermediate Robot Building book.  There are others based on 555 timer chips to.  However the pic16f628 has a PWM module and can output a PWM signal on one pin (RB3).  This meant one less extra IC chip and associated parts (resistors/capacitors).  However the setting up of the PWM was a little more esoteric.

I recommend reading the Microchip "PICmicro Mid-Range MCU Family Reference Manual".  The section on PWM makes the setup of PWM a lot clearer as there are some worked examples of the formulas used.  Without these I would have been pretty lost in time conversion hell.

Setting up PWM requires two main steps.  First is setting the frequency of the PWM.  The second is setting the duty cycle of the PWM.  Both the pic16f628 reference manual the the Mid-Range reference manual describe the formulas to do this.  Where things get interesting is that the PWM duty cycle is 10 bits and thus spread across two registers (CCPR1L and CCP1CON<5:4>).  Below is a worked example showing this.

First I set the PWM frequency to 38khz (ish).  For the TMR2 prescale I looked at the examples in the reference manual as a guide of what to set.  Like most of technology it's a case of seeing what someone else did and changing it to fit your specific case.  Via the equation with a 4mhz clock and a TMR2 prescale of 1

PWM period = (PR2 +1) * 4 * TOSC * TMR2 prescale
1/38kHz = (PR2 +1) * 4 * 1/4MHz * 1
26us = (PR2+1) * 4 * 0.25
26us = (PR2+1) * 1
25 = PR2

and the code with comments

; set pwm period
; 0x19 == 25 decimal.  So via equation
; 25+1 * 4 * 0.25 * 1 = 26
; 1/26 == 38khz ish
    banksel PR2
    movlw   0x19
    movwf   PR2

Then I set the duty cycle to 50%.  This means that the frequency will be twice that of the pwm.  Ie for each PWM period the duty cycle has to change twice (on, then off).  Thus the value to be put into the registers will be 0x34 (decimal 52 - 26*2).  This is split across the two registers.  The easiest way I found to do this was write out 0x34 as binary

0011 0100

Now this needs to be 10 bits, so the left most bits will be '00'

0000 1101 00

So CCPR1L will be '0000 1101' (0x0d) and CCP1CON<5:4> will be '00' (CCP1CON = 0x0c).  Code and comments below

; set pwm duty cycle to 50%
; so need duty cycle to be twice pwm period - ie 52 = 0x34
; since Tosc is in both pwm and duty cycle equation they cancel out
; remember split across bits 5/4 of ccp1con and ccpr1l
; ie 0000 1101 00
;  0x   0    d  0
    banksel CCP1CON
    movlw   0x0c
    movwf   CCP1CON
    movlw   0x0d
    movwf   CCPR1L  ; duty cycle 0x34 - ie 52 decimal
; set tmr2 prescaler 
    banksel T2CON
    movlw   0x00
    movwf   T2CON
; turn on timer 2
    bsf T2CON, TMR2ON

On the first attempt I got the duty cycle numbers wrong and saw no frequency output.  Stumped I ending up measuring the voltage on pin RB3.  It was 5V.  So the voltage was at VDD which is 5V which means I had a duty cycle of over 100%.  Reworking the numbers I spotted my error and fixed things up.  With a duty cycle of 50% the voltage was half VDD as expected.

On a side note I used a Casio FX-100d calculator to do the number crunching.  It's over 20 years old (I had it in high school) and is still running on the original battery.  Not sure what battery technology it has but I'm assuming it's an arc reactor subtype.

Tuesday, November 20, 2012

Pennybot line detection

The first piece of functionality I wanted to get working was the white line edge detection.  Previously I had used photoresistors and a LM393 comparator chip.  This time I wanted to try using LED Infra-red (IR) emitters and IR phototransitors detectors.  This was to reduce the impact of environmental light on the edge detection sensors.  Rather than a separate comparator chip I would use the comparator module in the pic16f628.  I had some nice 3mm LED IR emitter and 3mm phototransistor in a dual plastic housing that I had gotten from an old robot kit I had purchased purely for parts.  Not knowing the specs of either part I used a 1K resistor on the IR emitter.  For the phototransistor I wasn't sure the part was actually a phototransister.  As suggested in some example circuits I was using a 50K resistor in series.  There was very little response (ie voltage change) to changes in light level, less than 0.2 volts.  Trying a few different parts the result was the same.  Finally I guessed this was a IR only phototransistor.  Putting my finger to cover the IR LED and phototransistor (ie bouncing the IR led output back to the transistor) the transistor turned on - success!  The voltage range of the test point on the photo transistor from off to on was approx 4.8V (off) to 0.4V (on).  

Over on the microcontroller side of things I was using the comparator module as two common reference comparators (setting CM<2:0> = 011).  For the reference voltage I used a 10K pot to divide the 5V input and thus be able to tune the trigger point of the comparator.  I setup an ISR to trigger every time the comparator tripped.  The ISR incremented a counter and the main loop displayed this count in binary on 4 leds (the counter rolled over at 10).  Initially I was getting some twitchy responses with double counts, etc.  I added a 50ms delay in the ISR on the reading of the sensor and this was eliminated.  In addition to the counter being displayed I also toggled an led on port RA3 depending of the comparator output.  Code and comments below. 


    include "P16F628A.INC"        ;include the defaults for the chip
    list p=16f628a
    __config (_CP_OFF & _CPD_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF)

; ra0 / ra1 = inputs V-
; ra2 common V+
; ra3 output to led

; variables
    cblock 0x20
            OUTCOUNT ; interrupt code counter
            count ;used in delay routine
            count1 ;used in delay routine
            counta ;used in delay routine
            countb ;used in delay routine
    endc

    #define W_TEMP  0x70 ; common memory area across all banks
    #define STATUS_TEMP 0x71 ; temp vars for ISR

    org 0
    goto init   ; skip ISR code
;
; ISR code
;
    org 4
    movwf   W_TEMP        ; Save W & STATUS, etc
    swapf   STATUS, W
    bcf     STATUS, RP0
    movwf   STATUS_TEMP         ; end ISR save bits

    incf OUTCOUNT,1 ; COUNT +1, then check and reset count if needed
    movlw 0x0A ; put 10 in W
    subwf OUTCOUNT,0 ; subtract 10 from count to see if count > 10
    btfsc STATUS,0 ; check carry flag, skip if clear
    clrf OUTCOUNT ; reset count to 0

    call Delay50 ; wait 50ms for switch to get stable
    bcf STATUS,RP0 ; select bank 0
    btfsc CMCON,C2OUT ; if c2out is 1
    bsf PORTA,3 ; turn on ra3 led
    btfss CMCON,C2OUT ; if c2out is 0
    bcf PORTA,3 ; turn off ra3 led
    bcf PIR1, CMIF ; clear pending interrupts

    swapf   STATUS_TEMP, W   ; restore W & STATUS
    movwf   STATUS
    swapf   W_TEMP,F
    swapf   W_TEMP,W
    retfie                  ; end ISR end bits

init
    movlw 0x03 ; init comparator mode
    movwf CMCON ; CM<2:0> = 011
    bsf STATUS,RP0 ; select bank 1
    movlw 0x07 ; init data direction
    movwf TRISA ; ra2/0 as inputs, ra 4/3 as output
    movlw 0x00
    movwf TRISB ; all port b as output - for counter
    bcf STATUS,RP0 ; select bank 0
    movf CMCON,F ; read cmcon to end change condition wrt interrupt setup
    bcf PIR1, CMIF ; clear pending interrupts
    bsf STATUS, RP0 ; select bank 1
    bsf PIE1, CMIE ; enable comparator interrupts
    bcf STATUS,RP0 ; select bank 0 - determine initial state of comp output
    clrf PORTB ; clear portb
    btfsc CMCON,C2OUT ; if c2out is 1
    bsf PORTA,3 ; turn on ra3 led
    btfss CMCON,C2OUT ; if c2out is 0
    bcf PORTA,3 ; turn off ra3 led - finished initial state
    clrf OUTCOUNT ; init COUNT at 0
    bsf INTCON, PEIE ; enable peripheral interrupts
    bsf INTCON, GIE ; enable global interrupts 
main

    movf OUTCOUNT,0 ; COUNT to W
    movwf PORTB ; display count in hex on leds
    goto main

;Delay routines

Long_Delay
        movlw    d'50'        ;delay 5 seconds
        call    Delay100W
        return

Delay100W    movwf    count        ;delay W x 100mS
d2        call    Delay100    ;maximum delay 25.5 seconds
        decfsz    count    ,f
        goto    d2
        return

Delay255    movlw    0xff        ;delay 255 mS
        goto    d0
Delay100    movlw    d'100'        ;delay 100mS
        goto    d0
Delay50        movlw    d'50'        ;delay 50mS
        goto    d0
Delay20        movlw    d'20'        ;delay 20mS
        goto    d0
Delay10        movlw    d'10'        ;delay 10mS
        goto    d0
Delay1        movlw    d'1'        ;delay 1mS
        goto    d0
Delay5        movlw    0x05        ;delay 5.000 ms (4 MHz clock)
d0        movwf    count1
d1        movlw    0xC7
        movwf    counta
        movlw    0x01
        movwf    countb
Delay_0        decfsz    counta, f
        goto    $+2
        decfsz    countb, f
        goto    Delay_0

        decfsz    count1    ,f
        goto    d1
        return

;end of Delay routines

    end







Wednesday, November 14, 2012

Pennybot restart

Knowing as always time is short for robot building I wanted to break down the tasks to build pennybot into smaller achievable tasks that would take 1-2 weekends (I only get a few hours spare per weekend) to complete but would aid in the final design.  Putting the chassis aside for now as it was mainly complete I concentrated on the microcontroller.  I hadn't touched a microcontroller for 4 years so it was pretty much relearning from scratch.

The first thing to learn was MPLAB X.  I could have stuck with MPLAB 8 but it was time to move on.  I also had invested in a PicKit 3 as a serial port wasn't an option on any of the laptops I wanted to use for development.  I used a simple "blink the leds" assembly program as the trial experiment.  

I soldered up a little PicKit 3 breadboard header and cable, plugged everything in a hoped.  I fell down the usual holes along the way (power from board or from pickit for example) and got burnt by having to be strict on the formatting in the MPLAB editor.  Previously the text files could be pretty sloppy and still work with mpasm.  However the formatting rules made me do things the proper way, which saved me time when I came back after a week or so to review some code.  

I also jumped pic models to a pic16f628.  That's right, I upgraded to a ~10 year old pic.  One day I'll join the real world.  Not having to have an external timing crystal (and getting two pins back) and the comparator module onboard were a big plus.  Also it was a very simple cutover from the pic16f84.  Finally I could buy (and did) 5 pic16f628 chips for $10 off ebay.  This means I have enough for this project and a few others so any investment in time in learning to program this model would pay off.  This did mean that C was pretty much out of the picture.  However I liked learning how to do things in assembly.  I enjoy having that real low level knowledge of what is going on even if the setup on some features (eg pwm) can get a bit messy.

I started development on a Windows 7 desktop.  After awhile I moved onto a linux laptop.  The only issue I had was the include statement.  In Linux (which is case sensitive) the include file is in capitals.  Everything else was fine.  So with MPLABX and the PicKit 3 sorted out it was time to do some real programs.

Sunday, April 22, 2012

Voltage box

Voltage box sans labels


As described in my last blog post I decided I needed a small hand held variable voltage supply box.  The output voltage would be in multiples of 1.5V to match the various multiple AA/AAA battery combinations.  Also I would also want 3.3 and 5 volts outputs.  The entire thing would be powered by a 9V battery if possible with maybe the option of a DC input.

The basis of the design is a LM317 voltage regulator.  Since the output voltage is determined by a resistor ratio it would be simple to use a rotary switch to swap what resistor was used.  Thus the output voltage could be changed and to a fixed value.  I didn't want to use a variable resistor as I would need some kind of output screen to show what the output voltage was currently.  Originally I was going to use a single pole switch (limited to 6 positions).  However that changed later as the design evolved.

Using the LM317 was quite simple.  Following the datasheet I added the various recommended filter capacitors and protection diodes and tested the circuit on a breadboard.  Using the output voltage equation from the datasheet I determined what resistors would be needed for the output voltages of 1.5, 3, 3.3, 4.5, 5 and 6 volts.  Not all the values were "standard" values but most were available.  My aim was to be within 5% of the desired voltage.

Now that I knew the resistors needed it was time to go shopping to Jaycar.  For a case I used the remote control case (Jaycar part HB5610) as it had a battery access port built into the case.  A 9V battery fits in but is a tight fit and needs a bit of wiggling to get the battery cover on.  Although I don't normally use binding posts I wanted some on this project to future proof it.  The standard way of connecting this project will be via a 2 pin molex connector exactly the same as my previous variable resistor box was setup.  This also allows me to reuse the same cables.  I might even go back to my variable resistor box and put on binding posts there too.

While doing the breadboard design it occurred to me that having an led light up as each voltage was selected would add a nice bit of bling to the project.  Much better than just a sticky label, I would have six leds and as each voltage was selected the appropriate led would light.  To enable this I changed the rotary switch to be a 2 pole 6 way type.  The original 1 pole 12 way switch went into the parts box.  I would use a 5mm red led for the power light and 3mm green leds for the voltage selection display.  I like big obvious power lights.

Needing a way to secure the leds to the case I considered hot glue but I don't like this.  Wandering in Jaycar again I came across some 3mm and 5mm led bezels.  Very nice and they give a nice clean finish.  However when I got home I obviously had this idea previously as I already had some in the parts box.  The disadvantage of doing projects very occasionally is you forget what you have in stock at home.   

After machining the case for the components I had to fit in all the components on a prototype board.  Due to the rotary switch and binding posts I lost approx. 50% of the space in the case.  All the components fitted but were rather tight.  Also having the circuit board on the bottom of the case and the rotary switch and power switch on the top of the case made the construction harder than it needed to be.  I needed to keep the wires short so they would fit once the case was closed but long enough so I had access to solder the connecting wires.  The six green leds connecting to the rotary switch needed the most fiddling to get them to fit and not take up too much room as the leds were 10mm away from the rotary switch.

Everyone says not to do work when you are tired.  I wouldn't but I'm never not tired or sick or both.  The joys of young kids.  So as expected a few mistakes were made.  Some were simple like forgetting to connect the output terminal to a binding post.  The worst was when I connected the green led power line directly to the 9V rail, not the 2.2K current limiting resistor.  On power up the green leds were either not working, really dull or bright orange.  I switched between the 6 leds a few times before powering off.  Then I discovered what I had done.  Three out of the six leds were burnt out.  Much painful unsoldering and wiggling components out of the way resulted.  It was during this work another issue was introduced that I discovered later.  I also looped the battery cables around a screw inside the case to provide strain support in case the 9V connecter was jerked out to far.

Closing the case up however one of the green leds turned off.  Open the case, it turned back on.  There was only .5mm of difference when putting the case together between the led working or not.  So some joint was flexing and disconnecting.  This led was also one of the ones that had been swapped out earlier.  A few prods with the soldering iron fixed the dry solder joint on the led.  The tight access from the short wires made access a bit of challenge.

Finally everything was together and working.  The kids love the leds and my son keeps trying to turn off the red led by pushing it like the switches on some other household items.  A bit scary to see in a one year old the learnt response that a red led is a power switch.  I just need to make up some labels.

Enough time wasted on little projects.  Time to get back to my second mini sumo bot.


Monday, April 2, 2012

Toy debug sessions

My young children have a toy tv remote that makes various fun sounds when the numerous buttons are pressed. It also has two leds at the front that light up and/or flash in sequence. A nice simple toy that keeps them away from the real remotes. This is a good idea because baby slobber gets into anything and isn't good for electronic components. A case in point proved with the hard life this toy has had.

The toy remote had survived the various sucking attacks of my daughter and now it was my son's turn. However over the last few weeks the sound coming out of the speaker was getting quieter and sometimes there was no sound at all (the lights however continued to flash). New batteries were installed (3 x AAA) but a few days later all sound had stopped. The fixitup daddy was escalated to. To the shed...

Five self tapping screws held the case together. All the buttons were on a single rubber piece that came off to reveal the pcb. However to get to the component I had to unsolder the battery terminals from the pcb so the board could come free. Straight away I noticed the large amount of corrosion at the front (where the leds were located and a prime sucking point) of the pcb. The legs of one of the leds were brown and the board was discoloured. So my first thought was that baby slime had made it to the speaker and broken/dissolved it.

I cleaned all the board is isopropyl alcohol to remove the goo. Then I unsoldered the speaker to test it. However when a voltage was applied across it's contacts crackling could be heard. So the speaker was ok. Put that part back in. I replaced the corroded led (even though it still worked, that much corrosion is just bad). At this point I was focused on some passive component having failed. Doing various tests on the surface mount resistors all checked out ok. A diode test on the transistors seemed fine. I then considered the large (compared to the surface mount ones) electrolytic capacitor. It was a 100uf 6.3v. Old capacitor, baby slime - maybe faulty? Testing the resistance across it - 500ohms. That shouldn't be so time to replace that part. Given the small space in the toy I used a recycled 6.3v capacitor from an old computer mouse. Applying power and everything worked! Another of life problems solved by replacing a capacitor.

The next day however, failure. The sound from the remote was dead again. Back to the shed.

I replaced the second hand capacitor with a new one thinking this would be a quick fix. I didn't have any 6.3V caps so I substituted a 16V one. This took a bit of lead bending to make it fit in the space available. However that didn't solve the issue. So either something else had broken overnight (unlikely) or the capacitor wasn't the real cause of the issue. Back to more circuit tracing.

The pcb was dual sided. The heart of the toy was a microcontroller hidden under the standard black glob. So working in reverse for each part of the circuit I traced backwards to the controller. There were three main parts each driven off a separate pin of the microcontroller:

* the speaker driver consisting of what looked like a transistor and a few resistors and capacitors
* two identical led drivers circuits consisting of again what looked like a transistor and a few few resistors and capacitors.

Luckily all the transistors were the same model. The two on the led circuits were working so I could use their behaviour to compare to the behaviour of the transistor on the speaker circuit. Again I checked all the end points between components (use the continuity tester on my multimeter) and tested the values of all the components. All looked fine. Next I powered the circuit and checked the voltages at various points. Again all looked fine.

Concentrating on the transistors I tested the behaviour of the led transistors. Testing the base pin on the transistor I found out it went from 0v to 0.7v when the led was turned on. The collector pin went from 4v (ish) to 0v. Ie the transistor was turned on. Now to test the speaker transistor. When sound was meant to occur 0.7v was seen on the base pin. However the collector pin stayed at 4v. A dead transistor perhaps. I bypassed the transistor by bridging the base pin to the collector. Sound was heard, but it was very soft. So the transistor should be acting as an amplifier as expected, but it was not working currently. I unsoldered/destroyed the broken transistor so I could replace it. I don't have any surface mount components so I used a generic NPN transistor in a TO92 package and held the transistor onto the appropriate pins. Sound was back and it was loud. Not as loud as originally but that was ok as the sound level before was too high.

The original transistor was a SOT-23 package so a TO92 wasn't going to fit. Also the transistor was directly under the speaker so there was no room for a through hole component. However like a lot of consumer toy there were various components on the silk screen that weren't present. Perhaps they are used in other designs or revisions? One available spot was next to the leds which was for an electrolytic capacitor. Plenty of room for a TO92 part. The leads were a bit long but all fitted. The only mar on the whole job was when I slipped and slightly burnt the speak wire.

Putting everything back together the sounds are working and there is one happy little boy who isn't trying to grab the tivo remote as much as before.

Looking back I spent a lot of time (3-4 hours) fussing around on a $15 toy. On the hourly rate test it was a failure (I like to work out based on my hourly rate how much something would take to do before deciding to do it myself or get someone else to do it or buy a replacement) but from a learning aspect it was great success which is why I persevered. Or the obsessive compulsive aspect of me kicked in and refused to be beaten.

Things learnt:

* not having a computer in the shed to look up datasheets slowed things down. I had to use trial and error to work out which pins on the TO92 transistor were what for example. I need to test if the wireless network makes it down there. Or waste time walking back to the house.
* surface mount bits are hard to unsolder. With the normal tip on my soldering iron I couldn't get solder sucker in fast enough after I moved my soldering iron out of the way.
* my guilt on having lots of components that I didn't buy for any real reason is reduced by projects like this.

The final thought now is to build a hand held portable battery powered voltage supply. I'm thinking of LM317 run off a 9V battery and a rotary switch to determine what voltage. Voltages would be in multiples of 1.5V to fix what is seen in toys with maybe 3.3V and 5V added in for good luck.