• 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.

ISR Code Optimize - Assembly

Suraj143

Active Member
Thread starter #1
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:
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
 

Pommie

Well-Known Member
Most Helpful Member
#2
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:
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.
 

Suraj143

Active Member
Thread starter #3
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
 

Pommie

Well-Known Member
Most Helpful Member
#4
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.
 

Suraj143

Active Member
Thread starter #7
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:
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
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
#9
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..
 

Suraj143

Active Member
Thread starter #12
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...!!!
 

Attachments

Pommie

Well-Known Member
Most Helpful Member
#13
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:
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.
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
#14
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.. )

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;
   }
 

Mike - K8LH

Well-Known Member
#16
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!
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'.
 

Mike - K8LH

Well-Known Member
#18
Well, you could unroll the loop, or better yet, use 16 separate 'row' processes (at the expense of code space). For example;

Code:
        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:
        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:

Mike - K8LH

Well-Known Member
#19
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:

Suraj143

Active Member
Thread starter #20
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?
 

Latest threads

EE World Online Articles

Loading

 
Top