Simple logarithm implementation in PIC assembler

Most natural observations are exponentational/logarithmic in nature.

I often do simple hardware using Microchip PIC processors (usually 12F or 16F families). Hardware doing some business in the home.

One such example is my Christmas-tree-lightning-controller. Basically it only turns my electric Christmas-tree-lights on when I want to see them on…

GPC

GPC

In order to do this, it needs to measure the out-door light. It uses an accumulation cell (of 8 samples) and a moving average register with 8 cells: Light or darkness is determined from 8 accumulated samples of “10-bits light” averaged through the latest 8×8 samples…

8×8 samples of 10-bits equals 6 bits of 10bits equals 16 bits…

So the output of the moving average register is at most 16 bits wide and should pose no problems on a modern microcontroller.

Unfortunately, the small PIC micros are not very good at “multi-byte” calculations why the 16-bit result is a bit awkward to deal with. And my simple experiments indicates that light-level comparisons should be measured on a “percentage change” basis and not as an absolute comparison.

If I could just do a simple 8-bit logarithm function of the 16-bit absolute result, I would be able to do simple percentage comparisons of different light level measurements by simple subtraction of 8-bit values. Even the simples PIC’s can do subtraction of 8-bit values without special engineered software subroutines 🙂

Being inspired by the µLaw compression schemes used in Telephony, I wrote this little routine, that basically calculates 16×log2(x), where x is some 16-bit value and the result is an 8-bit value. Simulating the calculations in software gives a maximum error of 1-bit on the result.

; NOTE: Variables wi, r0 and r1 are 
; defined elsewhere in on-chip RAM
;
; log2: calcuate r0 = approx 16*log2(r1:r0). 
; wi, r1 destroyed
;
log2:
        movlw   16
        movwf   wi
; loop
log2_loop:
        bcf     STATUS,C
        rlf     r0,f
        rlf     r1,f    ; C affected
        decfsz  wi,f    ; Z affected
        btfsc   STATUS,C
        goto    log2_done
        goto    log2_loop
; done
log2_done:
        movlw   0xf0
        andwf   r1,w
        iorwf   wi,w
        movwf   r0
        swapf   r0,f
        return

The simpe logarithm shown above I’ve used lots of different places. If You want to know how or why it works, don’t hesistate to put a comment below.

Unfortunately, my Christmas-tree-lights-controller is not (yet) perfect, as sudden, heavy light seems to overflow the moving averager. In other words, when the terrorist children living next-door are having fun with fireworks, the lights on my outdoor Christmas tree blinks in its own secret manner 🙂

About Jesper Udby

I'm a freelance computer Geek living in Denmark with my wife and 3 kids. I've done professional software development since 1994 and JAVA development since 1998.
This entry was posted in Microcontoller, Open Source, Personal, PIC and tagged , , . Bookmark the permalink.

2 Responses to Simple logarithm implementation in PIC assembler

  1. Michael says:

    Hi, you actually can save one goto opcode:

    ; NOTE: Variables wi, r0 and r1 are
    ; defined elsewhere in on-chip RAM
    ;
    ; log2: calcuate r0 = approx 16*log2(r1:r0).
    ; wi, r1 destroyed
    ;
    log2:
    movlw 16
    movwf wi
    ; loop
    log2_loop:
    bcf STATUS,C
    rlf r0,f
    rlf r1,f ; C affected
    decfsz wi,f ; Z affected
    btfss STATUS,C
    goto log2_loop
    ; done
    log2_done:
    movlw 0xf0
    andwf r1,w
    iorwf wi,w
    movwf r0
    swapf r0,f
    return

    • Jesper Udby says:

      Nope, wait a sec.

      The decfsz wi,f skips the bit test and exits the loop via goto log2_done. If you inverse the bit test and removes the goto that exits the loop, the decfsz continues the loop instead of exiting.

Leave a Reply

Your email address will not be published. Required fields are marked *