Sida 1 av 2

asm: Stack overflow/underflow error...

Postat: 8 januari 2007, 02:21:16
av JimmyAndersson
Har lite problem med min delayrutin. Först gav den "Stack overflow error". Debuggade och plockade bort lite grejjer och då fick jag underflow error istället.

Får jag lov att presentera min första asm-kod på 20 år! :whoho:

Kod: Markera allt

;************************************************************
	processor	18f1320
	#include		<p18f1320.inc>
;************************************************************
;		TFTUVbox
;
;		Använder interna oscillatorn (8MHz.)
;		Knappar --> AN5 (RB1)
;		Öppet lock --> RB7
;		Mäta ljus --> AN4 (RB0)
;		Ljud <-- RB3
;		Styra UV <-- RB4
;		Styra TFT <-- RB6
;
;************************************************************
;		CONFIG SETTINGS

	CONFIG	OSC = INTIO2
	CONFIG	PWRT = ON, BOR = OFF, WDT = OFF, MCLRE = ON
	CONFIG	STVR = OFF, LVP = OFF, DEBUG = OFF, CP0 = ON
	CONFIG	CP1 = ON, CPB = ON, CPD = ON, WRT0 = ON
	CONFIG	WRT1 = ON, WRTB = ON, WRTC = ON, WRTD = ON
	CONFIG	EBTR0 = ON, EBTR1 = ON, EBTRB = OFF
;************************************************************
;	Defines och EUQ

;	DISPLAY 12x2
#define		D4		LATA, 0
#define		D5		LATA, 1
#define		D6		LATA, 2
#define		D7		LATA, 3
#define		RS		LATA, 4
#define		E		LATA,6

;	BELYSNING
#define		UV_rela	PORTB, 4
#define		TFT_rela	PORTB, 6

;	ENCODER
#define		Encoder1a	PORTB, 5
#define		Encoder1b	PORTB, 2

;************************************************************

Boot	CODE	h'0000'
	goto	Start

;************************************************************
Main	CODE
 
Start
;	OSCILLATOR FREQ 8MHz
	bcf		OSCCON, IDLEN
	bsf		OSCCON, IRCF2
	bsf		OSCCON, IRCF1
	bsf		OSCCON, IRCF0
	bsf		OSCCON, SCS1

;	IN/UTGÅNGAR
	movlw	b'10000000' 
	movwf	TRISA
	movlw	b'10100111'
	movwf	TRISB

;	NOLLSTÄLL PORTARNA...
	clrf	PORTA
	clrf	PORTB

;	INITIERA INTERRUPT
**Plockade bort lite initieringar här**

;************************************************************
;	INITIERA DISPLAYEN
lcd_start	CODE

	bcf		RS
	movlw	b'00000011'
	movwf	LATA
	call delay_1ms
;	movlw	b'00000011'
;	movwf	LATA
;************************************************************
loop

	goto	loop	;Igen!

;************************************************************
; Delay1ms -- 1ms = 2000 cycles @ 8MHz.  <-- Ska bli 1ms, koden stämmer inte nu.

dly_vars	udata_acs
CNT1		res 1
CNT2		res 1
CNT3		res 1

dly_code	CODE

delay_1ms
;	return
;
	movlw	0x01 
	movwf	CNT1
	movlw	0x01 
	movwf	CNT2
	movlw	0x10 
	movwf	CNT3
dly_loop
	decfsz	CNT2
	goto	dly_loop
	movlw	0x08
	movwf	CNT2
;	decfsz	CNT1
;	goto	dly_loop
;	decfsz	CNT3
;	goto	dly_loop
	return

	end
Delayrutinen är stul... eh, lånad av sodjans kod.

När jag kör koden i MPLAB SIM och har med de sista fyra ; så får jag:

CORE-E0002: Stack under flow error occurred from instruction at 0x0000c4

Plockar jag bort de sista ; så får jag istället:

CORE-E0001: Stack over flow error occurred from instruction at 0x0000be



Litet klipp ur .lst-filen när jag har med de sista ;

Kod: Markera allt

                                           ;	decfsz	CNT1
                                           ;	goto	dly_loop 
                                           ;	decfsz	CNT3
                                           ;	goto	dly_loop 
0000c4   0012     RETURN    0x0            	return 
Hmm? :jimmyhacker:

Postat: 8 januari 2007, 11:44:49
av sodjan
Stack over/under flow brukar tyda på att men har "obalans" i sina CALL/RETURN.

Overflow : Man gör för många CALL innan RETURN (16 nivåer på en PIC18).
Underflow : Man gör RETURN utan en tidigare CALL.

Ett vanligt fel är att man gör GOTO till en subrutin där man sedan gör RETURN.

Hur "flyter" koden genom MPSIM ? Tar den de vägar som är tänkt ?
Sannolikt kommer du till RETURn på 0000c4 utan att ha gjort CALL innan...

Med koden som den ser ut *här* så får jag inte samma fel, det saknas kanske något.

En annan liten detalj....

Notera att varje CODE segment är en enhet som länkaren kan välja att
placera var som helst i minnet. D.v.s att det inte är en bra ide att bara
låta koden "glida" över från ett segment till ett annat, det är inte säkert
att den kod man tror ligger där man tror.

Alla hopp in/ut ur olika CODE segment bör ske med GOTO eller CALL/RETURN.

Postat: 8 januari 2007, 20:57:18
av JimmyAndersson
Jag råkade ta bort några rader för mycket när jag kopierade in koden i inlägget.

Om jag har med nedanstående text efter "**Plockade bort lite initieringar här**" i min förra kod så får jag felet med underflow:

Kod: Markera allt

;	TIMER1 INITIERING OCH DESS INTERRUPT-INITIERING
	bsf		T1CON, RD16
	bsf		T1CON, T1RUN
	bsf		T1CON, T1CKPS1
	bsf		T1CON, T1CKPS0
	bcf		T1CON, T1OSCEN
	bcf		T1CON, T1SYNC
	bcf		T1CON, TMR1CS
	bcf		T1CON, TMR1ON
	bcf		PIE1, TMR1IE
	bsf		INTCON, GIE
	bsf		INTCON, PEIE

Om jag kommenterar bort allt ovanstående förutom GIE och PEIE så får jag fortfarande fel. Om jag däremot även kommenterar bort GIE och PEIE så försvinner felet.

Har kollat i databladet, men det enda jag kommit på är några små skillnader mot .inc-filen.
I databladet delar GIE och GIEH samma bit. Lika så med PEIE och GIEL, men i .inc-filen är de två skilda bitar. Men det har ingen betydelse för resultatet i min kod.

Postat: 9 januari 2007, 00:11:56
av sodjan
OK, då förstår jag.... :-)

Du "enablar" alltså interrupt, men jag ser ingen interrupt rutin (ISR).
Du startar Timer1 med interrupt. Vid varje interrupt så hamnar du på
h'0008' eller h'0016' (minns inte vilket , kolla databladet). I princip en
"automatisk CALL" till den adressen. Men sedan finns det ingen ISR kod
och ingen RETFIE.

Simple as that...

Fråga, varför behöver du *både* hårdkodade delay rutiner *och* timer interrupt ?
Man brukar använda antingen eller...

Om du ska använda interrupt, kör med *en* nivå och glöm xxxH symbolerna
och registerbitarna.

Postat: 9 januari 2007, 01:30:06
av JimmyAndersson
"Du "enablar" alltså interrupt, men jag ser ingen interrupt rutin (ISR)."

Aha! Det var *det* som jag hade missat. Nu fungerar det. :)


"Fråga, varför behöver du *både* hårdkodade delay rutiner *och* timer interrupt ?"

Good point. Jag kan lika gärna använda timer till 1ms-pausen också. :)


"Om du ska använda interrupt, kör med *en* nivå och glöm xxxH symbolerna och registerbitarna."

Här hänger jag inte med. Jag måste väl använda t.ex registerbiten GIE ? Hur gör man annars?

Postat: 9 januari 2007, 12:21:16
av sodjan
GIE ja.
GIEH nej.

Postat: 9 januari 2007, 15:20:03
av JimmyAndersson
?

Försöker igen:

"Om du ska använda interrupt, kör med *en* nivå och glöm xxxH symbolerna och registerbitarna."

Så jag ska alltså inte skriva såhär:

Kod: Markera allt

;   TIMER1 INITIERING OCH DESS INTERRUPT-INITIERING 
   bsf      T1CON, RD16 
   bsf      T1CON, T1RUN 
   bsf      T1CON, T1CKPS1 
   bsf      T1CON, T1CKPS0 
   bcf      T1CON, T1OSCEN 
   bcf      T1CON, T1SYNC 
   bcf      T1CON, TMR1CS 
   bcf      T1CON, TMR1ON 
   bcf      PIE1, TMR1IE 
   bsf      INTCON, GIE 
   bsf      INTCON, PEIE

Hur ska det vara då?

"glöm xxxH symbolerna och registerbitarna."

Då blir det ju inget kvar förutom bsf och bcf...

Testade att rensa ovanstående kod-del så att det bara stod:

Kod: Markera allt

   bsf      RD16 
   bsf      T1RUN 
   bsf      T1CKPS1 
   bsf      T1CKPS0 
   bcf      T1OSCEN 
   bcf      T1SYNC 
   bcf      TMR1CS 
   bcf      TMR1ON 
   bcf      TMR1IE 
   bsf      GIE 
   bsf      PEIE
men då fick jag massa felmeddelande av den här typen:

Error[128] C:\WINDOWS\SKRIVBORD\PIC\ASM\PIC18LF1320\TEST1\TEST1.ASM 135 : Missing argument(s)

(Samma sak med de övriga kodraderna ovan.)




Vore toppen om jag kunde få en "putt i rätt riktning" åtminstone. :)

Postat: 9 januari 2007, 15:59:30
av sodjan
He he... :-)

Alltså, när man kör med *dubbla* interrupt prioriteter, så använder man
en del symboler/bitar som slutar på "H", t.ex GIEH.

När man kör med *en* (rekomenderas) interrupt nivå, så används *inte*
dessa "high-" symboler, utan bara t.ex GIE.

D.v.s att du inte ska göra "bsf INTCON, GIEH", utan bara "bsf INTCON, GIE".
Du behöer inte heller bry dig om de bitar som anger om ett visst interrupt
(t.ex från timer1) ska vara "low" eller "high".

Det var mer som en generell notering...

Posta gärna din aktuella kod så testbygger jag senare i kväll...

Postat: 9 januari 2007, 18:31:04
av JimmyAndersson
Jasså, det var så du menade. :D


ISR-delen är inte klar, så jag får underflow error när GIE är satt. Av samma orsak är många av interrupt-initieringarna bortkommenterade.
LCD-initieringen ska göras om, det var mer en test för att kolla delayet. Ska bl.a göra en snyggare rutin och använda timer istället för delay-delen.
Men clearar man GIE så blir det inga fel i debuggern.

Min nuvande kod ser ut såhär:

Kod: Markera allt

;************************************************************
	processor	18f1320
	#include		<p18f1320.inc>
;************************************************************
;		TFTUVbox
;
;		Använder interna oscillatorn (8MHz.)
;		Knappar --> AN5 (RB1)
;		Öppet lock --> RB7
;		Mäta ljus --> AN4 (RB0)
;		Ljud <-- RB3
;		Styra UV <-- RB4
;		Styra TFT <-- RB6
;
;************************************************************
;		CONFIG SETTINGS - Note: DEBUG, CPx, WRTx, osv.

	CONFIG	OSC = INTIO2
	CONFIG	PWRT = ON, BOR = OFF, WDT = OFF, MCLRE = ON
	CONFIG	STVR = OFF, LVP = OFF, DEBUG = OFF, CP0 = ON
	CONFIG	CP1 = ON, CPB = ON, CPD = ON, WRT0 = ON
	CONFIG	WRT1 = ON, WRTB = ON, WRTC = ON, WRTD = ON
	CONFIG	EBTR0 = ON, EBTR1 = ON, EBTRB = OFF
;************************************************************
;	Defines och EUQ

;	DISPLAY 12x2
#define		D4		LATA, 0
#define		D5		LATA, 1
#define		D6		LATA, 2
#define		D7		LATA, 3
#define		RS		LATA, 4
#define		E		LATA,6

;	BELYSNING
#define		UV_rela		PORTB, 4
#define		TFT_rela	PORTB, 6

;	ENCODER
#define		Encoder1a	PORTB, 5
#define		Encoder1b	PORTB, 2

;************************************************************

Boot	CODE	h'0000'
	goto	Start

;************************************************************
Main	CODE
 
Start
;	OSCILLATOR FREQ 8MHz
	bcf		OSCCON, IDLEN
	bsf		OSCCON, IRCF2
	bsf		OSCCON, IRCF1
	bsf		OSCCON, IRCF0
	bsf		OSCCON, SCS1

;	IN/UTGÅNGAR
	movlw	b'10000000' 
	movwf	TRISA
	movlw	b'10100111'
	movwf	TRISB

;	NOLLSTÄLL PORTARNA...
	clrf	PORTA
	clrf	PORTB

;	INITIERA INTERRUPT
;	bcf		INTCON, TMR0IE
;	bcf		INTCON, INT0IE
;	bcf		INTCON, RBIE ; <---- DISABLE RB-PORT CHANGE INTERRUPT
;	bcf		INTCON, TMR0IF
;	bcf		INTCON, INT0IF
;	bcf		INTCON, RBIF

;	bsf		INTCON2, RBPU
;	bsf		INTCON2, INTEDG0
;	bsf		INTCON2, INTEDG1
;	bsf		INTCON2, INTEDG2
;	bsf		INTCON2, TMR0IP
;	bsf		INTCON2, RBIP
;
;	bsf		INTCON3, INT2IP
;	bsf		INTCON3, INT1IP
;	bcf		INTCON3, INT2IE
;	bcf		INTCON3, INT1IE
;	bcf		INTCON3, INT2IF
;	bcf		INTCON3, INT1IF

;	bcf		PIE1, RCIE
;	bcf		PIE1, TXIE
;	bcf		PIE1, CCP1IE
;	bcf		PIE1, TMR2IE
;
;	bcf		RCON, IPEN
;	movlw	0x00
;	movwf	PIE2
;
;	AD-OMVANDLARE OCH DESS INTERRUPT-INITIERING
;	bcf		ADCON0, VCFG1
;	bcf		ADCON0, VCFG0
;	bsf		ADCON0, CHS2
;	bcf		ADCON0, CHS1
;	bsf		ADCON0, CHS0
;	bsf		ADCON0, ADON	; AD-OMVANDLARE ENABLED
;	bsf		ADCON0, GO_DONE ; CLEARAS NÄR AD ÄR GJORD
;	movlw	b'01001111'
;	movwf	ADCON1

;	bsf		ADCON2, ADFM
;	bcf		ADCON2, ACQT2
;	bsf		ADCON2, ACQT1
;	bcf		ADCON2, ACQT0
;	bsf		ADCON2, ADCS2
;	bcf		ADCON2, ADCS1
;	bsf		ADCON2, ADCS0

;	bcf		PIR1, ADIF	; AD-CONVERTER INTERRUPT FLAG BIT
;	bsf		PIE1, ADIE	; ENABLES AD-INTERRUPT

;	TIMER1 INITIERING OCH DESS INTERRUPT-INITIERING
	bsf		T1CON, RD16
	bsf		T1CON, T1RUN
	bsf		T1CON, T1CKPS1
	bsf		T1CON, T1CKPS0
	bcf		T1CON, T1OSCEN
	bcf		T1CON, T1SYNC
	bcf		T1CON, TMR1CS
	bsf		T1CON, TMR1ON	; <---- TIMER1 ENABLED

	bsf		PIE1, TMR1IE	; <---- TMR1 OVERFLOW INTERRUPT ENABLED

	bsf		INTCON, GIE		; GLOBAL INTERRUPT ENABLED
	bsf		INTCON, PEIE	; PERIPHERAL INTERRUPT ENABLED


;************************************************************
;	INITIERA DISPLAYEN
lcd_start	CODE

	bcf		RS
	movlw	b'00000011'
	movwf	LATA
	call	delay_1ms
	movlw	b'00000011'
	movwf	LATA
	call	delay_1ms
	movlw	b'00000011'
	movwf	LATA
	call	delay_1ms
	movlw	b'00000010'
	movwf	LATA
	call	delay_1ms
	movlw	b'00000010'
	movwf	LATA
	call	delay_1ms
	movlw	b'00001000'
	movwf	LATA
	call	delay_1ms
	movlw	b'00000000'
	movwf	LATA
	call	delay_1ms
	movlw	b'00000001'
	movwf	LATA
	call	delay_1ms
	movlw	b'00000000'
	movwf	LATA
	call	delay_1ms
	movlw	b'00000110'
	movwf	LATA
	call	delay_1ms
	movlw	b'00000000'
	movwf	LATA
	call	delay_1ms
	movlw	b'00001100'
	movwf	LATA
	call	delay_1ms

;************************************************************

loop

	goto	loop	;Igen!

;************************************************************
isr_rutin	CODE

isr_rutin

	nop
	;här ska det ligga några fler rader..  :-)
	;nop-raderna ska bort sedan.
	nop
	bcf		PIR1, TMR1IF

	retfie

;************************************************************
; Delay1ms -- 1ms = 2000 cycles @ 8MHz

dly_vars	udata_acs
CNT1		res 1
CNT2		res 1
CNT3		res 1

dly_code	CODE

delay_1ms
	movlw	0x01 
	movwf	CNT1
	movlw	0x01
	movwf	CNT2
	movlw	0x10
	movwf	CNT3
dly_loop
	decfsz	CNT2
	goto	dly_loop
	movlw	0x08
	movwf	CNT2
	decfsz	CNT1
	goto	dly_loop
	decfsz	CNT3
	goto	dly_loop
	return

	end

Postat: 9 januari 2007, 18:50:03
av sodjan
> så jag får underflow error när GIE är satt.

Det borde försvinna om du lägger till lite kod på h'0008'
(d.v.s interrupt vektorn):

Kod: Markera allt

;************************************************************

Boot      CODE   h'0000'
   goto   Start

;************************************************************

Int_vect  CODE   h'0008'
   goto   isr_rutin

;************************************************************
Den ISR du har "fungerar" ju som den är, den clearar TMR1IF och gör RETFIE.
Lägg gärna till "RETFIE FAST", så får du automatisk save/restore av kontext (registren PC, WREG, BSR och STATUS).
Det tar ingen extra tid utan sker on-the-fly. Ytterligare en skillnad mot PIC16 vilket ger snabbare interrupts på PIC18.

Din metod att sätta de olika kontrol-registren är ju i och för sig väldigt
tydligt, men ofta går det också att använda en "MOVLW b'xxxxxxxx'" följt av
en "MOVWF <reg>".
Sen kan man kommentera vad man gör...

Inte så stor mening att testköra kanske, eftersom det är uppenbart att det
saknades kod på h'0008'.

Postat: 9 januari 2007, 18:50:17
av Andax
Jimmy, du bör läsa sodjans inlägg lite noggrannare... Se citatet nedan. Det är väl framförallt det CODE som står vid lcd_start som kan strula...
sodjan skrev:En annan liten detalj....

Notera att varje CODE segment är en enhet som länkaren kan välja att
placera var som helst i minnet. D.v.s att det inte är en bra ide att bara
låta koden "glida" över från ett segment till ett annat, det är inte säkert
att den kod man tror ligger där man tror.

Alla hopp in/ut ur olika CODE segment bör ske med GOTO eller CALL/RETURN.

Postat: 9 januari 2007, 19:48:34
av JimmyAndersson
Andax:
"Jimmy, du bör läsa sodjans inlägg lite noggrannare..."

Tro mig, jag läser dem så noga jag kan. Ofta flera gånger. Att min kod inte stämde i det fallet berodde på en missuppfattning från min sida. Det är ju ändå bara fyra-fem dagar sedan jag började knappa assembler och alla "aha-upplevelser" kan ju inte komma samtidigt... :)

Men efter lite ändringar så flyter nu koden på fint.
Det jag ändrat är att plocka bort "lcd_start CODE" från "lcd_start" plus ändringarna i sodjan's inlägg.

Postat: 9 januari 2007, 22:57:52
av Andax
Jimmy, kom på att min formulering kanske lät mer hård än jag menade... :wink: Å andra sidan, med din iver är 4-5 dagar en ganska lång tid att lära sig assembler!! :)

Tycker det ser strålande ut...

Postat: 9 januari 2007, 23:18:25
av JimmyAndersson
"Å andra sidan, med din iver är 4-5 dagar en ganska lång tid att lära sig assembler!!"

:lol: :lol: Så sant.

Postat: 9 januari 2007, 23:25:50
av sodjan
> Det jag ändrat är att plocka bort "lcd_start CODE" från "lcd_start"

Problemet är alltså att man alltid ska "gå in" i en visst kodesegment ("CODE")
via GOTO eller CALL. Då tar MPLINK hand om ifall de olika segmenten
blandas runt lite. GOTO eller CALL kommer alltid att peka "rätt".

Men, om koden blir lite konstig med ett GOTO eller CALL på ett ställe
där det av andra orsaker inte behövs, så är det lite bra att plocka
bort det extra CODE direktivet.

Personligen brukar jag lägga till en CODE för varje subrutin (eller grupp
av subrutiner som hör ihop på något sätt). En fördel är att MAP filen
ger en direkt rapport i klartext hur stor (word/bytes) varje subrutin (eller
grupp av subrutiner) är. Det är inte alltid så lätt att se från ASM filen,
speciellt om man använder många MACRO's som expanderas till
lite olika antal ASM-instruktioner...

Bortsätt från detta, så finns det ingen speciel nackdel med att ha många
CODE segment. Men ger MPLINK lite fler möjligheter. T.ex om man har
placerat en RETLW-tabell någonstans (t.ex hårdkodat på en fast 256-byte
gräns) så får MPLINK det lite lättare att "lägga pussel" ju fler CODE segment
den har att "pussla" med. Möjligtsvis ökar "build-tiden" lite...