1. 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.
    Dismiss Notice

ISR Code Optimize - Assembly

Discussion in 'Microcontrollers' started by Suraj143, Jan 1, 2018.

  1. Suraj143

    Suraj143 Active Member

    Joined:
    Jan 11, 2007
    Messages:
    1,601
    Likes:
    2
    Location:
    South Mald Isld
    Hi,

    I Want to check the 8bits of 29 registers on each interrupt.

    Means
    In 1st interrupt the code checks bit 7 of the 29 registers.
    In 2nd interrupt the code checks bit 6 of the 29 registers.
    In 3rd interrupt the code checks bit 5 of the 29 registers.
    In 4th interrupt the code checks bit 4 of the 29 registers.
    In 5th interrupt the code checks bit 3 of the 29 registers.
    In 6th interrupt the code checks bit 2 of the 29 registers.
    In 7th interrupt the code checks bit 1 of the 29 registers.
    In 8th interrupt the code checks bit 0 of the 29 registers.

    Is there any method to add a variable to the bit ? Otherwise I have to write the same code 8 times. :(

    Code (text):

    ISR_1
           movlw    .29
           movwf    Col_Counter
    nxtbyte
            bcf     SR_Data         ; 1
            btfss   INDF,7          ; 1
            bsf     SR_Data         ; 1
            bsf     SR_Clock        ; 1
            bcf     SR_Clock        ; 1
            movlw    .2                ; 1
            addwf    FSR,F         ; 1
            decfsz    Col_Counter,F    ; 1
            goto    nxtbyte         ; 2
     
  2. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,293
    Likes:
    356
    Location:
    Brisbane Australia
    ONLINE
    When you say "optimize" is that for speed or memory?

    If it's for speed then move the movlw .2 outside the loop as it's never changed and write it as a macro so it can be repeated 8 times.

    If it's for memory then use an sfr with a bit mask and shift it right each time. When there is a carry you have just done bit 0 so shift it right once more to start again at bit 7.

    Something along the line of,
    Code (text):

    ISR_ALL
           movlw    .29
           movwf    Col_Counter
    nxtbyte
            bcf     SR_Data         ; 1
            movfw    mask
            andwf   INDF,w          ; 1
            btfsc    STATUS,Z
            bsf     SR_Data         ; 1
            bsf     SR_Clock        ; 1
            bcf     SR_Clock        ; 1
            movlw    .2                ; 1
            addwf    FSR,F         ; 1
            decfsz    Col_Counter,F    ; 1
            goto    nxtbyte         ; 2
            rrf        mask,f
            btfsc   STATUS,C
            rrf        mask,f
     
    Edit, is this pic18 code as you increment FSR twice?

    Mike.
     
  3. Suraj143

    Suraj143 Active Member

    Joined:
    Jan 11, 2007
    Messages:
    1,601
    Likes:
    2
    Location:
    South Mald Isld
    Hi, I want to minimize interrupt latency. Needs to do with less cycles (Speed Code).

    You are right. I will take literal 2 outside the loop.So it will reduce another 1 instruction cycle.
    This is for PIC16F886. The 29 registers I have defined like this 30h, 32h, 34h...etc

    Can I use a variable to detect a particular bit like this?

    btfss INDF,Variable ; Variable = 0,1,2,3,4,5,6,7
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,293
    Likes:
    356
    Location:
    Brisbane Australia
    ONLINE

    You can't use a variable, you have to and it with a mask.

    If you have enough memory you could just use 240 (assuming 30*8) locations and just use bit 0. That way in your next ISR you just carry on incrementing.

    Mike.
     
  6. Nigel Goodwin

    Nigel Goodwin Super Moderator Most Helpful Member

    Joined:
    Nov 17, 2003
    Messages:
    39,380
    Likes:
    665
    Location:
    Derbyshire, UK
    No you can't do that, also looping would increase latency, not decrease it.
     
  7. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,649
    Likes:
    109
    Location:
    Michigan, USA
    Hi Suraj:

    Are you using this software to load four 8-bit shift register ICs in cascade?
     
  8. Suraj143

    Suraj143 Active Member

    Joined:
    Jan 11, 2007
    Messages:
    1,601
    Likes:
    2
    Location:
    South Mald Isld
    OK thanks guys.

    @ Mike-K8LH

    Yes you are correct.I'm feeding to four 74HC595 registers on a cascade arrangement.I'm doing a 16 row 29 column design.Anode row method , 1/16 Duty Cycle :)

    Below how I placed registers.

    Code (text):

    D2 D4 D6 D8 D10 D12 D14 D16 D18 D20 D22 D24 D26 D28----- D58
    D1 D3 D5 D7 D9  D11 D13 D15 D17 D19 D21 D23 D25 D27----- D57
     
  9. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,649
    Likes:
    109
    Location:
    Michigan, USA
    My goodness, that's a pretty big array. Let me think about this...

    Cheerful regards, Mike
     
    Last edited: Jan 3, 2018
  10. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,393
    Likes:
    923
    Location:
    Rochdale UK
    For speed, I used the interrupt to drive 8 74hc595's you only need to shift one bit per interrupt.

    I think the difference is that I was using portb to drive the rows and serially controlling the columns via the interrupt..

    If you need the C code I'll gladly post it here..
     
  11. Suraj143

    Suraj143 Active Member

    Joined:
    Jan 11, 2007
    Messages:
    1,601
    Likes:
    2
    Location:
    South Mald Isld
    Hi,

    Here is the register map how I placed with more details.
     

    Attached Files:

  12. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,393
    Likes:
    923
    Location:
    Rochdale UK
    Have you a quick schematic? It just helps the thought process.
     
  13. Suraj143

    Suraj143 Active Member

    Joined:
    Jan 11, 2007
    Messages:
    1,601
    Likes:
    2
    Location:
    South Mald Isld
    Hi,

    Here is the diagram. Anode Row Design.

    Each row has different colour LEDs. I use unbranded chinese LEDs. With a 10mA current the bright is awesome.Not sure the 100R anode resisters are too high...!!!
     

    Attached Files:

  14. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,293
    Likes:
    356
    Location:
    Brisbane Australia
    ONLINE
    If your data is static during the writes then you could shift it through the carry and back to where it started.

    I.E.
    Code (text):

    ISR_1
           movlw    .29
           movwf    Col_Counter
    nxtbyte
            bcf     SR_Data         ; 1
            bcf     STATUS,C        ;ensure zero gets shifted in
            rlf     INDF,f          ;move bit 7 into Carry
            btfss   STATUS,C        ;jump if bit 7 was zero
            goto    skip
            bsf     INDF,0          ;set bit 0
            bsf     SR_Data         ;set data bit
    skip    bsf     SR_Clock        ; 1
            bcf     SR_Clock        ; 1
            movlw    .2                ; 1
            addwf    FSR,F         ; 1
            decfsz    Col_Counter,F    ; 1
            goto    nxtbyte         ; 2
       
     
    The above also doesn't corrupt W.

    Mike.
     
  15. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,393
    Likes:
    923
    Location:
    Rochdale UK
    It was asked before.... Why are you looping in the ISR at all... If you make COL a global variable Just have the ISR shove one piece data onto PORTB and one onto PORTD each pass.... As long as your ISR fires quick enough it will look good!

    Here's mine ( but with one port.. )

    Code (c):

    void interrupt ISR(void)
         {
       if(TMR2IF)
           {
           PORTB = 0;    // Blank portB
           if(displayPointer == 0 )
               RC4 = 1;   // Start col
           RC3 = 1;
           __delay_us(50);    // clock
           RC3 = 0;
           RC4 = 0;  //  only one col on at a time..
           PORTB = buffer[displayPointer];  // Data in ram blit to LED panel
           if(++displayPointer==64)   // 64 columns
               displayPointer = 0;
             }
       TMR2IF = 0;
       }
     
     
  16. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,649
    Likes:
    109
    Location:
    Michigan, USA
    Hi Suraj,

    Is that drawing correct? The 16F886 doesn't have a Port D, does it?
     
  17. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,649
    Likes:
    109
    Location:
    Michigan, USA
    Wouldn't you update all 29 bits in the shift registers before updating a row? If so, 29 interrupts per row multiplied by 16 rows with perhaps a 120-Hz refresh rate would work out to something like ~17.96-usec interrupts, wouldn't it? That seems like a lot of processing 'overhead'.
     
    • Agree Agree x 1
  18. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,393
    Likes:
    923
    Location:
    Rochdale UK
    Remember! All I was doing was displaying 32x16 pixel array... The results were very pleasing... I wouldn't run much faster than 50 hz.. I only did it to see if I could..
     
  19. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,649
    Likes:
    109
    Location:
    Michigan, USA
    Well, you could unroll the loop, or better yet, use 16 separate 'row' processes (at the expense of code space). For example;

    Code (text):
            radix   dec
    isrproc
            pushisr                 ; save context
            incf    row,F           ; bump 'row' counter
            bcf     row,4           ; 0..15, inclusive
            movf    row,W           ;
            addwf   PCL,F           ;
            goto    row00           ;
            goto    row01           ;
            goto    row02           ;
            goto    row03           ;
            goto    row04           ;
            goto    row05           ;
            goto    row06           ;
            goto    row07           ;
            goto    row08           ;
            goto    row09           ;
            goto    row10           ;
            goto    row11           ;
            goto    row12           ;
            goto    row13           ;
            goto    row14           ;
            goto    row15           ;
    isrexit
            pullisr                 ; restore context
            retfie                  ;

    row00   rowproc 0               ;
    row01   rowproc 1               ;
    row02   rowproc 2               ;
    row03   rowproc 3               ;
    row04   rowproc 4               ;
    row05   rowproc 5               ;
    row06   rowproc 6               ;
    row07   rowproc 7               ;
    row08   rowproc 8               ;
    row09   rowproc 9               ;
    row10   rowproc 10              ;
    row11   rowproc 11              ;
    row12   rowproc 12              ;
    row13   rowproc 13              ;
    row14   rowproc 14              ;
    row15   rowproc 15              ;
     
    The 'rowproc' macro might look something like this (assuming SR_Clock & SR_Data on PORTC and "array" equates to your display buffer);
    Code (text):

            radix   dec
    rowproc macro   row
            local   addr,bit
    addr = array + (row>7)
    bit = row%8
            clrf    PORTC           ; SR_Clock & SR_Data = 0          |00

            btfsc   addr+00,bit     ; column 00                       |00
            bsf     SR_Data         ;                                 |00
            bsf     SR_Clock        ; strobe SR_Clock                 |00
            clrf    PORTC           ; clear SR_Data                   |00

            btfsc   addr+02,bit     ; column 01                       |00
            bsf     SR_Data         ;                                 |00
            bsf     SR_Clock        ; strobe SR_Clock                 |00
            clrf    PORTC           ; clear SR_Data                   |00

            btfsc   addr+04,bit     ; column 02                       |00
            bsf     SR_Data         ;                                 |00
            bsf     SR_Clock        ; strobe SR_Clock                 |00
            clrf    PORTC           ; clear SR_Data                   |00
    ~~~~~
            btfsc   addr+56,bit     ; column 29                       |00
            bsf     SR_Data         ;                                 |00
            bsf     SR_Clock        ; strobe SR_Clock                 |00
            clrf    PORTC           ;                                 |00
    ;
            clrf    PORTB           ; blank the display               |00
            clrf    PORTD           ;  "                              |00
            bsf     SR_Latch        ; strobe SR_Latch                 |00
            bcf     SR_Latch        ;  "                              |00
         if(row<8)
            bsf     PORTB,bit       ; turn on new row 00..07          |00
         else
            bsf     PORTD,bit       ; turn on new row 08..15          |00
         endif
            goto    isrexit         ;                                 |00
            endm
     
    The "good news" is that ISR overhead is reduced from around ~350-400 cycles per row interrupt to perhaps around ~130 cycles (plus context save and restore). The "bad news" is that you would use up about a quarter of the memory available on a 16F886 (about ~2000 words).

    Food for thought.

    Good luck. Have fun. Cheerful regards, Mike
     
    Last edited: Jan 6, 2018
  20. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,649
    Likes:
    109
    Location:
    Michigan, USA
    I should mention that if you have three additional pins available on the same port as SR_Clock and SR_Data you can use separate data lines to load the shift registers in parallel using just 8 clocks instead of 29 clocks (a 4-bit wide parallel SPI port of sorts). This would reduce ISR overhead to around 100 cycles (plus context save & restore) per interrupt and the ISR process would require about ~1000 words of program memory.

    Cheerful regards, Mike
     
    Last edited: Jan 6, 2018
  21. Suraj143

    Suraj143 Active Member

    Joined:
    Jan 11, 2007
    Messages:
    1,601
    Likes:
    2
    Location:
    South Mald Isld
    Hi thank you for the codes. Give me few days to study those codes.

    I got a hardware problem with my design. Its an anode row design.But there is no transistor array to the column shift registers. To turn OFF a bit I should send logic 1 to those shift registers causing most off the columns have 5V which will turn ON leakacge LEDs ( leackage current is passing through UDN2981 inside protection diode to GND). I burned many of cheapy leds while checking. Also many of Leds are lighting dimmly.

    Going to use transistor arrays to each shift registers.

    Whats your comments guys to make this display smoother with an even brightness?
     

Share This Page