Hjälp med att tajma rutiner i PIC/MPLAB?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
AndersG
EF Sponsor
Inlägg: 9127
Blev medlem: 25 februari 2008, 17:10:58
Ort: Mariehamn
Kontakt:

Inlägg av AndersG »

OK. Med allt jag sist och slutligen behövde i min ISR fick jag problem att hinna med. Inet ens med 8MHz klocka. Försökte då sätta PortA för Interrupt on change och läsa pulserna med bit 0 och riktning i bit 1. Nackdelen är då att jag får dubbla antalet pulser (en puls innebär två nivåförändringar). Testade då:

Kod: Markera allt

	BTFSS 	INTCON, RABIF 	; Was the cause PortAB interrupt?
	GOTO 	other_int 		; no, check ther interrupt

	MOVF 	PORTA, W 		; Port A change caused interrupt.Read PortA into flag register
	movwf	flags
	btfss	flags,0			; Counter input high?
	goto	cnt_end	
Nackdelen är då att det inte alls är säkert att portA har samma värde då jag läser den som då den triggade interrupten...

Men, eg vore det väl enklare att köra in pulserna på RA2/INT som ju triggar på valbar flank. Testade det och då gär det mycket bättre. Klarar av att räkna upp till 15-20kHz. Testade mot en HP pulsräknare.

En intressant sak upptäckte jag dock: Om jag drar upp frekvensen mycket över detta så tappar jag pulser, men, precis i området före så kommer koden att räkna flera pulser än räknaren. Kan någon förklara detta?
Bettendet är även symmetriskt, dvs både vid upp och nedräkning.

Kod: Markera allt

INTERRUPT
;
; Arrive here on any interrupt - first save the world...
; 
	movwf   w_temp            ; save off current W register contents
	movf    STATUS,w          ; move status register into W register
	movwf   status_temp       ; save off contents of STATUS register
	movf    PCLATH,w          ; move pclath register into W register
	movwf   pclath_temp       ; save off contents of PCLATH register
	movf    FSR,w          	; move fsr register into W register
	movwf   fsr_temp       	; save off contents of PCLATH register

; Actual isr code, determine cause of interrupt. Most likely first

	btfss	intcon, intf	; Was the cause an external interrupt? (RA2)
	goto	check_rabif		; no, check if cause is PortAB interrupt on change?
							; Yes, pulse arrived on RA2
	banksel	cntr
	movlw	cntr			; Put counter in W
	btfss	flags,1			; Bit 1 of flags indicate up/down
	goto	cnt_up
	call	dec32z			; Decrement
	goto	cnt_end
cnt_up
;
; Code that skips every nth pulse to account for battery efficiency
;
	banksel	effcounter
	movf	effcounter,F	; If zero, then skip efficiency adjustment
	btfss	status,z
	goto	cnt_up2
	decfsz	effcounter,1	; Decrement efficiency counter
	goto	cnt_up2			; and if not zero, then we increment
							; if we have counted down, then we prime the register again
							; net result is that every nth pulse is skipped. E = 1 - 1/n
							; Ie 2 =50%, 3 = 66%, 4 = 75%, 5 = 80%, 6 = 83%, 7 = 86%, 8 = 88%, 9 = 89%, 10 = 90%
							; 255 = 99.6%
	movf	effcounter_init,0
	movwf	effcounter
	goto	cnt_end	

cnt_up2;
	banksel	cntr
	call	inc32z			; Increment
cnt_end	
	bcf		intcon,intf		; Clear external interrupt flag
	goto	exit_interrupt
;
check_rabif
	BTFSS 	INTCON, RABIF 	; Was the cause PortAB interrupt?
	GOTO 	other_int 		; no, check ther interrupt

	MOVF 	PORTA, W 		; Port A change caused interrupt.Read PortA into flag register
	movwf	flags
	BCF 	INTCON, RABIF 	; Clear the RAB interrupt flag.
	goto	exit_interrupt
;
; This is the handler for other interrupts, ie timer1
;
other_int
	banksel	PIR1
	btfss   PIR1,TMR1IF     ; If Timer 1 overflowed and caused the interrupt, handle it.
	goto	other_int1		; No timer overflow
	banksel dspcounter		; Check our loop counter if it is time to go and update stuff
	decfsz	dspcounter		; Time to go?
	goto	other_int1		; No, not yet
	bsf		prtflag,1		; Yes, set flag to indicate to main loop that we need an update
	movlw	DISPDELAY		; Prime the display delay counter
	movwf	dspcounter
other_int1

	banksel	PIR1
	BCF 	PIR1,TMR1IF 	; Clear flag and continue.
;
; Catch-all for interrupt exit. Restore the world as we know it.
;
exit_interrupt
	movf    fsr_temp,w     ; retrieve copy of FSR register
	movwf   fsr            ; restore pre-isr FSR register contents
	movf    pclath_temp,w     ; retrieve copy of PCLATH register
	movwf   PCLATH            ; restore pre-isr PCLATH register contents
	movf    status_temp,w     ; retrieve copy of STATUS register
	movwf   STATUS            ; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt

Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7487
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Inlägg av Marta »

Du har en bug vid ingång och utgång till Din ISR. Du måste använda swap även för att återställa statusregistret, annars crashar Du Z-flaggan. Om det förklarar märkligheten vet jag inte, men hur som helst är det en potentiell källa till märkliga problem.


När den räknar för många pulser antar jagatt detta innebär attDin ISR körs förmånga gånger. Detta kan troligen inträffa när det blir så tätt melln interrupts att de andra interruptkällorna inte hinner servas. Då ligger dessa kvar och den interruptar omedelbart igen så snart GIE aktiveras. Hinner det då komma en ny puls så uppfattar nog Din ISR detta som att det är en växling på ingången och räknar ett steg extra. Detta är bara en känsla jag får efter att ha tittat på koden, kan mycket väl vara en helt annan förklaring.
Användarvisningsbild
AndersG
EF Sponsor
Inlägg: 9127
Blev medlem: 25 februari 2008, 17:10:58
Ort: Mariehamn
Kontakt:

Inlägg av AndersG »

Du har en bug vid ingång och utgång till Din ISR. Du måste använda swap även för att återställa statusregistret, annars crashar Du Z-flaggan. Om det förklarar märkligheten vet jag inte, men hur som helst är det en potentiell källa till märkliga problem.
Intressant! Koden kommer direkt från Microchips kodmall, men på sid 211, exempel 14-1 så är det rätt! Skall rätta och testa.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Jag minns inte vilken krets du använder, men...

Notera att en del PIC18 kan köras upp till 32 MHz (8Mhz + 4xPLL)
utan extern kristall eller oscillator.

PIC18 har också lägre overhead vid interrupt genom att olika register
sparar automatisk utan extra instruktioner. Så om du använder en
PIC16 idag, så bör du kunna gå upp en del i frekvens genom att
byta till en (modern) PIC18.
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7487
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Inlägg av Marta »

Det hänger på hur STATUS läses. Blir det vad deär stod innan, eller hinner Z-flaggan ändras innan dess värde överförs? Kanske skiljer mellan olika processorer också. Hur som helst är det en onödig risk, det blir varken fler eller segare instruktioner av att swappa istället.


Jag har bara gjort som det står i databladens rutor och aldrig experimenterat med att utröna hur det förhåller sig. Det är ju tämligen lätt att göra ett testprogram för detta och stilla nyfikenheten. Sätt Z samt CY för att säkerställa STATUS är skilt ifrån noll, läs STATUS och se om positionen för Z är 1 eller 0.


Edit: Angående att korta koden så har PIC18 även villkorliga hopp som kan omvandla vissa skip/goto till enkelinstruktioner. Det blir då 1 eller 2 cykler istället för 2 eller 3 om jag kommer ihåg instruktionstiderna rätt.
Användarvisningsbild
AndersG
EF Sponsor
Inlägg: 9127
Blev medlem: 25 februari 2008, 17:10:58
Ort: Mariehamn
Kontakt:

Inlägg av AndersG »

16F690,eftersom den sitter in PICKIT2. Därev inte sagt att jag måste använda den. Med lösningen nu så klarar jag 15-20kHz, vilket räcker eftersom jag har 3333,33 Hz från FV omvandlaren vid fullskaleutslag.

En annan fördel med 18-serien är iofs att vissa har två 16-bitars hårdvaruräknare så jag junde ha separata för i och urladdning. Typ 16 bitar i räknaren och 16 i mjukvara = 32 bitar
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7487
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Inlägg av Marta »

Finns ju också möjligheten att applicera en liten prescaler, som då givetvis kan vara en upp-/ner-räknare och sänka frekvensen 8 eller 16 gånger. Då örssssvinner rimligtvis alla problem med att processorn halkar efter. Den kommer att behålla noggrannheten, det är bara den upplösning som processorn kan "se" som minskas och det bör rimligtvis inte ha någon betydelse.
Användarvisningsbild
AndersG
EF Sponsor
Inlägg: 9127
Blev medlem: 25 februari 2008, 17:10:58
Ort: Mariehamn
Kontakt:

Inlägg av AndersG »

Japp. Jag har redan funderat på att sätta en 40-seriens 4-bitars upp/nedräknare. Har ett par på hyllan, men nu funkar det ju med bara PICen, men som sagt var. Kan vara bra att ha alternativ.
Användarvisningsbild
AndersG
EF Sponsor
Inlägg: 9127
Blev medlem: 25 februari 2008, 17:10:58
Ort: Mariehamn
Kontakt:

Inlägg av AndersG »

Ett annat alternativ kan vara MAX1660:
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/1793

Som eg innehåller allt som behövs, inkl separata 32 bitars räknare för upp och ned som läses via SMBus.
Skriv svar