PCLATH problem med PIC16F886. Indikering?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
korp
Inlägg: 1216
Blev medlem: 30 maj 2006, 02:21:18
Ort: Strömstad

PCLATH problem med PIC16F886. Indikering?

Inlägg av korp »

Igår var allt frid och fröjd i mitt PIC16F886-baserade projekt. Jag hämtar data från en tabell som visas på en LCD. När jag lade till ytterligare en liten tabell så började det strula. Plötsligt visade sig datan som tidigare fungerade fint, som skräptecken.

Jag tror att jag för första gången har överskridit 2K-gränsen i ett projekt, där en tabell oturligt nog har hamnat på adress 0x000151 (enligt *.map-filen), vilket vad jag förstår är i en annan "page" som inte är direkt adresserbar utan att använda PCLATH. Jag försöker nu förstå mig på hur jag ska använda PCLATH för att nå den med mitt CALL...

Min största fundering är dock om det verkligen inte finns någon indikering på att detta problem uppstått? Jag märkte det ju inte förrän saker och ting började strula och därefter kollade i map-filen. Det känns otroligt bökigt att sitta och dubbelkolla map-filen efter varje omkompilering. När man kör "relocatable mode" ändras adresserna rätt friskt så fort man gör en liten ändring.

Nästa gång jag kompilerar kanske tabellen ligger under 2K och något annat hamnar över 2K. Hur ska man hantera detta utan att få gråa hår? Jag har sökt på forumet, men inte sett något bra svar, alternativt inte fattat :D

Edit: stavfel
Användarvisningsbild
korp
Inlägg: 1216
Blev medlem: 30 maj 2006, 02:21:18
Ort: Strömstad

Inlägg av korp »

Det enklaste är kanske att statiskt lägga tabellen på en viss adress, även om det känns som det går emot hela "relocatable"-tänket.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Anropet av tabellen (jag antar att det är en tabell med CALL/RETLW) kan
fixas på två sätt. Och det är igentligen två olika problem, dels att göra
CALL till en annan page, dels ifall tabellen i sig ligger på två olika
pages ("splittad").

Det första problem löses genom att alltid sätta PCLATH innan CALL
till tabellen. Kolla upp PAGESEL i MPASM manualen. Det direktivet
hjälper till att sätta PCLATH rätt föra CALL. Och det justerar sig automatisk
mellan varje "build". Väldigt enkelt:

Kod: Markera allt

pagesel CallDest
call    CallDest

Det andra problemet med en tabell splittad över två pages, kan
igentligen inte uppträda när man kör relocatable med MPLINK.
MPLINK kommer att flytta hela tabellen till en ledig page om den
inte får plats i den aktuella pagen. Så nedanstående är kanske inte
helt rellevant i ditt fall. Läs det om du vill. Eller blev den faktiskt
splittad äver två olika pages ?

1. Lägg varje tabell på en känd adress (d.v.s ge varje tabell ett egen CODE segment).
2. Justera tabell-koden så att den själv justerar PCLATH innan ADDWF PC.

Alt 1 är enklare och ger snabbare kod men kan ge större "luckor" i minnet.
Alt 2 ger utnyttjar minnet bättre, men gör att varje tabell-uppslagning tar
några instruktioner mer.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Det enklaste är kanske att statiskt lägga tabellen på en viss adress,
> även om det känns som det går emot hela "relocatable"-tänket.

Det behövs igentligen inte, om man dels skriver anropet (pagesel/call)
korrekt, dels skriver själva tabellkoden korrekt (d.v.s med justering
av PCLATH).

Application note 556 har lite mer info.
Jag har för mig att det finns ett par småfel i den, så se upp ! :-)
http://ww1.microchip.com/downloads/en/A ... 00556e.pdf
Användarvisningsbild
korp
Inlägg: 1216
Blev medlem: 30 maj 2006, 02:21:18
Ort: Strömstad

Inlägg av korp »

Åh, alldeles förträfflig hjälp! Tackar Sodjan för solklar förklaring!
PIC-programmering är verkligen beroendeframkallande. I timmar, ja ibland dagar, kan jag brottas med ett till synes simpelt problem och allt är mörkt och lite irriterat. Sen löser man det- eller får hjälp och så är man på topp igen. Självplågeri på hög nivå :)

Har du tid att utveckla detta lite? Jag tror mig förstå att man får räkna ut en offset på något vis och addera till PCLATH efter tabellens label?
2. Justera tabell-koden så att den själv justerar PCLATH innan ADDWF PC.
Edit: Ah! Sorry. Ska kolla på application note:n!
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Jag tror mig förstå att man får räkna ut en offset på något vis och
> addera till PCLATH efter tabellens label?

Tanken är ju att man lägger till ett "index" till PC, och det man gör är
att simulera detta i förväg för att se om man *kommer att* passera
en page-gräns. I så fall ökar man PCLATH med 1 i förväg innan
indexet läggs till till PC, så att man sedan hamnar på rätt page.

Som sagt, detta förklaras i den App Note som jag länkade till.
Notera sock att jag tror att det finns en bugg i koden, jag har för
mig att det går fel om man anropar den med ett index = h'00',
eller något sådant...

En helt annan sak är sedan att 16F88x familjen kan läsa (och skriva)
direkt från/till Flash, utan att gå via CALL/RETLW tabeller. Se sid 115
(kap 10.1.4) i databladet. Eller se http://www.jescab.se/HD44780.html
för lite 16F886 kod som gör just detta.
Användarvisningsbild
korp
Inlägg: 1216
Blev medlem: 30 maj 2006, 02:21:18
Ort: Strömstad

Inlägg av korp »

Med risk för att verka helt bakom flötet har jag stött på ett nytt problem i sammanhanget. För att komma runt Paging-problemet har jag skapat enkla macros för goto och call;

Kod: Markera allt

xgoto	MACRO	label		;Macro to fix the PIC paging problem with 2K Word boundary.
	pagesel	label
	goto	label
	ENDM
xcall	MACRO	label		;Macro to fix the PIC paging problem with 2K Word boundary.
	pagesel	label
	call	label
	ENDM
Ett problem som då uppstår är villkortsuttryck som t ex;

Kod: Markera allt

	banksel	PIR1
	btfsc	PIR1, TMR1IF		;Check if timer1 triggered the interrupt.
	xgoto	CHECKTIMER
	xgoto	INTERRUPT_END		;If no known interrupt triggered the event end the interrupt.
Eftersom xgoto-macrot består av flera rader så fungerar inte villkorsuttrycket som det normalt gör. Hittils har jag lyckats lösa det med att placera destinationslabel:n i samma kodsegment (code) som villkoret, men hur löser man problemet detta på bra sätt om de inte är i samma segment? Några extra labels i samma segment, och hopp därifrån till mål-label:n?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Man kan inte "skipa" över ett fler-raders macro. Du kommer
at hamna på rad 2 i macrot efter en skip.

Det finns sätt att komma runt det, genom att sätta in
extra GOTO på första och andra raden i macrot.
Det första GOTO't hoppar över det andra, och det andra hoppar
direkt till slutet av macrot.

Men enklast är att undvika "skip" instruktioner direkt innan ett macro...
Användarvisningsbild
korp
Inlägg: 1216
Blev medlem: 30 maj 2006, 02:21:18
Ort: Strömstad

Inlägg av korp »

Hmm.. Jo precis, fast även om man då ska undvika macros i samband med skips så måste man ju hantera eventualiteten att den label man vill skippa till finns i en annan page, eller? Följande borde fungera även om det blir lite extra kod.

Kod: Markera allt

;--------------------------------------------------------
YADAYADA       CODE
	banksel	PIR1
	btfsc	PIR1, TMR1IF		;Check if timer1 triggered the interrupt.
	goto	SKIPTOCHECKTIMER
	goto	SKIPTOINTERRUPT_END	;If no known interrupt triggered the event end the interrupt.
SKIPTOCHECKTIMER
        pagesel   CHECKTIMER
        goto     CHECKTIMER
SKIPTOINTERRUPT_END
        pagesel   INTERRUPT_END
        goto     INTERRUPT_END
;--------------------------------------------------------
HMMMMMM       CODE
CHECKTIMER
        ;Vad man nu vill göra här...
INTERRUPT_END
        ;Och här.. Här händer det spännande grejor...
Edit: Fixade några slarvfel i koden
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> den label man vill skippa till finns i en annan page, eller?

Om labeln och "skippen" ligger i samma CODE segment, så är det inget
problem. MPLINK splittar aldrig *ett* CODE segment över flera pages.

Olika CODE segment kan däremot läggas på valfri page, antingen
valt automatiskt av MPLINK eller genom att man själv talar om vilken
page den/de ska ligga på.

Sedan kan man logiskt samla ihop sin kod så att det inte blir
så många GOTO eller CALL över page gränser.

Notera också att MPASM stöder ett par "pseudo-instructions" som LCALL
och LGOTO ("L" står för "long") som sätter PCLATH rätt beroende på var
labeln befinner sig som man ska till. Dock inte "recomended for new
designs"... I princip är det samma sak som ett pagesel före CALL
eller GOTO.

En del gör egna macron som äver återställer PCLATH efter RETURN
med en pagesel $.

SKIP instruktioner direkt före macron är ett känt "problem" och det
går säkert att leta upp en hel del skrivet om det. Enklast är att undvika
macron direkt efter skip-instruktioner, inkl banksel (som ju genererar
två instruktioner på 4-banks modeller).

Ytterligare en metod är att alltid använda PIC18 då man behöver mer än
2 K minne, så slipper man page-ning helt... :-)
Skriv svar