hanhthien184
10-05-2008, 07:35 PM
Em sử dụng dsPIC33FJ256GP710 cấu hình hoạt động ở 40MIPS.
Hàm phục vụ ngắt (ngắt ngoài INT4) của em như sau:
void interrupt_int4() org 0x80 { //When ADS is asserted
addr_select = PORTA;
addr_select &= 0x3F;
if (addr_select == 0)
{
LATD = ADC_1; //ADC_1
LATFbits.LATF0 = 0; //LRDYi active
LATFbits.LATF0 = 1; //LRDYi inative
}
else if (addr_select == 2)
{
LATD = ADC_2; //ADC_2
LATFbits.LATF0 = 0; //LRDYi active
LATFbits.LATF0 = 1; //LRDYi inative
}
else
{
LATD = addr_select;
LATFbits.LATF0 = 0; //LRDYi active
LATFbits.LATF0 = 1; //LRDYi inative
}
IFS3bits.INT4IF = 0; //ensure interrupt not pending
}
Yêu cầu của trình phục vụ ngắt này phải thực hiện trong thời gian rất ngắn (khoảng 0.5us).
Tuy nhiên khi viết chương trình với C (MikroC) thì nó tự động push tất cả các thanh ghi làm việc nên mất khá nhiều chu kỳ lệnh:
View assembly của chương trình trên ta thấy:
$0200 $ _interrupt_int4:
$0200 $F80036 PUSH RCOUNT
$0202 $781F80 PUSH W0
$0204 $200020 MOV #2, W0
$0206 $09000C REPEAT #12
$0208 $781FB0 PUSH [W0++]
;INT_TEST.c,15 :: void interrupt_int4() org 0x80 { //When ADS is asserted
;INT_TEST.c,16 :: addr_select = PORTA;
$020A $801610 MOV PORTA, W0
$020C $8A2000 MOV W0, _addr_select
;INT_TEST.c,17 :: addr_select &= 0x3F;
$020E $2003F1 MOV #63, W1
$0210 $244000 MOV #@_addr_select, W0
$0212 $608090 AND W1, [W0], W1
$0214 $8A2001 MOV W1, _addr_select
;INT_TEST.c,18 :: if (addr_select == 0)
$0216 $508060 SUB W1, #0, W0
$0218 $3A000A BRA NZ L_interrupt_int4_0, L_interrupt_int4_0
;INT_TEST.c,20 :: LATD = ADC_1; //ADC_1
$021A $822010 MOV _ADC_1, W0
$021C $8816B0 MOV W0, LATD
;INT_TEST.c,21 :: LATFbits.LATF0 = 0; //LRDYi active
$021E $2FFFE1 MOV #65534, W1
$0220 $202E20 MOV #@LATFbits+0, W0
$0222 $608810 AND W1, [W0], [W0]
;INT_TEST.c,22 :: LATFbits.LATF0 = 1; //LRDYi inative
$0224 $200011 MOV #1, W1
$0226 $202E20 MOV #@LATFbits+0, W0
$0228 $708810 IOR W1, [W0], [W0]
;INT_TEST.c,23 :: }
$022A $040258 GOTO L_interrupt_int4_1
$022E $ L_interrupt_int4_0:
;INT_TEST.c,24 :: else if (addr_select == 2)
$022E $822001 MOV _addr_select, W1
$0230 $508062 SUB W1, #2, W0
$0232 $3A000A BRA NZ L_interrupt_int4_2, L_interrupt_int4_2
;INT_TEST.c,26 :: LATD = ADC_2; //ADC_2
$0234 $822020 MOV _ADC_2, W0
$0236 $8816B0 MOV W0, LATD
;INT_TEST.c,27 :: LATFbits.LATF0 = 0; //LRDYi active
$0238 $2FFFE1 MOV #65534, W1
$023A $202E20 MOV #@LATFbits+0, W0
$023C $608810 AND W1, [W0], [W0]
;INT_TEST.c,28 :: LATFbits.LATF0 = 1; //LRDYi inative
$023E $200011 MOV #1, W1
$0240 $202E20 MOV #@LATFbits+0, W0
$0242 $708810 IOR W1, [W0], [W0]
;INT_TEST.c,29 :: }
$0244 $040258 GOTO L_interrupt_int4_3
$0248 $ L_interrupt_int4_2:
;INT_TEST.c,32 :: LATD = addr_select;
$0248 $822000 MOV _addr_select, W0
$024A $8816B0 MOV W0, LATD
;INT_TEST.c,33 :: LATFbits.LATF0 = 0; //LRDYi active
$024C $2FFFE1 MOV #65534, W1
$024E $202E20 MOV #@LATFbits+0, W0
$0250 $608810 AND W1, [W0], [W0]
;INT_TEST.c,34 :: LATFbits.LATF0 = 1; //LRDYi inative
$0252 $200011 MOV #1, W1
$0254 $202E20 MOV #@LATFbits+0, W0
$0256 $708810 IOR W1, [W0], [W0]
;INT_TEST.c,35 :: }
$0258 $ L_interrupt_int4_3:
$0258 $ L_interrupt_int4_1:
;INT_TEST.c,36 :: IFS3bits.INT4IF = 0; //ensure interrupt not pending
$0258 $2FFBF1 MOV #65471, W1
$025A $2008A0 MOV #@IFS3bits+0, W0
$025C $608810 AND W1, [W0], [W0]
;INT_TEST.c,37 :: }
$025E $ L_end__interrupt_int4:
$025E $2001A0 MOV #26, W0
$0260 $09000C REPEAT #12
$0262 $78104F POP [W0--]
$0264 $78004F POP W0
$0266 $F90036 POP RCOUNT
$0268 $064000 RETFIE
?Có cách nào cải thiện được tốc độ của ngắt (có thể không push các thanh ghi không cần thiết trong trình phục vụ ngắt)bằng MikroC là tốt nhất (hoặc chuyển sang C30 cũng được)
vì chương trình của em rất lớn nên nếu chuyển tất cả sang ASM thì không đủ thời gian thực hiện.
=>Các bác nào có hướng giải quyết nào hay giúp em với.
Hàm phục vụ ngắt (ngắt ngoài INT4) của em như sau:
void interrupt_int4() org 0x80 { //When ADS is asserted
addr_select = PORTA;
addr_select &= 0x3F;
if (addr_select == 0)
{
LATD = ADC_1; //ADC_1
LATFbits.LATF0 = 0; //LRDYi active
LATFbits.LATF0 = 1; //LRDYi inative
}
else if (addr_select == 2)
{
LATD = ADC_2; //ADC_2
LATFbits.LATF0 = 0; //LRDYi active
LATFbits.LATF0 = 1; //LRDYi inative
}
else
{
LATD = addr_select;
LATFbits.LATF0 = 0; //LRDYi active
LATFbits.LATF0 = 1; //LRDYi inative
}
IFS3bits.INT4IF = 0; //ensure interrupt not pending
}
Yêu cầu của trình phục vụ ngắt này phải thực hiện trong thời gian rất ngắn (khoảng 0.5us).
Tuy nhiên khi viết chương trình với C (MikroC) thì nó tự động push tất cả các thanh ghi làm việc nên mất khá nhiều chu kỳ lệnh:
View assembly của chương trình trên ta thấy:
$0200 $ _interrupt_int4:
$0200 $F80036 PUSH RCOUNT
$0202 $781F80 PUSH W0
$0204 $200020 MOV #2, W0
$0206 $09000C REPEAT #12
$0208 $781FB0 PUSH [W0++]
;INT_TEST.c,15 :: void interrupt_int4() org 0x80 { //When ADS is asserted
;INT_TEST.c,16 :: addr_select = PORTA;
$020A $801610 MOV PORTA, W0
$020C $8A2000 MOV W0, _addr_select
;INT_TEST.c,17 :: addr_select &= 0x3F;
$020E $2003F1 MOV #63, W1
$0210 $244000 MOV #@_addr_select, W0
$0212 $608090 AND W1, [W0], W1
$0214 $8A2001 MOV W1, _addr_select
;INT_TEST.c,18 :: if (addr_select == 0)
$0216 $508060 SUB W1, #0, W0
$0218 $3A000A BRA NZ L_interrupt_int4_0, L_interrupt_int4_0
;INT_TEST.c,20 :: LATD = ADC_1; //ADC_1
$021A $822010 MOV _ADC_1, W0
$021C $8816B0 MOV W0, LATD
;INT_TEST.c,21 :: LATFbits.LATF0 = 0; //LRDYi active
$021E $2FFFE1 MOV #65534, W1
$0220 $202E20 MOV #@LATFbits+0, W0
$0222 $608810 AND W1, [W0], [W0]
;INT_TEST.c,22 :: LATFbits.LATF0 = 1; //LRDYi inative
$0224 $200011 MOV #1, W1
$0226 $202E20 MOV #@LATFbits+0, W0
$0228 $708810 IOR W1, [W0], [W0]
;INT_TEST.c,23 :: }
$022A $040258 GOTO L_interrupt_int4_1
$022E $ L_interrupt_int4_0:
;INT_TEST.c,24 :: else if (addr_select == 2)
$022E $822001 MOV _addr_select, W1
$0230 $508062 SUB W1, #2, W0
$0232 $3A000A BRA NZ L_interrupt_int4_2, L_interrupt_int4_2
;INT_TEST.c,26 :: LATD = ADC_2; //ADC_2
$0234 $822020 MOV _ADC_2, W0
$0236 $8816B0 MOV W0, LATD
;INT_TEST.c,27 :: LATFbits.LATF0 = 0; //LRDYi active
$0238 $2FFFE1 MOV #65534, W1
$023A $202E20 MOV #@LATFbits+0, W0
$023C $608810 AND W1, [W0], [W0]
;INT_TEST.c,28 :: LATFbits.LATF0 = 1; //LRDYi inative
$023E $200011 MOV #1, W1
$0240 $202E20 MOV #@LATFbits+0, W0
$0242 $708810 IOR W1, [W0], [W0]
;INT_TEST.c,29 :: }
$0244 $040258 GOTO L_interrupt_int4_3
$0248 $ L_interrupt_int4_2:
;INT_TEST.c,32 :: LATD = addr_select;
$0248 $822000 MOV _addr_select, W0
$024A $8816B0 MOV W0, LATD
;INT_TEST.c,33 :: LATFbits.LATF0 = 0; //LRDYi active
$024C $2FFFE1 MOV #65534, W1
$024E $202E20 MOV #@LATFbits+0, W0
$0250 $608810 AND W1, [W0], [W0]
;INT_TEST.c,34 :: LATFbits.LATF0 = 1; //LRDYi inative
$0252 $200011 MOV #1, W1
$0254 $202E20 MOV #@LATFbits+0, W0
$0256 $708810 IOR W1, [W0], [W0]
;INT_TEST.c,35 :: }
$0258 $ L_interrupt_int4_3:
$0258 $ L_interrupt_int4_1:
;INT_TEST.c,36 :: IFS3bits.INT4IF = 0; //ensure interrupt not pending
$0258 $2FFBF1 MOV #65471, W1
$025A $2008A0 MOV #@IFS3bits+0, W0
$025C $608810 AND W1, [W0], [W0]
;INT_TEST.c,37 :: }
$025E $ L_end__interrupt_int4:
$025E $2001A0 MOV #26, W0
$0260 $09000C REPEAT #12
$0262 $78104F POP [W0--]
$0264 $78004F POP W0
$0266 $F90036 POP RCOUNT
$0268 $064000 RETFIE
?Có cách nào cải thiện được tốc độ của ngắt (có thể không push các thanh ghi không cần thiết trong trình phục vụ ngắt)bằng MikroC là tốt nhất (hoặc chuyển sang C30 cũng được)
vì chương trình của em rất lớn nên nếu chuyển tất cả sang ASM thì không đủ thời gian thực hiện.
=>Các bác nào có hướng giải quyết nào hay giúp em với.