Efficient interrupt processing

Post your requests and ideas on the future development of mikroC for dsPIC30/33 and PIC24.
Post Reply
Author
Message
taoistmonk
Posts: 5
Joined: 03 Aug 2008 18:25

Efficient interrupt processing

#1 Post by taoistmonk » 03 Aug 2008 22:25

I just learned the interrupt routine shell that Micro-C generates
automatically pushes and pops all registers, even though the routine
actually only uses two registers W0 and W1. This is contrary to the
claims made by the documentation and it results in 48 wasted cycles
of CPU overhead. If this is true then this is a real disappointment. We have no other choice but to use a compiler that generates efficient code. We design real-time systems, and this just doesn't cut it. Tell me I'm wrong and I'll be happy, otherwise I'll be buying microchips compiler. :cry:

idakota
Posts: 334
Joined: 27 Sep 2006 08:07
Location: Pretoria/South Africa
Contact:

#2 Post by idakota » 04 Aug 2008 07:02

I think that for any true real-time systems it is better to code the time critical components in pure ASM. No C compiler will ever be able to match the power and flexability of hand coding is asembler.

So, do your interrupt routines in pure ASM :)

taoistmonk
Posts: 5
Joined: 03 Aug 2008 18:25

#3 Post by taoistmonk » 04 Aug 2008 14:00

I agree, and we know enough about assembler to do this. The problem is that when you have an org directive say at 0x14, the mikroE compiler generates the shell assembler routines with the inefficient code that pushes-pops all of the registers. We could certainly strip out this code manually or automatically. We would then have to generate hex from this newly modified assembly file. Were not as familiar with the MikroE tools to know if this is possible. Any Comments or suggestions? Thanks for the comments!

idakota
Posts: 334
Joined: 27 Sep 2006 08:07
Location: Pretoria/South Africa
Contact:

#4 Post by idakota » 04 Aug 2008 14:07

Oh yes, of course. ME doesn't allow you to write your own interrupt call routine....maybe the next version?

SmartShadow
Posts: 14
Joined: 27 Nov 2007 12:30

#5 Post by SmartShadow » 20 Aug 2008 20:29

First of all Hello all :D

I think u are wrong idakota. Take a look on this code, and then on the code in asm (generated by their compiler). ME team si working hard to bring us the best products and I think we should encourage them :D (not necessarily buy other compilers ;) ).

It's a short multitasking code. Maybe somebody else could find it useful. :D

short k=0,k1=0,k2=0;

//void z_delay_us(int x)
//{
// asm{
// MOV [W14+-8], W0
// sub_delay:
// REPEAT #4
// NOP
// DEC W0
// CP0 W0
// BRA NZ,sub_delay
// }
//}

void C1I() org 0x16 {
IFS0 = 0xFF6D;
T3CON = 0x0000;
}

void C2I() org 0x1c {
IFS0 = 0xFF6D;
T3CON = 0x8030;
}

void T1I() org 0x22 {
//** it is necessary to clear manually the interrupt flag:
IFS0 = 0xFF6D; // Clear TMR1IF

//** user code starts here
PORTF = ~ PORTF; // Invert PORTD
k = ~k;
if (k==0)
k1=k1+1;
else
k2=k2+1; //** user code ends here
}

void main() {
char txt[10];
int i;
TRISF = 0x0000; // PORTD as output
PORTF = 0xAAAA; // Initialize PORTD
IPC0 = 0x0050;
IPC1 = 0x7006; // Interrupt priority level = 1
IFS0 = 0xFF6D; // Clear TMR1IF
IEC0 = 0x0092; // Enable Timer1 interrupts
PR3 = 0x9897;
IC1CON = 0x0083;
IC2CON = 0x0083;

T3CON = 0x8030; // Timer1 ON, internal clock FCY, prescaler 1:256

ADPCFG = 0xFFFF;

Lcd_Custom_Init_DsPicPro2();
while (1)
for (i=0;i<=65535;i++)
{
IntToStr(i,txt);
Lcd_Custom_Out(1,1, txt);
ByteToStr(k1,txt);
Lcd_Custom_Out(2,1, txt);
ByteToStr(k2,txt);
Lcd_Custom_Out(2,8, txt);
}
}

And now the best part, the asm code generated with mikroc for dspic.

; ADDRESS OPCODE ASM
; ----------------------------------------------
$0000 $0406C2 GOTO _main
$0002 $000000 NOPR
$0004 $FFFFFF NOPR
$0006 $FFFFFF NOPR
$0008 $FFFFFF NOPR
$000A $FFFFFF NOPR
$000C $FFFFFF NOPR
$000E $FFFFFF NOPR
$0010 $FFFFFF NOPR
$0012 $FFFFFF NOPR
$0014 $FFFFFF NOPR
$0016 $000158 GOTO _C1I
$0018 $FFFFFF NOPR
$001A $FFFFFF NOPR
$001C $00013A GOTO _C2I
$001E $FFFFFF NOPR
$0020 $FFFFFF NOPR
$0022 $000100 GOTO _T1I
$0024 $FFFFFF NOPR
$0026 $FFFFFF NOPR
$0028 $FFFFFF NOPR
$002A $FFFFFF NOPR
$002C $FFFFFF NOPR
$002E $FFFFFF NOPR
$0030 $FFFFFF NOPR
$0032 $FFFFFF NOPR
$0034 $FFFFFF NOPR
$0036 $FFFFFF NOPR
$0038 $FFFFFF NOPR
$003A $FFFFFF NOPR
$003C $FFFFFF NOPR
$003E $FFFFFF NOPR
$0040 $FFFFFF NOPR
$0042 $FFFFFF NOPR
$0044 $FFFFFF NOPR
$0046 $FFFFFF NOPR
$0048 $FFFFFF NOPR
$004A $FFFFFF NOPR
$004C $FFFFFF NOPR
$004E $FFFFFF NOPR
$0050 $FFFFFF NOPR
$0052 $FFFFFF NOPR
$0054 $FFFFFF NOPR
$0056 $FFFFFF NOPR
$0058 $FFFFFF NOPR
$005A $FFFFFF NOPR
$005C $FFFFFF NOPR
$005E $FFFFFF NOPR
$0060 $FFFFFF NOPR
$0062 $FFFFFF NOPR
$0064 $FFFFFF NOPR
$0066 $FFFFFF NOPR
$0068 $FFFFFF NOPR
$006A $FFFFFF NOPR
$006C $FFFFFF NOPR
$006E $FFFFFF NOPR
$0070 $FFFFFF NOPR
$0072 $FFFFFF NOPR
$0074 $FFFFFF NOPR
$0076 $FFFFFF NOPR
$0078 $FFFFFF NOPR
$007A $FFFFFF NOPR
$007C $FFFFFF NOPR
$007E $FFFFFF NOPR
$0080 $FFFFFF NOPR
$0082 $FFFFFF NOPR
$0084 $FFFFFF NOPR
$0086 $FFFFFF NOPR
$0088 $FFFFFF NOPR
$008A $FFFFFF NOPR
$008C $FFFFFF NOPR
$008E $FFFFFF NOPR
$0090 $FFFFFF NOPR
$0092 $FFFFFF NOPR
$0094 $FFFFFF NOPR
$0096 $FFFFFF NOPR
$0098 $FFFFFF NOPR
$009A $FFFFFF NOPR
$009C $FFFFFF NOPR
$009E $FFFFFF NOPR
$00A0 $FFFFFF NOPR
$00A2 $FFFFFF NOPR
$00A4 $FFFFFF NOPR
$00A6 $FFFFFF NOPR
$00A8 $FFFFFF NOPR
$00AA $FFFFFF NOPR
$00AC $FFFFFF NOPR
$00AE $FFFFFF NOPR
$00B0 $FFFFFF NOPR
$00B2 $FFFFFF NOPR
$00B4 $FFFFFF NOPR
$00B6 $FFFFFF NOPR
$00B8 $FFFFFF NOPR
$00BA $FFFFFF NOPR
$00BC $FFFFFF NOPR
$00BE $FFFFFF NOPR
$00C0 $FFFFFF NOPR
$00C2 $FFFFFF NOPR
$00C4 $FFFFFF NOPR
$00C6 $FFFFFF NOPR
$00C8 $FFFFFF NOPR
$00CA $FFFFFF NOPR
$00CC $FFFFFF NOPR
$00CE $FFFFFF NOPR
$00D0 $FFFFFF NOPR
$00D2 $FFFFFF NOPR
$00D4 $FFFFFF NOPR
$00D6 $FFFFFF NOPR
$00D8 $FFFFFF NOPR
$00DA $FFFFFF NOPR
$00DC $FFFFFF NOPR
$00DE $FFFFFF NOPR
$00E0 $FFFFFF NOPR
$00E2 $FFFFFF NOPR
$00E4 $FFFFFF NOPR
$00E6 $FFFFFF NOPR
$00E8 $FFFFFF NOPR
$00EA $FFFFFF NOPR
$00EC $FFFFFF NOPR
$00EE $FFFFFF NOPR
$00F0 $FFFFFF NOPR
$00F2 $FFFFFF NOPR
$00F4 $FFFFFF NOPR
$00F6 $FFFFFF NOPR
$00F8 $FFFFFF NOPR
$00FA $FFFFFF NOPR
$00FC $FFFFFF NOPR
$00FE $FFFFFF NOPR
$0100 $ _T1I:
$0100 $F80036 PUSH RCOUNT
$0102 $781F80 PUSH W0
$0104 $200020 MOV #2, W0
$0106 $09000C REPEAT #12
$0108 $781FB0 PUSH [W0++]
;Timer1_interrupt.c,50 :: void T1I() org 0x22 {
;Timer1_interrupt.c,52 :: IFS0 = 0xFF6D; // Clear TMR1IF
$010A $2FF6D0 MOV #65389, W0
$010C $880420 MOV W0, IFS0
;Timer1_interrupt.c,55 :: PORTF = ~ PORTF; // Invert PORTD
$010E $202E00 MOV #@PORTF, W0
$0110 $EA8810 COM [W0], [W0]
;Timer1_interrupt.c,56 :: k = ~k;
$0112 $218162 MOV #@_k, W2
$0114 $784012 MOV.B [W2], W0
$0116 $EAC080 COM.B W0, W1
$0118 $784901 MOV.B W1, [W2]
;Timer1_interrupt.c,57 :: if (k==0)
$011A $50C060 SUB.B W1, #0, W0
$011C $3A0005 BRA NZ L_T1I_0, L_T1I_0
;Timer1_interrupt.c,58 :: k1=k1+1;
$011E $200011 MOV.B #1, W1
$0120 $218170 MOV #@_k1, W0
$0122 $40C810 ADD.B W1, [W0], [W0]
$0124 $04012E GOTO L_T1I_1
$0128 $ L_T1I_0:
;Timer1_interrupt.c,60 :: k2=k2+1; //** user code ends here
$0128 $200011 MOV.B #1, W1
$012A $218180 MOV #@_k2, W0
$012C $40C810 ADD.B W1, [W0], [W0]
$012E $ L_T1I_1:
;Timer1_interrupt.c,61 :: }
$012E $ L_end__T1I:
$012E $2001A0 MOV #26, W0
$0130 $09000C REPEAT #12
$0132 $78104F POP [W0--]
$0134 $78004F POP W0
$0136 $F90036 POP RCOUNT
$0138 $064000 RETFIE
$013A $ _C2I:
$013A $F80036 PUSH RCOUNT
$013C $781F80 PUSH W0
$013E $200020 MOV #2, W0
$0140 $09000C REPEAT #12
$0142 $781FB0 PUSH [W0++]
;Timer1_interrupt.c,45 :: void C2I() org 0x1c {
;Timer1_interrupt.c,46 :: IFS0 = 0xFF6D;
$0144 $2FF6D0 MOV #65389, W0
$0146 $880420 MOV W0, IFS0
;Timer1_interrupt.c,47 :: T3CON = 0x8030;
$0148 $280300 MOV #32816, W0
$014A $880890 MOV W0, T3CON
;Timer1_interrupt.c,48 :: }
$014C $ L_end__C2I:
$014C $2001A0 MOV #26, W0
$014E $09000C REPEAT #12
$0150 $78104F POP [W0--]
$0152 $78004F POP W0
$0154 $F90036 POP RCOUNT
$0156 $064000 RETFIE
$0158 $ _C1I:
$0158 $F80036 PUSH RCOUNT
$015A $781F80 PUSH W0
$015C $200020 MOV #2, W0
$015E $09000C REPEAT #12
$0160 $781FB0 PUSH [W0++]
;Timer1_interrupt.c,40 :: void C1I() org 0x16 {
;Timer1_interrupt.c,41 :: IFS0 = 0xFF6D;
$0162 $2FF6D0 MOV #65389, W0
$0164 $880420 MOV W0, IFS0
;Timer1_interrupt.c,42 :: T3CON = 0x0000;
$0166 $200000 MOV #0, W0
$0168 $880890 MOV W0, T3CON
;Timer1_interrupt.c,43 :: }
$016A $ L_end__C1I:
$016A $2001A0 MOV #26, W0
$016C $09000C REPEAT #12
$016E $78104F POP [W0--]
$0170 $78004F POP W0
$0172 $F90036 POP RCOUNT
$0174 $064000 RETFIE
//here was the LCD and conversion code ...

and the main function ...

$06C2 $ _main:
$06C2 $20800F MOV #0x800, W15
$06C4 $217FE0 MOV #0x0017FE, W0
$06C6 $880100 MOV W0, SPLIM
$06C8 $A84044 BSET CORCON, #2
$06CA $200010 MOV 1, W0
$06CC $8801A0 MOV W0, PSVPAG
$06CE $218160 MOV #@_k, W0
$06D0 $280001 MOV #@?ICS_k, W1
$06D2 $090002 REPEAT #2
$06D4 $785831 MOV.B [W1++], [W0++]
$06D6 $FA000C LNK #12
;Timer1_interrupt.c,63 :: void main() {
;Timer1_interrupt.c,66 :: TRISF = 0x0000; // PORTD as output
$06D8 $200000 MOV #0, W0
$06DA $8816F0 MOV W0, TRISF
;Timer1_interrupt.c,67 :: PORTF = 0xAAAA; // Initialize PORTD
$06DC $2AAAA0 MOV #43690, W0
$06DE $881700 MOV W0, PORTF
;Timer1_interrupt.c,68 :: IPC0 = 0x0050;
$06E0 $200500 MOV #80, W0
$06E2 $8804A0 MOV W0, IPC0
;Timer1_interrupt.c,69 :: IPC1 = 0x7006; // Interrupt priority level = 1
$06E4 $270060 MOV #28678, W0
$06E6 $8804B0 MOV W0, IPC1
;Timer1_interrupt.c,70 :: IFS0 = 0xFF6D; // Clear TMR1IF
$06E8 $2FF6D0 MOV #65389, W0
$06EA $880420 MOV W0, IFS0
;Timer1_interrupt.c,71 :: IEC0 = 0x0092; // Enable Timer1 interrupts
$06EC $200920 MOV #146, W0
$06EE $880460 MOV W0, IEC0
;Timer1_interrupt.c,72 :: PR3 = 0x9897;
$06F0 $298970 MOV #39063, W0
$06F2 $880870 MOV W0, PR3
;Timer1_interrupt.c,73 :: IC1CON = 0x0083;
$06F4 $200830 MOV #131, W0
$06F6 $880A10 MOV W0, IC1CON
;Timer1_interrupt.c,74 :: IC2CON = 0x0083;
$06F8 $200830 MOV #131, W0
$06FA $880A30 MOV W0, IC2CON
;Timer1_interrupt.c,76 :: T3CON = 0x8030; // Timer1 ON, internal clock FCY, prescaler 1:256
$06FC $280300 MOV #32816, W0
$06FE $880890 MOV W0, T3CON
;Timer1_interrupt.c,78 :: ADPCFG = 0xFFFF;
$0700 $2FFFF0 MOV #65535, W0
$0702 $881540 MOV W0, ADPCFG
;Timer1_interrupt.c,80 :: Lcd_Custom_Init_DsPicPro2();
$0704 $07FDDA RCALL _Lcd_Custom_Init_DsPicPro2, 0-1
;Timer1_interrupt.c,81 :: while (1)
$0706 $ L_main_2:
;Timer1_interrupt.c,82 :: for (i=0;i<=65535;i++)
$0706 $200000 MOV #0, W0
$0708 $980750 MOV W0, [W14+10]
$070A $ L_main_4:
$070A $47006A ADD W14, #10, W0
$070C $780110 MOV [W0], W2
$070E $2FFFF1 MOV #65535, W1
$0710 $510001 SUB W2, W1, W0
$0712 $3E0033 BRA GTU L_main_5, L_main_5
;Timer1_interrupt.c,84 :: IntToStr(i,txt);
$0714 $470060 ADD W14, #0, W0
$0716 $781F80 PUSH W0
$0718 $47006A ADD W14, #10, W0
$071A $781F90 PUSH [W0]
$071C $07FE22 RCALL _IntToStr, 0-104015
$071E $B1004F SUB #4, W15
;Timer1_interrupt.c,85 :: Lcd_Custom_Out(1,1, txt);
$0720 $470060 ADD W14, #0, W0
$0722 $781F80 PUSH W0
$0724 $200010 MOV.B #1, W0
$0726 $781F80 PUSH W0
$0728 $200010 MOV.B #1, W0
$072A $781F80 PUSH W0
$072C $07FF4B RCALL _Lcd_Custom_Out, 0-10000015
$072E $B1006F SUB #6, W15
;Timer1_interrupt.c,86 :: ByteToStr(k1,txt);
$0730 $470060 ADD W14, #0, W0
$0732 $781F80 PUSH W0
$0734 $218170 MOV #@_k1, W0
$0736 $784010 MOV.B [W0], W0
$0738 $FB0000 SE W0, W0
$073A $781F80 PUSH W0
$073C $07FF83 RCALL _ByteToStr, 0-100015
$073E $B1004F SUB #4, W15
;Timer1_interrupt.c,87 :: Lcd_Custom_Out(2,1, txt);
$0740 $470060 ADD W14, #0, W0
$0742 $781F80 PUSH W0
$0744 $200010 MOV.B #1, W0
$0746 $781F80 PUSH W0
$0748 $200020 MOV.B #2, W0
$074A $781F80 PUSH W0
$074C $07FF3B RCALL _Lcd_Custom_Out, 0-10000015
$074E $B1006F SUB #6, W15
;Timer1_interrupt.c,88 :: ByteToStr(k2,txt);
$0750 $470060 ADD W14, #0, W0
$0752 $781F80 PUSH W0
$0754 $218180 MOV #@_k2, W0
$0756 $784010 MOV.B [W0], W0
$0758 $FB0000 SE W0, W0
$075A $781F80 PUSH W0
$075C $07FF73 RCALL _ByteToStr, 0-100015
$075E $B1004F SUB #4, W15
;Timer1_interrupt.c,89 :: Lcd_Custom_Out(2,8, txt);
$0760 $470060 ADD W14, #0, W0
$0762 $781F80 PUSH W0
$0764 $200080 MOV.B #8, W0
$0766 $781F80 PUSH W0
$0768 $200020 MOV.B #2, W0
$076A $781F80 PUSH W0
$076C $07FF2B RCALL _Lcd_Custom_Out, 0-10000015
$076E $B1006F SUB #6, W15
;Timer1_interrupt.c,90 :: }
$0770 $ L_main_6:
;Timer1_interrupt.c,82 :: for (i=0;i<=65535;i++)
$0770 $200011 MOV #1, W1
$0772 $47006A ADD W14, #10, W0
$0774 $408810 ADD W1, [W0], [W0]
;Timer1_interrupt.c,90 :: }
$0776 $04070A GOTO L_main_4
$077A $ L_main_5:
$077A $040706 GOTO L_main_2
;Timer1_interrupt.c,91 :: }
$077E $ L_end__main:
$077E $FA8000 ULNK
$0780 $37FFFF BRA $
$8000 $FF0000 TBLWT+* DATA
$8002 $FFFF00 TBLWT+* DATA


I have attached the most of the ASM code to show u that if u create your own interrupts you don't get wasted MPU cicles cause of the PUSH and PULL

Best regards
Mitroi Nicolae

idakota
Posts: 334
Joined: 27 Sep 2006 08:07
Location: Pretoria/South Africa
Contact:

#6 Post by idakota » 20 Aug 2008 20:45

SmartShadow wrote:I think u are wrong idakota.
Just wondering, what was I wrong with?

Daniel Wee
Posts: 38
Joined: 14 Jun 2007 22:05

#7 Post by Daniel Wee » 12 Feb 2009 20:34

SmartShadow, your example shows that the compiler is still generating unnecessary pushes. Just take the C1I function for example. The vector at 0x16 has a GOTO _C1I but if you look at the _C1I, you can see that it starts with:-

$013A $ _C2I:
$013A $F80036 PUSH RCOUNT
$013C $781F80 PUSH W0
$013E $200020 MOV #2, W0
$0140 $09000C REPEAT #12
$0142 $781FB0 PUSH [W0++]

You see that "REPEAT #12" bit there? That's unnecessary because your function only uses W0. So I'm afraid you are mistaken about the compiler optimization in this regard - there is none here.

Daniel

Post Reply

Return to “mikroC for dsPIC30/33 and PIC24 Wish List”