Is there a faster way to compare?


Closed Thread
Results 1 to 13 of 13
  1. #1
    Join Date
    Aug 2006
    Location
    Omaha, Nebraska USA
    Posts
    263

    Question Is there a faster way to compare?

    I'm doing something like this (pseudocode):

    FOR INDEX=1 TO SOMETHING
    IF INDEX>A THEN PIN1=1
    IF INDEX>B THEN PIN2=1
    IF INDEX>C THEN PIN3=1
    IF INDEX>D THEN PIN4=1
    IF INDEX>E THEN PIN5=1
    NEXT INDEX

    Each of those IF . . . THENs appears to chew up a lot of time, each reducing the upper limit on the number of iterations (SOMETHING).

    I'm having to do this in/as an interrupt handler and I've got about 7ms (at 8MHz) to do it in.

    Is there a faster/better/simpler way? (Someone <i><u>please</u></i> tell me there is!)

    Fingers crossed here . . .
    Last edited by RussMartin; - 7th February 2010 at 21:05.
    Russ
    N0EVC, xWB6ONT, xWN6ONT

    "Easy to use" is easy to say.

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Are they all BYTE's?
    Is it a PWM output?

    7ms is a LONG TIME.
    <br>
    DT

  3. #3
    Join Date
    Aug 2006
    Location
    Omaha, Nebraska USA
    Posts
    263


    Did you find this post helpful? Yes | No

    Default

    INDEX and A through E are bytes. All five pins are on the same port.

    Not sure if it's PWM or not. But at the end of the interrupt handler, all pins are reset to 0. Values A through E each represent a proportion of SOMETHING. If A through E were equal, all five pins would need to turn on as nearly as possible at the same instant.

    The interrupt (INT_INT) is being driven by a zero-crossing detector at 60 Hz (120 interrupts/second).

    Guess it <i>is</i> PWM, period 120 Hz, and I'm varying the duty cycle on each pin.
    Last edited by RussMartin; - 7th February 2010 at 22:05.
    Russ
    N0EVC, xWB6ONT, xWN6ONT

    "Easy to use" is easy to say.

  4. #4
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    This should be a bit faster ... (untested)
    Code:
    INDEX      VAR BYTE BANK0
    SOMETHING  VAR BYTE BANK0
    A          VAR BYTE BANK0
    B          VAR BYTE BANK0
    C          VAR BYTE BANK0
    D          VAR BYTE BANK0
    
    PIN1       VAR PORTB.0
    PIN2       VAR PORTB.1
    PIN3       VAR PORTB.2
    PIN4       VAR PORTB.3
    
    
    ASM
    TestStart
          movlw   0              ;FOR INDEX=1 TO SOMETHING
          movwf   _INDEX
          
    ForLoop    
          incf    _INDEX,F       
          
          movf    _A,W           ; IF INDEX>A THEN PIN1=1
          subwf   _INDEX,W
          btfsc   STATUS,C
          bsf     _PIN1
          
          movf    _B,W           ; IF INDEX>B THEN PIN2=1
          subwf   _INDEX,W
          btfsc   STATUS,C
          bsf     _PIN2
    
          movf    _C,W           ; IF INDEX>C THEN PIN3=1
          subwf   _INDEX,W
          btfsc   STATUS,C
          bsf     _PIN3
    
          movf    _D,W           ; IF INDEX>D THEN PIN4=1
          subwf   _INDEX,W
          btfsc   STATUS,C
          bsf     _PIN4
          
          movf    _INDEX,W       ; Next INDEX
          subwf   _SOMETHING,W
          btfss   STATUS,Z
        goto    ForLoop
    ENDASM
    DT

  5. #5
    Join Date
    Sep 2007
    Location
    USA, CA
    Posts
    271


    Did you find this post helpful? Yes | No

    Default

    Russ,
    I am sure there are other ways to get the pwm you need (such as interrupts), since this method takes up a HUGE amount of cpu time. However, if that doesn't matter and you just need a bit more speed, consider asm.

    I compiled your snippet with PBP, and it used up 57 words of program space on a 16F. Proton+ did the same code in 36 words; almost 2/3 the size. PBP's asm file is nearly unreadable, so I can't compare them, but here is the Proton output from a single basic line for both 16F and 18F:

    16F...
    [TEST.BAS] IF INDEX>A THEN PORTA.1=1
    MOVF INDEX,W
    SUBWF _A,W
    BTFSC STATUS,0
    GOTO BC@LL4 'go to the next line...
    BSF PORTA,1

    18F...
    [TEST.BAS] IF INDEX>B THEN PORTA.1=1
    MOVF INDEX,W,0
    CPFSLT _B,0
    F@JUMP BC@LL6 'go to the next line...
    BSF PORTA,1,0

  6. #6
    Join Date
    Aug 2006
    Location
    Omaha, Nebraska USA
    Posts
    263


    Did you find this post helpful? Yes | No

    Default

    Thanks for the suggestion, Darrel; I'll try it, expanding to add PIN5 and value E.

    Thanks for the comparison, tenaja.

    Although now I wonder if I'm looking for the wrong problem. Using the o'scope, I see that each of those IF . . . THENs actually takes only about 22us; that's only 110us for all 5. Maybe it's the FOR . . . NEXT. Each time I added an IF . . . THEN, I had to reduce SOMETHING and rescale each of however many variables I was comparing.
    Russ
    N0EVC, xWB6ONT, xWN6ONT

    "Easy to use" is easy to say.

  7. #7
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by RussMartin View Post
    ... Using the o'scope, I see that each of those IF . . . THENs actually takes only about 22us; that's only 110us for all 5. ...
    That's 110us * SOMETHING (the loop count).

    If SOMETHING is ever higher than 63, you will have used up the 7ms and more.

    With the ASM code I gave, each IF takes only 2us @8mhz.
    SOMETHING can be 255 and it will still only take ~2.6ms.

    hth,
    DT

  8. #8
    Join Date
    Aug 2006
    Location
    Omaha, Nebraska USA
    Posts
    263


    Did you find this post helpful? Yes | No

    Default

    Yes, I knew about the <b>* SOMETHING</B> !

    But now I have the opposite problem . . . since yours is so much faster, I would need to run it almost three times (because the variables can range from 0 to whatever SOMETHING is scaled to). Should I just run it three times in succession, or do I need to go to a WORD variable for SOMETHING? (I need to scale SOMETHING through as much of that time span as possible.)
    Russ
    N0EVC, xWB6ONT, xWN6ONT

    "Easy to use" is easy to say.

  9. #9
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default

    since yours is so much faster, I would need to run it almost three times (because the variables can range from 0 to whatever SOMETHING is scaled to).


    Totally Lost me on that one.
    <br>
    DT

  10. #10
    Join Date
    Aug 2006
    Location
    Omaha, Nebraska USA
    Posts
    263


    Did you find this post helpful? Yes | No

    Default

    Okay, let me background this first.

    For each of 5 channels: A 0-5V value is read (derived from an op-amp) by an ADC channel (presently at 10 bits, so 0-1023). That value is manipulated depending on other data (an offset or a correction, for example). The complementary value (1023-value), scaled so that 0 (1023-1023) can be managed in x repetitions (the maximum that can be fit into about 7.8ms) of the loop, is how long the delay in the interrupt handler must be before turning on the corresponding output pin to a triac driver. Normally, a 5us pulse would be adequate to keep the triac on until the end of the AC phase, but the indicator for the channel is an LED, so the pin is left high until the end of the phase.

    Just sending a pulse on a pin means running the FOR . . . NEXT loop only up to the scaled value and sending the pulse; keeping the indicator on proportionately (well, somewhat) means the pin must stay high until near the end of the phase.

    Your code running to 255 and finishing in 2.6ms means that only 36 percent of the 7.8ms period is controlled, because it is so fast. Proportionately, the phase would have to be scaled something like 0-765, probably a little less.

    Could I just run additional cycles of the tests before incrementing the INDEX to stretch it out?

    The code works as is, but over a very limited signal range.
    Last edited by RussMartin; - 8th February 2010 at 06:30.
    Russ
    N0EVC, xWB6ONT, xWN6ONT

    "Easy to use" is easy to say.

  11. #11
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,795


    Did you find this post helpful? Yes | No

    Default

    I have not tested the idea.

    Instead of writing each IF-THEN test to the port, writing to a variable and at the end that variable to the port will be faster?

    Ioannis

  12. #12
    Join Date
    Aug 2005
    Location
    Michigan, USA
    Posts
    224


    Did you find this post helpful? Yes | No

    Default

    Hi Russ,

    Have you considered using timer derived periodic interrupts and performing just one PWM "step" per interrupt? Perhaps spreading out 256 "steps" across the 8.333-msec period (8333-usecs/256 = 32.55-usec interrupts)?

    Here's another method like Darrel's which would work well if you group the outputs consecutively (B7..B3 or B4..B0 for example). Updating the port from a 'shadow' register allows precise bit update timing (multiple bits with same duty cycle value will update at exactly the same time).

    Regards, Mike

    Code:
    ;
    ;  1/256th step, 18 cycles (isochronous), active high output
    ;  on duty cycle match until end-of-period
    ;
            clrf    shadow          ; clear 'shadow'                  |B0
            movf    led+4,W         ; led[4] duty cycle, 0..255       |B0
            subwf   dcy,W           ; C = led[4] >= dcy               |B0
            rlf     shadow,F        ;                                 |B0
            movf    led+3,W         ; led[3] duty cycle, 0..255       |B0
            subwf   dcy,W           ; C = led[3] >= dcy               |B0
            rlf     shadow,F        ;                                 |B0
            movf    led+2,W         ; led[2] duty cycle, 0..255       |B0
            subwf   dcy,W           ; C = led[2] >= dcy               |B0
            rlf     shadow,F        ;                                 |B0
            movf    led+1,W         ; led[1] duty cycle, 0..255       |B0
            subwf   dcy,W           ; C = led[1] >= dcy               |B0
            rrf     shadow,F        ;                                 |B0
            movf    led+0,W         ; led[0] duty cycle, 0..255       |B0
            subwf   dcy,W           ; C = led[0] >= dcy               |B0
            rlf     shadow,W        ; W = led 'step' output           |B0
            movwf   PORTB           ; update LEDs                     |B0
            incf    dcy,F           ; bump duty cycle counter         |B0
    ;

  13. #13
    Join Date
    Aug 2006
    Location
    Omaha, Nebraska USA
    Posts
    263


    Did you find this post helpful? Yes | No

    Default

    Thanks, Ioannis and Mike. Let me noodle with your suggestions for a bit.

    Meanwhile, for anyone interested:

    For an IF A [comparison] B THEN statement, without the appended action, the execution time at 8MHz if A and B are WORDs appears to be about 22-24us; if A and B are BYTEs, it appears to be about 5-6us. These numbers are not down to a gnat's whisker; they are as measured on my scope (Tektronix 465M).
    Russ
    N0EVC, xWB6ONT, xWN6ONT

    "Easy to use" is easy to say.

Similar Threads

  1. How to compare strings/array? RFID Project
    By dan-tron in forum mel PIC BASIC Pro
    Replies: 100
    Last Post: - 10th April 2017, 08:21
  2. how to compare data
    By Mus.me in forum mel PIC BASIC Pro
    Replies: 19
    Last Post: - 1st November 2009, 23:30
  3. Compare Data
    By Pesticida in forum mel PIC BASIC Pro
    Replies: 9
    Last Post: - 14th February 2008, 21:40
  4. 12F675 compare voltage help.
    By geckogrotto in forum mel PIC BASIC Pro
    Replies: 19
    Last Post: - 2nd February 2007, 17:46
  5. OT - Firefox browser - faster performance
    By malc-c in forum Off Topic
    Replies: 2
    Last Post: - 14th August 2006, 11:33

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts