Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

ASM: 24bit compare help please

augustinetez

Active Member
Further from my previous 202 error thread, I've started working on the code to do the compares and running in to problem doing 24bit compares.

Either my Google Foo is off or I'm not holding my tongue right, but I can find nothing for doing 24bit compares, everybody seems besotted with 16 or 32bit compares, even Piclist.

The code I'm using for testing is below and the problem I'm encountering is for example comparing any value between and including 18100 & 18943 to 18100 returns the correct flag value of FF but values of 18944 and above return the wrong flag value of 0.

It is supposed to return FF for any value equal to or greater than the low band edges eg Band1L etc when compared to the incoming number (frequency).

The other routine is to do the opposite and test for values lower than or equal to the BandxH limits - haven't fully tested that side but expect it
also to be faulty.

Any ideas, please.

We are supposed to be without power for quite a long period tomorrow (typical on a stinking hot day), so I may be "off air" for 24hrs or so.

Code:
    list n=0

    errorlevel -302, -305  ; Skip nuisance messages

    LIST         P=PIC16F628A,r=dec,x=off

    INCLUDE    P16F628A.inc

    __config _CP_OFF&_LVP_OFF&_BODEN_OFF&_MCLRE_OFF&_PWRTE_ON&_WDT_OFF&_INTOSC_OSC_NOCLKOUT

;--------------------------------------------------------------------------------

Band1H equ 20000    ; 0x00 0x4E 0x20
Band1L equ 18100    ; 0x00 0x46 0xB4

Band2H equ 38000    ; 0x00 0x94 0x70
Band2L equ 35000    ; 0x00 0x88 0xB8

Band3H equ 72000    ; 0x01 0x19 0x40
Band3L equ 70000    ; 0x01 0x11 0x70

Band4H equ 101500    ; 0x01 0x8C 0x7C
Band4L equ 101000    ; 0x01 0x8A 0x88

Band5H equ 143500    ; 0x02 0x30 0x8C
Band5L equ 140000    ; 0x02 0x22 0xE0

Band6H equ 181680    ; 0x02 0xC5 0xB0
Band6L equ 180680    ; 0x02 0xC1 0xC8

Band7H equ 214500    ; 0x03 0x45 0xE4
Band7L equ 210000    ; 0x03 0x34 0x50

Band8H equ 249900    ; 0x03 0xD0 0x2C
Band8L equ 248900    ; 0x03 0xCC 0x44

Band9H equ 297000    ; 0x04 0x88 0x28
Band9L equ 280000    ; 0x04 0x45 0xC0

Band10H equ 520000    ; 0x07 0xEF 0x40
Band10L equ 500000    ; 0x07 0xA1 0x20


load24    macro    arg1,arg2    ; arg1 = band being compared eg band1h, band1l etc max 24bit number (3 bytes)
    movlw    arg1 >> 16    ; arg2 = registers holding above eg comp:3 in cblock
    movwf    arg2+2        ; Max 24bit number
    movlw    (arg1&0xff00) >> 8
    movwf    arg2+1
    movlw    (arg1&0xff)
    movwf    arg2
    endm
    
; usage   
;    load24    bandxx,comp    ; load bandxx value being compared and registers to put values in
;--------------------------------------------------------------------------------

    CBLOCK    0x20    ; Start Data Block
    freq:3
    comp:3

    endc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    org    0
    goto    main
    org    4
    goto    main

main
    clrf    PORTA        ; initialise
    clrf    PORTB        ; initialise
    movlw    0x07        ; Code to turn off the analog comparators
    movwf    CMCON        ; Turn off comparators

    banksel TRISA        ; to Bank 1
    clrf    TRISA
    clrf    TRISB
    banksel    PORTA        ;back to Bank 0
;================================================================================
; input frequency dummy for compare test
    movlw    0x00        ; 20000    ; 0x00 0x4E 0x20
    movwf    freq+2        ; 18100    ; 0x00 0x46 0xB4
    movlw    0x49
    movwf    freq+1
    movlw    0xFF
    movwf    freq

;================================================================================

    load24    Band1L,comp    ;

;================================================================================

;    call    test_eq_or_less    ; eq or less Z & C set        returns FF
                ; greater than Z & C not set    returns 0

    call    test_eq_or_gr    ; eq or greater Z & C set    returns FF
                ; less than Z & C not set    returns 0

    goto    $


;
test_eq_or_gr   
;Test low edge of band - if freq => band edge return FF else return 0
    clrc            ; Clear STATUS,C
    movf    comp+2,W    ; comp = pre-entered band info by macro load24
    subwf    freq+2,W
    btfss    STATUS,C
    retlw    0

    movf    comp+1,W
    subwf    freq+1,W
    btfss    STATUS,C
    retlw    0

    movf    comp,W
    subwf    freq,W
    btfss    STATUS,C
    retlw    0        ; result is < band edge
    retlw    0xFF        ; result is => band edge

test_eq_or_less
;Test high edge of band - if freq =< return FF else return 0
    clrc            ; Clear STATUS,C
    movf    freq+2,W
    subwf    comp+2,W
    btfss    STATUS,C
    retlw    0

    movf    freq+1,W
    subwf    comp+1,W
    btfss    STATUS,C
    retlw    0

    movf    freq,W
    subwf    comp,W
    btfss    STATUS,C
    retlw    0        ; result is > band edge
    retlw    0xFF        ; result is =< band edge

    END
 
You just test each byte from high to low between the two values. If it's different, you have a result, otherwise test the next lower byte.

This is adapted from a 16 bit compare, using input values at fixed locations X h, m, l and Y the same.

A single routine returns higher, equal or lower, which is pretty much normal.
I've not tested it.

Code:
compare_24: ; High bytes
    movf X_h,w
    subwf Y_h,w ; subtract high byte
; If equal (result = 0) ?
    skpz
    goto compare24_end
; Else, compare mid bytes
    movf X_m,w
    subwf Y_m,w ; subtract middle byte
; equal ?
    skpz
    goto compare24_end
; else compare low bytes
    movf X_o,w
    subwf Y_o,w    ; subtract low bytes
compare24_end:
    ; if X=Y then now Z=1.
    ; if Y<X then now C=0.
    ; if X<=Y then now C=1.
    return


I'd stick with having fixed memory locations for each value; one will be the input frequency anyway, the other can have each fixed frequency copied to it - you could add a few lines in front to store that, or store it in advance of calling the compare.
 
For future designs, in case you need fast comparison, this SOC easily implements
a HW comparator. Here I show comparing an internal or external 24 bit value or
HW value to a a simple counter clocked by a DDS resource, all onchip. Trivial to
do a comparison of external values or internal or A/D value or whatever......

1701604591265.png



Will do the following tests :

1701604525302.png



Note of chips overall resources (right hand window) how little of chip was used to do this.

What's typical of 5LP family, multiple copies in many cases, all onchip :

1701604730348.png


You can use the ARM cpu on it or do codeless designs.


Regards, Dana.
 
Last edited:
Just started to reply this morning and the power went off :(

Dana, thanks, probably a bit over the top at the moment.

RJ that's basically what I'm using other than the fact it is split in to the two routines of => & =<.
Will have a play with yours and see what happens.
 
On closer inspection, yours (RJ) uses STATUS,Z while mine was using STATUS,C, so that was the problem.

Anyway, after a bit of playing around, appears to be working as needed but I did break it out to two seperate routines to give =< & =>

As written, it will give X<=Y but I need to mess about doing extra flag checking to get X>=Y which just confuses this stupid brain unless I'm really really concentrating and it's just too hot here to do that :D
 

Latest threads

New Articles From Microcontroller Tips

Back
Top