Kod till denna koppling? (nybörjarfråga)

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

Japp!

Kod: Markera allt

RST   CODE     0x0 
   goto     Init 
Det löstes med denna kod. Har inte en aning varför det skulle behövas, verkar konstigt i mina ögon efter som jag har en goto på en rad, sen två rader ner så finns labeln. :?
Sedan lade jag till BANKSEL i i min subrutin ifall det skulle bli något knas med vilken bank variablarna skulle hamna i. Men tackar så mycket för hjälpen. Nu saknas bara lite grejor att prova med :D
och kanske lite mer avancerad kod.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Visst, jag missade det i hastigheten.
Man måste ha något som lägger någon kod på adress h'0000', d.v.s reset-vektorn.

För att få kod på h'0000' så måste man explicit ange den adressen eftersom
de första byten i programminnet ligger i en section (i LKR filen) som är
"protected". D.v.s att länkaren (MPLINK) inte lägger någon kod på "protected"
sectioner när man använder CODE *utan* explicit adress...

För att slippa BANKSEL (för t.ex COUNT1 och COUNT2) så kan du lägga dom
i "shared memory", d.v.s den del av RAM som är gemensam för alla
bankerna. Kolla minnesmappen i databladet. Det är de sista 16 byte'en
i alla bankerna som är gemensamma, d.v.s att de accessar samma minne
oavsett hur bank-bitarna är satta.

För att allokera variabler i "shared memory" använder du "UDATA_SHR"
istället för "UDATA". That's it. Kolla i MAP filen så ser du hur COUNT1 och
COUNT1 nu ligger på andra adresser.

Det finns ett speciellt läge då man *måste* lägga variablerna i shared memory
och det är för de variabler där man sparar "kontext" vid interrupt. D.v.s
där
man sparar undan W och STATUS registren så att de kan återställas
innan RETFIE igen. Om man skulle börja sätta om bank-bitarna så
ändras ju STATUS...
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Sodjan: Kan du förklara vad som är så "fiffigt" med CODE taggen?

Av resten framgår att det är CODE *direktivet* i MPASM som avses, eller hur !?

Right, det här handlar om skillnaden mellan det gamla föråldrade sättet
att skriva kod ("absolute mode") och det nya moderna sättet ("relocatable mode").

Det är inte bara CODE som är skillnaden, det är en hel del andra direktiv
som hör till relocatable mode, RES, UDATA_xxx, EXTERN, GLOBAL o.s.v.

En del har jag förklarat på denna sida : http://www.jescab.se/Rellocmode.html

Fördelarna är många.

- Kod som enklare kan flyttas mellan olika PIC modeller.
Anpassning till olika minnesmappar sker automatiskt via LKR filen och MPLINK.

- Kod som enklare kan återanvändas i olika projekt.
Alla variabler allokeras ju av MPLINK med hänsyn till övriga moduler.

- Ingen risk för att två variabler råkar dela adress.
Lätt gjort om man använder abs.mode och EQU...

- Länkaren kan sprida kod-segmenten runt de delar (som t.ex tabeller) som man har lagt på fasta adresser.
Genom att lägga in flera CODE (de "kostar" inget) så underlättar man för MPLINK som får flera/mindre "pusselbitar" att jobba med.
Samtidigtt får man direkt i MAP filen storleken på sina olika kodsegment och kan direkt se hur stora t.x olika subrutiner är.

- Koden kan enkelt delas upp i flera ASM filer (med separat assemblering), kallas "modules".
Eftersom assmbleringen är beroendestyrd, så kan det snabba upp det hela.

- Labels och variabler kan ha samma namn i olika moduler utan sammanblandning.
Enbart de variabler och labels som görs globala (med directivet GLOBAL) måste vara unika i projektet.

Min personliga rekomendation är att börja att skriva kod i relocatable mode
direkt. Det är inte svårare, det är bara lite annorlunda syntax och det är
mycket bättre när projektet växer. Visst, 99% är (skräp-) koden som
finns "på nätet" är i den äldra absolut mode, men det är oftast bara ett
par monuters job att fixa till det, eller helt enkelt köra den färdiga koden
i abs.mode, men skriva sin egen kod på "rätt" sätt...

De kodmallar och kodexempel som jag håller på att ta fram kommer
alla att använda relocatable mode, så klart. Jag hoppas kunna få upp
ett par exempel på hur jag har tänkt att det ska se ut inom ett par
dagar på www.jescab.se.
v-g
EF Sponsor
Inlägg: 7875
Blev medlem: 25 november 2005, 23:47:53
Ort: Kramforce

Inlägg av v-g »

TERdON:Hehe så fel det kan bli om man inte skriver EXAKT det man vill veta. CODE DIREKTIVET ska det ju vara.

sodjan:Jag tackar och bockar för svaren båda två lärde mig en del. Mina antaganden stämde alltså angående CODE DIREKTIVET

Följdfråga för att få 100% koll.
Man skriver ju tex såhär:

Kod: Markera allt

SBRDELAY CODE XxxX
Delay 
	Loop1 decfsz COUNT1,1 
	goto Loop1 
	decfsz COUNT2,1 
	goto Loop1 
	return


Namnet(SBRDELAY) är ju vad man önskar och XxxX anger man ju inte om man inte vill ha rutinen på specifik plats. Namnet kan väl fö vara samma som tex Delayrutinen man önskar göra "relocatable" (antar att det inte är riktigt rekommenderat men...)

Nåväl nu till frågan:Om jag nu inte använder Delayrutinen i mitt program, kompileras den då inte in eller hur funkar det? Skulle man kunna lägga delayrutinen i en annan assemblerfil eller krävs en module för det.

Mitt "drömscenario" vore ju att man bara isf gör en "bamsing"asmfil/module där alla rutiner ligger såsom delay/range/div/mul/osv ligger så slipper man koda dessa rutiner gång på gång utan kanske bara ändra lite efter behov.

Detta är ju isf nästan lika bra som objektorienterad programmering :)

Ledsen för allt OffT men måste veta :) Manualen till MPASM lämnar ju tyvärr inte mycket ledtrådar :?
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

Då var jag tillbaka igen med nya grejor :D
Men nu har jag avancerat lite. Jag lyckades få igång timer1 och jag tror att den gör interrupt när den overflowar. Anledningen till att jag inte vet är att jag får error. Så länge som jag bara har:

Kod: Markera allt

org 0x04
retfie
så fungerar allt. Men så fort jag lägger till minsta lilla kod här så får jag error när jag bygger. Vad kan felet bero på? Här är en kopia av koden:

Kod: Markera allt

	list      p=16F628A           ; list directive to define processor
	#include <p16F628A.inc>       ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file


	__CONFIG   _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT 


;****Variablar**** 
 UDATA
;Variablar kan läggas här.
 UDATA_SHR
COUNT1 RES 1 
COUNT2 RES 1
COUNT3 RES 1
RST   CODE     0x0 
   goto     Init

;****Interrupt****
 org 0x04
;Här ska kod finnas som ska ske vid en interrupt.
 retfie

;****Sätter Timer1**** 

 CODE
Init
 BANKSEL T1CON
 bsf T1CON,0
 clrf TMR1H
 clrf TMR1L
 BANKSEL INTCON
 bsf INTCON,7
 BANKSEL PIE1
 bsf TMR1IE,0
 BANKSEL PIR1
 bcf PIR1,0

;****Sätter portar**** 
 BANKSEL TRISA 
 movlw 0x00 ;Gör port A till output 
 movwf TRISA
 movlw 0xFF
 movwf COUNT1
 movwf COUNT2
 movlw 0x00
 movwf COUNT3
 BANKSEL PORTA 
 movlw 0x02

;****kör en xor för att byta status på lysdioden**** 

Start
 xorwf PORTA,1 

;****kör en delay och går till Start**** 

 call Delay 
 goto Start 

;****Subrutin för delay**** 

Delay 

Loop1
;BANKSEL COUNT1 , behövs ej då variablarna finns i UDATA_SHR
 decfsz COUNT1,1
 goto Loop1
;BANKSEL COUNT2
 decfsz COUNT2,1 
 goto Loop1 

 return 

 end
Koden ovan gör att bygga och köra, men så fort jag lägger till något under "org 0x04" så skiter det sig.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

v-g, det stämmer att MPASM manualen tyvärr är lite dålig att beskriva
"relocatable mode/code" på ett bra sätt. Det är insprängt överallt där det
för varje direktiv står om det är applicerbart för absolute eller relocatable
mode. Inte så där speciellt solklart...

Så snart min tid räcker till (ha !) så kommer det en liten guide för
relocatable mode bland min övrig PIC info...

När det gäller hurvida kod kommer med eller inte när man bygger, så
är jag inte helt säker. Jag *tror* att all kod i princip kommer med,
det görs alltså ingen djupare analys av om en viss label CALL'as eller
inte. Problemet är ju att assambler igentligen inte har något begrepp
omj vad en "subrutin" är, man kan lika gärna göra GOTO som CALL
till en label. Om RETURN är bara en instruktion som alla andra. Det skulle
behövas ett direktiv "SUBRUTINE" eller liknande för att på ett klart sätt
definiera vad som är subrutiner...

Det jag vet att man *kan* göra, är att t.ex lägga en massa subrutiner
i en separat ASM fil, t.ex olika delays eller liknande. Varje rutin i denna
ASM fil omsluter man med en "IFDEF <label>....ENDIF" och sedan lägger
men en "#DEFINE <label>" i sin huvud ASM fil *om* man vill använda
just den subrutinen. Det blir inte helautomatiskt. men man kan i alla
fall ha sina subrutiner i en gemensam fil och bara "kalla in" de som
man vill använda på ett rellativt enkelt sätt. För att inte göra det allt för
"plottrigt" kan naturligtsvis IFDEF/ENDIF omsluta så mycket kod med
flera subrutiner som man finner lämpligt (som hänger ihop)...

Notera att det mha RES direktivet blir helt dynamiskt vad det gäller
allokering av minnes (RAM) adresser. I abs.mode blir det ett litet
hel--ete att försöka hålla reda på de *hårdkodade* adresserna mha EQU
i alla subrutiner !!
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> men så fort jag lägger till något under "org 0x04" så skiter det sig.

Först, ORG används inte alls i relocatable mode. CODE ska användas.

OK, det här är lite lurigt... :-)

Låt oss titta på den rellevanta delen av LKR filen :

Kod: Markera allt

CODEPAGE   NAME=vectors    START=0x0      END=0x4      PROTECTED
Notera att denna CODEPAGE börjar på adress h'0000' och slutar på
adress h'0004'.

Ett kod-segment (d.v.s från ett CODE direktiv till nästa CODE direktiv)
måste ligga inom ett och samma CODEPAGE. Alltså så får man bara plats
med *en* instruktion, normalt en GOTO.

Så här kan det t.ex se ut i början av koden :

Kod: Markera allt


;****Restet****
RST   CODE    h'0000'
   goto     Init

;****Interrupt****
INT   CODE h'0004'
   goto my_isr
Sedan. någon annanstans i koden :

Kod: Markera allt

;*** my_isr ***

my_isr_seg  CODE

my_isr
   ...
   ...
   ...
   retfie
Om detta är optimalt eller inte kan man diskutera.
Om man inte gillar det kan man modifiera LKR filen, men personligen
tycker jag att det är enklast att köra med original LKR filen.
TERdON
EF Sponsor
Inlägg: 295
Blev medlem: 15 november 2006, 04:38:29
Ort: Solna/Laholm
Kontakt:

Inlägg av TERdON »

Nåväl, förvirrande. Vänta bara tills ni börjar forska, då måste ni veta vem som har sagt något innan man vet vad det betyder (vissa begrepp överlagras till och med mer än en gång inom varje forskningsområde - och nu menar jag små sådana...)
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

Jag tror att jag har missat något här, för att det verkar som om interruptet sker, men det jag har lagt där utförs inte.
Jag har kollat på PIR1 i simulatorn och den är 0x00 från början, sen efter första overflowet så blir den 0x01.
Men den resetas inte och den kod som finns i interruptet utförs ej.
Kod:

Kod: Markera allt

	list      p=16F628A           ; list directive to define processor
	#include <p16F628A.inc>       ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file


	__CONFIG   _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT 


INT   CODE 0x04
   goto my_isr 
RST   CODE     0x0 
   goto     Init
;****Variablar**** 
 UDATA
;Variablar kan läggas här. 
 UDATA_SHR
COUNT1 RES 1 
COUNT2 RES 1
COUNT3 RES 1

;****Interrupt****
; org 0x04
; incf COUNT3,1
; BANKSEL PIR1
; bcf PIR1,0
;Här ska kod finnas som ska ske vid en interrupt.
; retfie

;*** my_isr *** 
my_isr_seg  CODE 
my_isr 
 incf COUNT3,1
 BANKSEL PIR1
 bcf PIR1,0
   retfie

;****Sätter Timer1**** 

CODE
Init
 BANKSEL T1CON
 bsf T1CON,0
 clrf TMR1H
 clrf TMR1L
 BANKSEL INTCON
 bsf INTCON,7
 BANKSEL PIE1
 bsf TMR1IE,0
 BANKSEL PIR1
 bcf PIR1,0

;****Sätter portar**** 
 BANKSEL TRISA 
 movlw 0x00 ;Gör port A till output 
 movwf TRISA
 movwf COUNT3
 movlw 0xFF
 movwf COUNT1
 movwf COUNT2
 BANKSEL PORTA 
 movlw 0x02

;****kör en xor för att byta status på lysdioden**** 

Start
 xorwf PORTA,1 

;****kör en delay och går till Start**** 

 call Delay 
 goto Start 

;****Subrutin för delay**** 

Delay 

Loop1
;BANKSEL COUNT1 , behövs ej då variablarna finns i UDATA_SHR
 decfsz COUNT1,1
 goto Loop1
;BANKSEL COUNT2 , -||-
 decfsz COUNT2,1 
 goto Loop1 

 return 

 end
Lyckas jag med detta så får det bli en liten digitalklocka senare. :D 8)
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Bara ett par mindre saker...

Använd W/F istället för 1/0 som "d" ("destination") i instruktioner.

Använd de fördefinierade namnen på bitar i register istället för
t.ex bsf T1CON, 0. Bit "0" i T1CON har väl ett namn ?

> bsf TMR1IE,0

Ska väl vara "bsf PIE1, TMR1IE" !?

Sen har jag inte kollat mer...
BJ
Inlägg: 8864
Blev medlem: 11 april 2007, 08:14:53
Ort: En_stad

Inlägg av BJ »

sodjan skrev:Right, det här handlar om skillnaden mellan det gamla föråldrade sättet
att skriva kod ("absolute mode") och det nya moderna sättet ("relocatable mode").
Att använda absolut-läget behöver ju inte vara föråldrat. Det andra är säkert bra på många sätt, men om man gör program där det är mycket värden och bitar som kopieras mellan olika adresser ("variabler"), så sparar man ju lite tid på att inte behöva använda banksel varje gång. Man kan ju "planera" programmet lite så att man vet vilken bank man är i.
Men för program som inte är så stora så är det ju inte lika viktigt.
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

Jag blandade visst ihop det hela angående: bsf "PIE1, TMR1IE" :D
Men dessvärre så kvarstår alla problem. Jag har ändrat alla bitar till de rätta namnen nu. Det verkar som om programmet aldrig kommer till interruptdelen. Så här ser den ut:

Kod: Markera allt

;*** my_isr *** 
 my_isr_seg  CODE 
my_isr 
 incf COUNT3,F
 BANKSEL PIR1
 bcf PIR1,TMR1IF
 retfie
I början av programmet har jag även:

Kod: Markera allt

INT   CODE 0x04
   goto my_isr 
Flaggan till timer1 blir 1 men den resettas inte. :(
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

BJ> Man kan ju "planera" programmet lite så att man vet vilken bank man är i...

Även när man kör relocatable mode. Finns ingen fördel med den gamla
metoden i just detta avseende. För "snabba" variabler som man vill
kunna accessa utan bank-byte använder man UDATA_SHR, andra som
måste ligga i en viss bank så använder man UDATA med en parameter
för att styra dom till en viss bank, övriga där det inte spelar någon
roll alls låter man MPLINK välja bank och använder BANKSEL.

Det måste vara ganska ovanligt att man har så "tajt" kod att man
inte hinner med en BANKSEL. Och som sagt, shared memory (eller
"unbanked memory" som det också kallas) är ju till för just det.

> Men för program som inte är så stora så är det ju inte lika viktigt.

Förstår inte hur du menar. För program som *är* stora är det än
viktigare att man använder ett modernt sätt att skriva koden på,
d.v.s relocatable mode. Det finns ingen anledning att klamra sig
fast vid ett föråldrat format.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Det verkar som om programmet aldrig kommer till interruptdelen

GIE ??
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

GIE har jag satt till 1. Så jag har inte glömt global interrupten iaf. 8) *stolt*
Kanske är lika bra att jag postar om koden med de förbättringar som skett.

Kod: Markera allt

	list      p=16F628A           ; list directive to define processor
	#include <p16F628A.inc>       ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file


	__CONFIG   _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT 


INT   CODE 0x0004
   goto my_isr 
RST   CODE     0x0000
   goto     Init
;****Variablar**** 
 UDATA
;Variablar kan läggas här men använder man UDATA_SHR
;så behöver man inte tänka på vilken bank de ligger i.
 UDATA_SHR
COUNT1 RES 1 
COUNT2 RES 1
COUNT3 RES 1

;*** my_isr *** 
 my_isr_seg  CODE
my_isr 
 incf COUNT3,F
 BANKSEL PIR1
 bcf PIR1,TMR1IF
 retfie

;****Sätter Timer1**** 

 CODE
Init
 BANKSEL T1CON
 bsf T1CON,TMR1ON
 clrf TMR1H
 clrf TMR1L
 BANKSEL INTCON
 bsf INTCON,GIE
 BANKSEL PIE1
 bsf PIE1,TMR1IE
 BANKSEL PIR1
 bcf PIR1,TMR1IF

;****Sätter portar**** 
 BANKSEL TRISA 
 movlw 0x00 ;Gör port A till output 
 movwf TRISA
 movwf COUNT3
 movlw 0xFF
 movwf COUNT1
 movwf COUNT2
 BANKSEL PORTA 
 movlw 0x02

;****kör en xor för att byta status på lysdioden**** 

Start
 xorwf PORTA,1 

;****kör en delay och går till Start**** 

 call Delay 
 goto Start 

;****Subrutin för delay**** 

Delay 

Loop1
;BANKSEL COUNT1 , behövs ej då variablarna finns i UDATA_SHR
 decfsz COUNT1,F
 goto Loop1
;BANKSEL COUNT2 , -||-
 decfsz COUNT2,F
 goto Loop1 

 return

 end
Skriv svar