PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega16 springt zu $0000, Reset?



tml
14.08.2005, 11:11
Hallo Leute,

ich hab ein eigenartiges Problem: Mein Atmega16 beginnt nach 66 sekuendiger fehlerfreier Programmausfuehrung ploetzlich wieder bei der Adresse $0000 mit dem Programm. Ich glaube allerdings nicht, dass es sich um einen Reset handelt, weil ich den Reset-Pin richtig angeschlossen hab, keinen Watchdog verwende, dieses JTAG-interface ausgeschalten habe und die Betreibsspannung nicht schwankt. Außerdem werden die Register nicht mit ihren Anfangswerten initialisiert, sondern behalten ihre derzeitigen Werte bei. Woran koennte das liegen? Ich waer echt dankbar, wenn mir jemand helfen kann, weil ich langsam am verzweifeln bin.

Danke im Voraus.

kater
14.08.2005, 11:24
Macht er das immer nach genau 66sek?
Koentest du uns das Programm geben?

PicNick
14.08.2005, 12:52
Kann sein, daß das nix damit zu tun hat. Aber wenn ich den ISP angeschlossen lasse, kriegt der Chip gelegentlich einen auf die Glocke vom Brennerprogramm.
Für störungsfrei (von der Seite) muß ich abstecken

tml
14.08.2005, 14:29
Das ging aber schnell! Danke.

Ja der macht das aller 66 Sekunden. Es ist egal, ob das ISP angeschlossen ist oder nicht, der Fehler tritt trotzdem auf.

Das Programm ist allerdings ein ganzes Stueck lang, weil ich ein LCD angeschlossen hab:

.nolist
.include "m16def.inc"
.list

.def data = r0
.def flag = r10
.def temp = r16
.def tim1 = r17
.def tim2 = r18
.def addr = r20
.def tmp1 = r19
.def blinkr = r21
.def cnt = r22
.def bin = r23
.def lowb = r24
.def highb = r25

.equ RS = 4 ;alle von PortC
.equ RW = 5
.equ E = 6

.equ Minus = 0

.cseg
initial:
cbi PortD, 7 ;Hintergrundbeleuchtung ausschalten

ldi temp, low(ramend)
out SPL, temp
ldi temp, high(ramend)
out SPH, temp ;Stackpointer initialisiert

ldi temp, 0b10000000 ;MSB setzen (JTD)
out MCUCSR, temp
out MCUCSR, temp ;2x -> kein JTAG

;I/O-Ports definieren

ldi temp, 0b11000000
out DDRD, temp ;Port D: Pin7,6->A, Rest->E
ldi temp, 0b00000001
out DDRB, temp ;Port B: Pin1->Ausgang, Rest->Eingang
ldi temp, 0xFF
out DDRC, temp ;Port C -> Ausgang

;A/D-Wandler initialisieren
sbi ADCSR, 7 ;anschalten
in temp, ADCSR
sbr temp, 0b00100111 ;Vorteiler=128; ADC an, Autotrigger
out ADCSR, temp ;uebernehmen
ldi temp, 0b11000001 ;V(ref) = 2,56V; kanal1
out ADMUX, temp
sbi ADCSR, 6 ;und los

LCDinit: cli
call wait500ms
call wait500ms
ldi temp, 0b11
out PortC, temp
call enable ;erstesmal uebernehmen
call wait5ms
call enable ;2.mal uebernehmen
call wait5ms
call enable ;3.mal uebernehmen
call wait5ms
ldi temp, 0b00000010 ;4-bit Modus einstellen
call SendCom
ldi temp, 0b00101000 ;Zeilenzahl und Matrix setzen
call SendCom
ldi temp, 0b00001000 ;Display abschalten
call SendCom
ldi temp, 0b00000001 ;Display loeschen
call SendCom
ldi temp, 0b00000110 ;Eingabemodus setzen
call SendCom
ldi temp, 0b00001100 ;Display einschalten
call SendCom ; ohne Cursor und ohne blinken
sei

ldi ZL, low(text1)
ldi ZH, high(text1)
call SendTxt
ldi temp, 0b11000011
call SendCom
ldi ZL, low(GradC)
ldi ZH, high(GradC)
call SendTxt
ldi temp, 0b11001110
call SendCom
ldi ZL, low(GradC)
ldi ZH, high(GradC)
call SendTxt
sbi PortD, 7 ;Hintergrundbeleuchtung einschalten

endlos: call wait5ms
in lowb, ADCL ;Lowbyte der Umwandlung einlesen
in highb, ADCH ;Highbyte einlesen
push lowb
push highb ;fuer spaeter
ldi temp, 0b11000000
call SendCom
call umrech
ldi temp, 0b0 ;
call chngchnl ;2.Kanal (Kanal1) auswaehlen
call wait5ms ;Zeit fuer neue Umwandlungen lassen
in lowb, ADCL ;Lowbyte der Umwandlung einlesen
in highb, ADCH ;Highbyte einlesen
ldi temp, 0b11001011
call SendCom
call umrech
ldi temp, 0b1
call chngchnl
cbi PortB, 0
sbrc flag, Minus ;IP+2 bei gesetztem "Minus"-flag
sbi PortB, 0
jmp endlos ;von vorn



;---Prozeduren fuer die verschiedenen Zeitspannen---
wait5ms: cli
push temp
ldi temp, 78
out OCR0, temp ;OutputCompareRegister=10000
ldi temp, 0b101
out TCCR0, temp ;8bit-Timer mit Vorteiler=8 starten
warten: in temp, TIFR
sbrs temp, 1 ;Flag testen (TCNT0=OCR0)
jmp warten
sbr temp, 0b10
out TIFR, temp ;Flag zuruecksetzen
eor temp, temp ;temp=0
out TCCR0, temp
out TCNT0, temp ;=0
pop temp
sei
ret
wait500ms: cli
push tmp1
ldi tmp1, 100
wait500msa: call wait5ms
dec tmp1
brne wait500msa
pop tmp1
sei
ret ;100 mal 5ms

;___________einen "Enable"-Impuls starten (Display uebernimmt Daten)_____________________
enable: sbi PortC, E ;Enable-Pin -> H
call wait5ms ;5000ns spaeter
cbi PortC, E ;Enable-Pin -> L
ret
;___________Einen String ans Display senden____________________________________________ _
SendTxt: push temp
push cnt
cli
clr cnt
lsl ZL
rol ZH ;Z-Pointer mal 2
SendTxta: lpm ;Byte von Adresse (Z) im Flash laden
mov temp, data ;in data (r0) landete das byte
cpi temp, 0
breq SendTxtb
call SendDat ;an LCD senden
adiw ZH:ZL, 1 ;Z-Pointer incrementieren
inc cnt
jmp SendTxta
SendTxtb: ldi temp, 0x20
call SendDat
inc cnt
cpi cnt, 16
brlo SendTxtb
ldi temp, 0b10000000
call SendCom
sei
pop cnt
pop temp
ret
;___________Prozedur zum Senden von Befehlen ans Display (4bit-Modus)___________________
SendCom: cli
push tmp1
push temp
mov tmp1, temp
swap temp ;hoeherwertiges Nibble->niederwertiges
andi temp, 0x0F ;hoeherwertiges->loeschen (auf 0 setzen)
out PortC, temp
call enable ;Uebernehemen
andi tmp1, 0x0F
out PortC, tmp1
call enable
call wait5ms
pop temp
pop tmp1
sei
ret
;___________Prozedur zum senden von Zeichen an das Display (4bit-Modus)_________________
SendDat: cli
push tmp1
push temp
mov tmp1, temp
swap temp ;hoeherwertiges Nibble->niederwertiges
andi temp, 0x0F ;hoeherwertiges->loeschen (auf 0 setzen)
out PortC, temp
sbi PortC, RS
call enable ;Uebernehemen
andi tmp1, 0x0F
out PortC, tmp1
sbi PortC, RS
call enable
call wait5ms
pop temp
pop tmp1
sei
ret
;---Prozedur zum Umrechnen des 10bit A/D-ergebnisses in eine Temperatur---
umrech: push lowb
push highb ;fuer spaeter
ldi temp, 88 ;mit 88 multiplizieren
ldi tmp1, 0
mul lowb, temp ;multiplizieren
mov tim1, r0
mov tim2, r1
mul highb, temp
add r0, tim2 ;hoeheres mit niedrigem addieren
adc r1, tmp1 ;falls Ueberlauf
mov lowb, r0
mov highb, r1
subi lowb, 0x18
mov bin, lowb
pop highb
pop lowb ;wiederherstellen
;cpi highb, 0x03
;brne umrech_e ;wenn nicht gleich -> umrech_e
cpi lowb, 0x2F
brlo umrech_k ;wenn kleiner 0°C springen
mov temp, flag
cbr temp, 0b1
mov flag, temp ;"Minusflag" loeschen
jmp umrech_e ;sonst beenden
umrech_k: ldi tmp1, 0xFF
sub tmp1, bin
inc tmp1 ;minusgrade ausrechnen
mov bin, tmp1
mov temp, flag
sbr temp, 0b1
mov flag, temp ;"Minusflag" setzen
umrech_e: ldi tmp1, '0' ;Ascii von 0
ldi cnt, 0 ;counter = 0
ldi tim1, 3 ;HilfCouNTer = 3
ldi XL, 0x60
ldi XH, 0 ;Adresse von 1. Speicherstelle im SRAM setzen
umrech_c: cpi bin, 10 ;Rest mit 10 vergleichen
brlo umrech_a ;wenn kleiner Schleife verlassen
subi bin, 10 ;10 abziehen
inc cnt ;incrementieren
jmp umrech_c
umrech_a: add bin, tmp1 ;-> Ascii-Code
st X+, bin ;Bin (Ascii-Code) in SRAM ($60) speichern und X-Pointer incrementieren
mov bin, cnt ;Ergebnis der Division nach, bin
clr cnt
dec tim1
breq umrech_b ;wenn 3mal durchgelaufen, dann beenden
jmp umrech_c
umrech_b: ;sbiw XL, 1 ;3. Ascii-Code laden (entspricht "Hunderter")
ld temp,-X
ldi temp, '+' ;positive Temperatur anzeigen
sbrc flag, 0
ldi temp, '-' ;negative Temperatur anzeigen
call SendDat
ld temp,-X ;2. Ascii-Code laden (entspricht "Zehner")
call SendDat
ld temp,-X ;1. Ascii-Code laden (entspricht "Einer")
call SendDat
ret

chngchnl: cli ADCSR, 5 ;anhalten
in tmp1, ADMUX
andi tmp1, 0b11100000 ;unterste 5 bit loeschen
or tmp1, temp ;entsprechende bits setzen
out ADMUX, tmp1
sbi ADCSR, 5
sbi ADCSR, 6 ;wieder starten
ret

;---Strings zum Ausgeben auf dem Display (0-terminiert)---
text1: .db "aktuelle Messung",0
kanal0: .db "0:",0
kanal1: .db "1:", 0
GradC: .db 0b11011111,"C",0


Ich vermute der Fehler liegt in dem Unterprogramm "umrech", welches den Wert vom ADC in eine Temperatur umrechnet und am Display ausgibt.

Es waer wirklich nett, wenn ihr euch den Quelltext mal anschaut, wenn nicht kann ich das aber auch verstehen, weil der ja nicht grad kurz ist (Da ich absolut keine idee hab, wo der Fehler liegt, konnte ich nicht nur einen Ausschnitt zeigen).

izaseba
14.08.2005, 16:41
Hallo,
ich hab mir zwar Dein Programm angeguckt, konnte aber auch keinen großen Fehler
finden, nur ein paar Anregungen.

Du benutzt keine Interrupts, wozu dann cli und sei ?
Bei den enable Puls brauchst Du keine 5 ms warten, ein paar nops reichen vollkommen.
So wie Du den XZeiger belegst ist es schon was komisch, so geht es sicherlich auch,
aber eleganter wäre z.B.

.equ puffer = 0x060

und dann mit
ldi XH,HIGH(puffer)
ldi XL,LOW(puffer)

Aber das ist eher kosmetischer Natur

A ja,
in Deiner endlos schleife machst Du zwei pushs :

push lowb
push highb

und wo werden sie wieder weggeholt?
Leider habe ich mir das nicht genau angeguckt, vielleicht hollst Du sie irgendwo in einer
anderen routine wieder weg, die ersten rcalls tun das aber nicht.

Nicht daß Du dir den Stack zumüllst.......

Gruß Sebastian

Psiyou
14.08.2005, 16:57
Hallo,

kenne mich mit asm jetzt nicht so aus, aber ich hab mal gehört das die Atmels beim auslösen eines interupts der nicht vergebenwurde std.mäßig wieder nach 0000 springen.
Is aber nur so ne vermutung...

Scheint falsch zu sein... Siehe nächsten Beitrag !!!!!

izaseba
14.08.2005, 17:03
std.mäßig wieder nach 0000 springen

Das würde ich nicht sagen, sie Springen ganau zu der Adresse, die den entspechendem
Interrupt zugewiesen ist.
Hier ein Auszug aus m16def.inc :


; ***** INTERRUPT VECTORS ************************************************
.equ INT0addr = 0x0002 ; External Interrupt Request 0
.equ INT1addr = 0x0004 ; External Interrupt Request 1
.equ OC2addr = 0x0006 ; Timer/Counter2 Compare Match
.equ OVF2addr = 0x0008 ; Timer/Counter2 Overflow
.equ ICP1addr = 0x000a ; Timer/Counter1 Capture Event
.equ OC1Aaddr = 0x000c ; Timer/Counter1 Compare Match A
.equ OC1Baddr = 0x000e ; Timer/Counter1 Compare Match B
.equ OVF1addr = 0x0010 ; Timer/Counter1 Overflow
.equ OVF0addr = 0x0012 ; Timer/Counter0 Overflow
.equ SPIaddr = 0x0014 ; Serial Transfer Complete
.equ URXCaddr = 0x0016 ; USART, Rx Complete
.equ UDREaddr = 0x0018 ; USART Data Register Empty
.equ UTXCaddr = 0x001a ; USART, Tx Complete
.equ ADCCaddr = 0x001c ; ADC Conversion Complete
.equ ERDYaddr = 0x001e ; EEPROM Ready
.equ ACIaddr = 0x0020 ; Analog Comparator
.equ TWIaddr = 0x0022 ; 2-wire Serial Interface
.equ INT2addr = 0x0024 ; External Interrupt Request 2
.equ OC0addr = 0x0026 ; Timer/Counter0 Compare Match
.equ SPMRaddr = 0x0028 ; Store Program Memory Ready

.equ INT_VECTORS_SIZE = 42 ; size in words

PicNick
14.08.2005, 17:27
Beim vorliegenden Code steht nach "CSEG" sofort das Programm und keinen ISR-Vectoren. D.h. WENN ein Interupt tatsächlich ausgelöst würde, fängt der rechner dann irgendwo im Programm vorne an.
Das sollte also wirklich nicht vorkommen. Laß das SEI also lieber weg, wenn du es eh nicht brauchst

tml
14.08.2005, 19:38
Ok. Die sei's cli's sind noch Ueberbleibsel vom vorhergehendem Programm. Ich bin grad dabei, meine Hardware richig zu testen und ein bisschen rumzuspielen und hab die vergessen weg zumachen, danke fuer den Hinweis.

Mit den Push's hast du recht. ](*,) . Ich hab die wirklich nicht wieder runtergeholt und der hat sich vielleicht bis zu dem Registerbereich runtergefressen und hat dort Chaos gemacht! Gerade in der Endlosschleife hab ich viel veraendert und da sin die ausversehen stehen geblieben.

Ich werd's gleich mal aendern und euch sofort Bescheid sagen, wenn's geht.

tml
14.08.2005, 19:52
Es geht!!! Es lag an den push's. Die sei's und so haben keine Fehler verursacht. Danke an alle, die sich mit meinem Problem befasst haben. =D>

Das mit den 5ms beim enable-impuls ist wirklich sehr ueberdimensioniert und hab das auch schon mit ein paar nop's probiert, da geht's aber nicht, warum auch immer. Dieser enable-impuls muss ja nur 450ns lang anliegen und die Daten 195ns vorher stabil sein (steht so im Datenblat vom HD44780). Hatte aber noch keine Erfahrung mit LCD's und hab das daher erstmal so gelassen.

Vielleicht kann mir ja jemand sagen, warum das bei mir nicht geht? Koennte es sein, dass der LCD-Controller "nur" HD44780-kompatibel ist?

izaseba
14.08.2005, 20:03
Hallo tml,
Es freut mich, daß es bei Dir geklappt hat,
In Fremden Codes zu lesen ist wirklich schwer,
aber mach die sei's und cli's auch weg die gehören da nicht hin!
Ich hab bei mir eine leere Schleife, die 10 mal durchlaufen wird um Enable zu aktivieren,
also 10 mal brne macht 20 Takte plus dec 1 takt, naja so etwa 30 Takte Warten,bevor Enable wieder Low geht, und das bei 10 Mhz Quarz, es klappt.
Solange das nicht stört daß er immer 5ms wartet ist es auch gut oder ?

Gruß Sebastian

tml
15.08.2005, 09:45
Na ja, eigentlich stoert's nicht, es ist bloß so, dass der da ganz schoen lange brauch um so ein String aufs Display zu bringen. Ich probier's mal mit der Schleife aus, werde die aber 16 mal durchlaufen, weil ich einen 16MHz Quarz hab.

tml
15.08.2005, 10:05
Das funktioniert nicht ](*,) ! Leider. Da passiert folgendes: Die 2. Zeile verschwindet ganz und der Kontrast der ersten Zeile wird dafuer ungewoehnlich hoch, außerdem werden nur die letzten 2 Zeichen angezeigt, die ersten 14 fehlen, werden allerdings kurz sichtbar.
Ich hab "enable" so geaendert:


enable: push temp
ldi temp, 16
sbi PortC, E ;Enable-Pin -> H
enablea: dec temp
nop
nop
nop
nop
brne enablea
cbi PortC, E ;Enable-Pin -> L
pop temp
ret


Ob die vier nop's dabei sind oder nicht aendert nicht's.

izaseba
15.08.2005, 18:31
Die 2. Zeile verschwindet ganz und der Kontrast der ersten Zeile wird dafuer ungewoehnlich hoch

Und Du bist Dir sicher, daß Deine Hardware 100% in Ordnung ist :-k
das mit dem Kontrast kann man doch im Programm nicht verändern :-k
echt komisch

Gruß Sebastian

tml
15.08.2005, 21:39
Ich kann mir natuerlich nicht sicher sein, dass die Hardware 100% in Ordnug ist. So viel gibt's da allerdings ja auch nicht zu beschalten. Ich habe die ersten vier Datenleitungen des LCD's auf GND gelegt (wegen 4bit Modus) und die anderen an Pin0-3 von PortC angeschlossen (ohne extra Pull-Up) die 3 Steuerleitungen, also RW, RS und E, haengen dann an Pin4-6 und Pin7 ist freigelassen. Diesen Kontrasteinstellpin vom Display hab ich ueber den Mittelanschluss eines 10K-Trimmers angeschlossen. Der Trimmer sitzt zwischen Vcc und GND. Sonst ist nichts weiter am LCD. Kann's daran liegen, dass ich keine Kondensatoren eingebaut hab, also diese Abblockkondensatoren? Aber das werde ich sowieso noch aendern. Kann es eigentlich sein, dass die Geschwindigkeit des Display von der Betriebsspannung abhaengt? Die betraegt naemlich nur 4,90V. Aber das sollte doch nicht der Grund sein, oder?

izaseba
15.08.2005, 22:05
Ne, Du
so wie Du das beschrieben hast ist schon alles O.K.

nur der R/W..., liest Du irgendwo im Programm was vom LCD?
Habe nicht genau hingeguckt, aber ich glaube eher nicht.
Dann kannst Du ihm auch auf LOW legen, womit Du Dir ein Pin sparst.

Ich habe die ersten vier Datenleitungen des LCD's auf GND gelegt (wegen 4bit Modus)

Schlecht ist das nicht. mache ich auch so, aber es muß nicht sein, habe ich mir hier in Forum sagen lassen, Das Display hat interne Pulldowns, oder waren das Pullups :-&

Und die Spannung dürfte auch nicht die große Rolle spielen, mein Netzteil ist leider was schwach auf der Brust, und bei etwa 0,5 A Stromstärke bricht die Spannung soweit zusammen, daß ich noch kaum was auf dem Display lesen kann, gemessen habe ich sie noch nicht, aber das Display verhält sich ganz normal (bis auf die Helligkeit natürlich)

Gruß Sebastian

kater
15.08.2005, 22:20
Ne, die Geschwindogkeit haengt nicht von der Spannung hab. Wohl er von der eingestellen Baud Rate.

izaseba
15.08.2005, 22:28
Wohl er von der eingestellen Baud Rate

Baud Rate bei LCD ? :-k

Irr_Deto_Man
15.08.2005, 23:22
Hi,
ich beschäftige mich auch gerade seit ein paar Tagen mit Displays, und bei klappt es mit dem Enable fast ohne Wartezeit. Angeschlossen, wie oben beschrieben, ausser: die nicht benötigten Datenleitungen hab ich einfach freigelassen. Den Programmteil habe ich so gefunden.

; Gib Nibble in LCDchar an LCD aus
;
Lcd4Set:
out pLcdPort,LCDchar ; Byte auf Ausgabeport
nop
sbi pLcdPort,0 ; Setze Enable-Bit 0
nop
nop ; bei 10Mhz
nop ; bei 4 Mhz nur 2 Nop s
nop
nop
cbi pLcdPort,0 ; Enable Bit 0 löschen
nop
ret
Nach jeder Zeichenausgabe 5ms warten, wenn BusyFlag nicht ausgelesen wird.
Ich habe schon mehrere Displays ( 2 und 4 Zeilen) probiert, alle haben einwandfrei funktioniert. (hatte mal nen Display-Kaufrausch)

tml
16.08.2005, 09:33
Auslese tue ich wirklich nichts vom Display, ich wollte nur urspruenglich das Busy-Flag auslesen, hab das nur nicht hingekriegt :-$ . Wahrscheinlich muss das eingebaut Pulldowns haben, weil man D0-3 sonst nicht auf GND klemmen duerfte. Na ja, dann werde ich's erstmal bei den 5ms belassen und spaeter mal sehen.