Ich habe ein Problem mit sehr schlechter Leistung in meinem PIC32-Code. Zum Beispiel habe ich diese ISR, die einige verschiedene Interrupt-Quellen bedient:
volatile int rxEvents = 0;
volatile int txEvents = 0;
volatile int int1Events = 0;
volatile int events = 0;
volatile bool spi_read_flag = 0;
volatile bool spi_write_flag = 0;
volatile bool spi_int_flag = 0;
volatile bool adc_ready = 0;
void __attribute__((__interrupt__)) _DefaultInterrupt(){
PIN(TIMER, LAT, LAT) = 1; // turn on an IO pin
if(IFS0bits.T1IF){
IFS0bits.T1IF = 0;
AD1CON1bits.ASAM = 1; // begin sampling
}
if(IFS1bits.AD1IF){
IFS1bits.AD1IF = 0;
adc_ready = true;
}
++events;
if(IFS1bits.SPI2RXIF){
++rxEvents;
IFS1bits.SPI2RXIF = 0;
spi_read_flag = 1;
}
if(IFS1bits.SPI2TXIF){
++txEvents;
IFS1bits.SPI2TXIF = 0;
spi_write_flag = 1;
}
if(IFS0bits.INT1IF){
++int1Events;
IFS0bits.INT1IF = 0;
spi_int_flag = 1;
}
PIN(TIMER, LAT, LAT) = 0; // turn off the IO pin
}
Wie Sie sehen können, überprüft und löscht es einfach Flag-Bits und setzt einige boolesche Flags / führt einige andere einfache Aktionen aus.
Beim Scoping des IO-Pins habe ich festgestellt, dass diese ISR in einigen Fällen bis zu 100 us dauern kann, was bei meiner Taktrate von 8 MHz bedeuten würde, dass 800 Anweisungen erforderlich sind, was verrückt erscheint. Ein Screenshot des Timings des IO-Pins ist unten zu sehen.
Meine Frage ist, was verursacht diese schlechte Leistung? Gibt es eine Uhreinstellung, die ich vermisse? Ich habe überprüft, dass der SPI-Takt bei 500 kHz läuft, wie erwartet mit einer Vorskalierung von 8 und einem Systemtakt von 8 MHz. Unten ist die vollständige Konfiguration, die ich verwende:
// DEVCFG3
// USERID = No Setting
// DEVCFG2
#pragma config FPLLIDIV = DIV_12 // PLL Input Divider (12x Divider)
#pragma config FPLLMUL = MUL_24 // PLL Multiplier (24x Multiplier)
#pragma config UPLLIDIV = DIV_12 // USB PLL Input Divider (12x Divider)
#pragma config UPLLEN = OFF // USB PLL Enable (Disabled and Bypassed)
#pragma config FPLLODIV = DIV_256 // System PLL Output Clock Divider (PLL Divide by 256)
// DEVCFG1
#pragma config FNOSC = FRC // Oscillator Selection Bits (Fast RC Osc (FRC))
#pragma config FSOSCEN = ON // Secondary Oscillator Enable (Enabled)
#pragma config IESO = ON // Internal/External Switch Over (Enabled)
#pragma config POSCMOD = OFF // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = ON // CLKO Output Signal Active on the OSCO Pin (Enabled)
#pragma config FPBDIV = DIV_8 // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/8)
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576 // Watchdog Timer Postscaler (1:1048576)
#pragma config FWDTEN = ON // Watchdog Timer Enable (WDT Enabled)
// DEVCFG0
#pragma config DEBUG = OFF // Background Debugger Enable (Debugger is disabled)
#pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select (ICE EMUC2/EMUD2 pins shared with PGC2/PGD2)
#pragma config PWP = OFF // Program Flash Write Protect (Disable)
#pragma config BWP = OFF // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF // Code Protect (Protection Disabled)
Hier ist die vollständige Disassemblierung, insgesamt 121 Anweisungen. Ich würde denken, dass dies eine Ausführungszeit im schlimmsten Fall von etwa 15 us bedeuten sollte (es sei denn, ich vermisse einige schwerwiegende Strafen im Zusammenhang mit dem Speicherzugriff?):
17: void __attribute__((__interrupt__)) _DefaultInterrupt(){
9D003854 415DE800 RDPGPR SP, SP
9D003858 401B7000 MFC0 K1, EPC
9D00385C 401A6002 MFC0 K0, SRSCtl
9D003860 27BDFFE0 ADDIU SP, SP, -32
9D003864 AFBB001C SW K1, 28(SP)
9D003868 401B6000 MFC0 K1, Status
9D00386C AFBA0018 SW K0, 24(SP)
9D003870 401A6800 MFC0 K0, Cause
9D003874 AFBB0014 SW K1, 20(SP)
9D003878 001AD282 SRL K0, K0, 10
9D00387C 7F5B7A84 INS K1, K0, 10, 6
9D003880 7C1B2044 INS K1, ZERO, 1, 4
9D003884 409B6000 MTC0 K1, Status
9D003888 AFA30004 SW V1, 4(SP)
9D00388C AFA20000 SW V0, 0(SP)
9D003890 8FA30018 LW V1, 24(SP)
9D003894 3063000F ANDI V1, V1, 15
9D003898 14600003 BNE V1, ZERO, 0x9D0038A8
9D00389C 00000000 NOP
9D0038A0 AFBE000C SW S8, 12(SP)
9D0038A4 AFA40008 SW A0, 8(SP)
9D0038A8 03A0F021 ADDU S8, SP, ZERO
18: PIN(TIMER, LAT, LAT) = 1; // indicate sampling started
9D0038AC 3C03BF88 LUI V1, -16504
9D0038B0 8C626160 LW V0, 24928(V1)
9D0038B4 24040001 ADDIU A0, ZERO, 1
9D0038B8 7C820844 INS V0, A0, 1, 1
9D0038BC AC626160 SW V0, 24928(V1)
19: if(IFS0bits.T1IF){
9D0038C0 3C02BF88 LUI V0, -16504
9D0038C4 8C421030 LW V0, 4144(V0)
9D0038C8 30420010 ANDI V0, V0, 16
9D0038CC 1040000A BEQ V0, ZERO, 0x9D0038F8
9D0038D0 00000000 NOP
20: IFS0bits.T1IF = 0;
9D0038D4 3C03BF88 LUI V1, -16504
9D0038D8 8C621030 LW V0, 4144(V1)
9D0038DC 7C022104 INS V0, ZERO, 4, 1
9D0038E0 AC621030 SW V0, 4144(V1)
21: AD1CON1bits.ASAM = 1; // begin sampling
9D0038E4 3C03BF81 LUI V1, -16511
9D0038E8 8C629000 LW V0, -28672(V1)
9D0038EC 24040001 ADDIU A0, ZERO, 1
9D0038F0 7C821084 INS V0, A0, 2, 1
9D0038F4 AC629000 SW V0, -28672(V1)
22: }
23: if(IFS1bits.AD1IF){
9D0038F8 3C02BF88 LUI V0, -16504
9D0038FC 8C421040 LW V0, 4160(V0)
9D003900 30420002 ANDI V0, V0, 2
9D003904 10400007 BEQ V0, ZERO, 0x9D003924
9D003908 00000000 NOP
24: IFS1bits.AD1IF = 0;
9D00390C 3C03BF88 LUI V1, -16504
9D003910 8C621040 LW V0, 4160(V1)
9D003914 7C020844 INS V0, ZERO, 1, 1
9D003918 AC621040 SW V0, 4160(V1)
25: adc_ready = true;
9D00391C 24020001 ADDIU V0, ZERO, 1
9D003920 A3828023 SB V0, -32733(GP)
26: }
27:
28: ++events;
9D003924 8F82801C LW V0, -32740(GP)
9D003928 24420001 ADDIU V0, V0, 1
9D00392C AF82801C SW V0, -32740(GP)
29: if(IFS1bits.SPI2RXIF){
9D003930 3C02BF88 LUI V0, -16504
9D003934 8C421040 LW V0, 4160(V0)
9D003938 30420080 ANDI V0, V0, 128
9D00393C 1040000A BEQ V0, ZERO, 0x9D003968
9D003940 00000000 NOP
30: ++rxEvents;
9D003944 8F828010 LW V0, -32752(GP)
9D003948 24420001 ADDIU V0, V0, 1
9D00394C AF828010 SW V0, -32752(GP)
31: IFS1bits.SPI2RXIF = 0;
9D003950 3C03BF88 LUI V1, -16504
9D003954 8C621040 LW V0, 4160(V1)
9D003958 7C0239C4 INS V0, ZERO, 7, 1
9D00395C AC621040 SW V0, 4160(V1)
32: spi_read_flag = 1;
9D003960 24020001 ADDIU V0, ZERO, 1
9D003964 A3828020 SB V0, -32736(GP)
33: }
34: if(IFS1bits.SPI2TXIF){
9D003968 3C02BF88 LUI V0, -16504
9D00396C 8C421040 LW V0, 4160(V0)
9D003970 30420040 ANDI V0, V0, 64
9D003974 1040000A BEQ V0, ZERO, 0x9D0039A0
9D003978 00000000 NOP
35: ++txEvents;
9D00397C 8F828014 LW V0, -32748(GP)
9D003980 24420001 ADDIU V0, V0, 1
9D003984 AF828014 SW V0, -32748(GP)
36: IFS1bits.SPI2TXIF = 0;
9D003988 3C03BF88 LUI V1, -16504
9D00398C 8C621040 LW V0, 4160(V1)
9D003990 7C023184 INS V0, ZERO, 6, 1
9D003994 AC621040 SW V0, 4160(V1)
37: spi_write_flag = 1;
9D003998 24020001 ADDIU V0, ZERO, 1
9D00399C A3828021 SB V0, -32735(GP)
38: }
39: if(IFS0bits.INT1IF){
9D0039A0 3C02BF88 LUI V0, -16504
9D0039A4 8C421030 LW V0, 4144(V0)
9D0039A8 30420080 ANDI V0, V0, 128
9D0039AC 1040000A BEQ V0, ZERO, 0x9D0039D8
9D0039B0 00000000 NOP
40: ++int1Events;
9D0039B4 8F828018 LW V0, -32744(GP)
9D0039B8 24420001 ADDIU V0, V0, 1
9D0039BC AF828018 SW V0, -32744(GP)
41: IFS0bits.INT1IF = 0;
9D0039C0 3C03BF88 LUI V1, -16504
9D0039C4 8C621030 LW V0, 4144(V1)
9D0039C8 7C0239C4 INS V0, ZERO, 7, 1
9D0039CC AC621030 SW V0, 4144(V1)
42: spi_int_flag = 1;
9D0039D0 24020001 ADDIU V0, ZERO, 1
9D0039D4 A3828022 SB V0, -32734(GP)
43: }
44: PIN(TIMER, LAT, LAT) = 0; // indicate sampling started
9D0039D8 3C03BF88 LUI V1, -16504
9D0039DC 8C626160 LW V0, 24928(V1)
9D0039E0 7C020844 INS V0, ZERO, 1, 1
9D0039E4 AC626160 SW V0, 24928(V1)
45: }
9D0039E8 03C0E821 ADDU SP, S8, ZERO
9D0039EC 8FA20018 LW V0, 24(SP)
9D0039F0 3042000F ANDI V0, V0, 15
9D0039F4 14400005 BNE V0, ZERO, 0x9D003A0C
9D0039F8 00000000 NOP
9D0039FC 8FBE000C LW S8, 12(SP)
9D003A00 8FA40008 LW A0, 8(SP)
9D003A04 8FA30004 LW V1, 4(SP)
9D003A08 8FA20000 LW V0, 0(SP)
9D003A0C 41606000 DI ZERO
9D003A10 000000C0 EHB
9D003A14 8FBA001C LW K0, 28(SP)
9D003A18 8FBB0014 LW K1, 20(SP)
9D003A1C 409A7000 MTC0 K0, EPC
9D003A20 8FBA0018 LW K0, 24(SP)
9D003A24 27BD0020 ADDIU SP, SP, 32
9D003A28 409A6002 MTC0 K0, SRSCtl
9D003A2C 41DDE800 WRPGPR SP, SP
9D003A30 409B6000 MTC0 K1, Status
9D003A34 42000018 ERET
Vollständige Befehlszeile ist hier (Pfade gekürzt, aber ansonsten unverändert)
"...\xc32-gcc.exe" -g -x c -c -mprocessor=32MX440F256H -MMD -MF blep_asynch.o.d -o blep_asynch.o blep_asynch.c
"...\xc32-gcc.exe" -g -x c -c -mprocessor=32MX440F256H -MMD -MF interrupt.o.d -o interrupt.o interrupt.c
"...\xc32-gcc.exe" -g -x c -c -mprocessor=32MX440F256H -MMD -MF data_handler.o.d -o data_handler.o data_handler.c
"...\xc32-gcc.exe" -g -x c -c -mprocessor=32MX440F256H -MMD -MF timer.o.d -o timer.o timer.c
"...\xc32-gcc.exe" -g -x c -c -mprocessor=32MX440F256H -MMD -MF acilib.o.d -o acilib.o acilib.c
"...\xc32-gcc.exe" -g -x c -c -mprocessor=32MX440F256H -MMD -MF adc.o.d -o adc.o adc.c
"...\xc32-gcc.exe" -g -x c -c -mprocessor=32MX440F256H -MMD -MF blep.o.d -o blep.o blep.c
"...\xc32-gcc.exe" -mprocessor=32MX440F256H -o project.production.elf main.o bit_order.o acilib.o blep.o adc.o timer.o interrupt.o blep_asynch.o aci_asynch.o data_handler.o -Wl,--defsym=__MPLAB_BUILD=1,--defsym=_min_heap_size=128,-Map="project.production.map"
Die PIC32-Default-Konfiguration ist hinsichtlich Performance schlecht. Einer der Stickies im PIC32-Forum auf der Website von Microchip spricht Folgendes an:
Wenn Sie PIC32 starten, unabhängig von den Oszillatorsicherungseinstellungen, die Sie angegeben haben, beginnt es mit
NEIN Caching eingeschaltet
NEIN Prefetch-Puffer aktiviert
7 FLASH-Wartezustände
1 SRAM-Wartezustände
Alle diese Elemente wirken sich auf die Leistung Ihres Codes aus und führen dazu, dass er erheblich langsamer ausgeführt wird, als Sie erwarten würden. Geben Sie also in der Regel in der allerersten Zeile Ihrer Hauptfunktion Folgendes ein:
SYSTEMConfigPerformance(80000000);
wobei die Zahl in Klammern Ihre gewählte endgültige Anweisungstaktrate ist. Diese Funktion richtet die Leistungsmerkmale des PIC32 mit der richtigen Anzahl von FLASH- und RAM-Wartezuständen für die gewählte Geschwindigkeit korrekt ein und aktiviert auch Caching und Prefetch. Richten Sie dies zuerst ein und sehen Sie, welche Geschwindigkeit Sie erhalten. Sie sollten es viel schneller finden. Sie müssen dann an den Optimierungseinstellungen des Compilers herumbasteln, um die Leistung noch weiter zu verbessern.
Versuchen Sie, die Konfigurationsleistungsroutine auszuführen, und prüfen Sie, ob sie hilft.
Dies ist keine Antwort, sondern ein Debug-Pfad. Die PIC32 haben eine ganze Reihe von Taktoptionen, und IIRC, wenn die, nach denen Sie fragen, Probleme verursachen, werden die Uhren ihr Bestes tun, um einen Weg zu finden, der funktioniert.
Der erste Schritt für mich in Fällen wie diesem besteht darin, meine Systemuhren zu überprüfen, indem ich meinen gesamten Code außer einfachen Konfigurationen loswerde, einen schmutzigen, einfachen Timer-Interrupt einprogrammiere, der nichts anderes tut, als ein bisschen umzuschalten, und sicherzustellen, dass das, was ich sehe, Sinn macht. Wenn dies der Fall ist, füge ich Code hinzu, und wenn dies nicht der Fall ist, wird mein Problem normalerweise identifiziert.
Ich persönlich mache so etwas immer, wenn ich ein Projekt starte, normalerweise bevor Probleme auftreten. Es ist eine gute Angewohnheit, sich darauf einzulassen.
Deine FPLLIDIV scheint viel zu hoch zu sein. Die Dokumentation besagt, dass der PLL-Eingang zwischen 4 und 5 MHz liegen sollte. Mit dem 8-MHz-RC-Takt sollte die FPLLIDIV 2 sein.
Mit einem Eingangsteiler von 12, einem PLL-Multiplikator von 24 und einem Ausgangsteiler von 256 erhalten Sie einen Gesamtteiler von 128 - Ihre endgültige Taktrate scheint 8 MHz DIV 128 zu sein.
Und Sie fügen auch einen peripheren Teiler von 8 hinzu - Ihre PIN-Taktrate scheint 8 kHz zu sein.
Dies sind meine Einstellungen mit dem internen schnellen RC-Oszillator. Ich bin mir nicht sicher, ob alle Artikel auf den besten Wert eingestellt sind. Aber es funktioniert vernünftig:
#pragma config FPLLIDIV = DIV_2 // PLL Input Divider (2x Divider)
#pragma config FPLLMUL = MUL_16 // PLL Multiplier (20x Multiplier)
#pragma config FPLLODIV = DIV_1 // System PLL Output Clock Divider (PLL Divide by 1)
#pragma config FWDTEN = OFF
#pragma config FNOSC = FRCPLL // Oscillator Selection Bits (Fast RC Osc with PLL)
#pragma config FSOSCEN = OFF // Secondary Oscillator Enable (Disabled)
#pragma config IESO = OFF // Internal/External Switch Over (Disabled)
#pragma config POSCMOD = OFF // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_1 // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
Matt Jung
Tut
Gordon Bailey
Gordon Bailey
Majenko
Gordon Bailey
Majenko
brhans
Gordon Bailey
Gordon Bailey
justieren
Gordon Bailey
justieren
Gordon Bailey
David
else if
um Zyklen zu sparen.justieren