Hallo Allerseits,
ich wuerd mich ueber ein wenig Hilfe zu meinem unten angefuegten Code
freuen ;]
Ich benutze einen ATTiny13 und compile so:
avr-gcc -g -mmcu=attiny13 -Wall -O2 main13.c -o main13.hex
Da ich keine Delays und dergleichen verwende denke ich, dass
es okay ist, wenn ich die Taktrate dem gcc nicht uebergebe.
Soweit richtig?
Das Programm soll eigentlich mit jeder Flanke an PB1 (da haengt
eine langsame Clock dran) den Ausgang PB4 mal kurz high schalten
und dann gleich wieder low. Es macht allerdings irgendwas voellig
anderes. Ich habe den Resetpin schon ueberprueft, der ist stabil
auf high. In den angefuegten Bildern sieht man die Messung mit
einem Logikanalysator:
Kanal0 - Clock vom Attiny
Kanal1 - langsames Clocksignal an PB1
Kanal2 - PB4
Kanal3 - Resetpin
Das Problem ist also, dass der Interrupt irgendwann ausgeloest
wird, aber nicht dann wenn er soll und merkwuerdigerweise noch
regelmaessig. Alle anderen Pins, die das verursachen koennten
liegen stabil auf high oder low, wo sie auch sein sollen.
Im Code sieht man, dass ich statt INT0 auch mal PCINT benutzt
habe, was zum gleichen Ergebnis fuehrte.
und hier der Code:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
// Interrupthandler - B1
5
ISR(INT0_vect){
6
PORTB=0b00010000;
7
PORTB=0b11100000;
8
}//*/
9
/*ISR(PCINT0_vect) {
10
}//*/
11
12
intmain(void){
13
// Ports konfigurieren
14
DDRB=0b00010101;
15
PORTB=0b00000000;
16
PORTB=0b00010000;// wird die Zeile weggelassen bleibt PB4 immer low
17
// Interrupts konfigurieren
18
MCUCR&=0b11111101;
19
MCUCR|=0b00000001;
20
GIMSK&=0b11011111;
21
GIMSK|=0b01000000;
22
//GIMSK |= 0b00100000;
23
//PCMSK |= 0b00000010;
24
// Interrupts an
25
sei();
26
27
while(1){
28
}
29
return0;
30
}
Ich hoffe irgendjemand findet einen haarstraeubenden Fehler im Code,
denn die Hardware scheints irgendwie nicht zu sein. ^^
> MCUCR &= 0b11111101;> MCUCR |= 0b00000001;> GIMSK &= 0b11011111;> GIMSK |= 0b01000000;
..such erst mal raus (und schreibs auch hin :-) was die einzelnen Bits
bedeuten, das will sich hier keiner freiwillig antun. Dann reden wir
weiter.
HTH
Haste Recht, hab ich nich dran gedacht ^^
> MCUCR &= 0b11111101;> MCUCR |= 0b00000001;
Laut Datenblatt ist MCUCR so aufgebaut:
7 6 5 4 3 2 1 0
– PUD SE SM1 SM0 – ISC01 ISC00
was ich da machen will ist ISC01 auf 0 setzen und ISC00 auf 1,
damit ich folgendes Verhalten bekomme:
Any logical change on INT0 generates an interrupt request.
> GIMSK &= 0b11011111;> GIMSK |= 0b01000000;
in GIMSK interessieren mich nur folgende Bits:
6 5
INT0 PCIE
PCIE setze ich auf 0 und INT0 auf 1 (External Interrupt Enable)
Ist die Erklaerung aufschlussreich, oder immer noch zu kryptisch?
Hallo, Felix!
Felix schrieb:> ISR(INT0_vect) {> PORTB = 0b00010000;> PORTB = 0b11100000;> }
Damit überschreibst Du Dir außer PB4 auch alle anderen Leitungen.
Kodiere Dir das besser als
1
PORTB|=(1<<PIN4);
2
PORTB&=~(1<<PIN4);
"PIN4" durch Deine Pin-Definition Deines Compilers ersetzen - arbeite
nicht mir avrgcc. Ersetze Deine kryptischen Bits gleich im Quelltext und
setze ihn nochmals rein, falls die Kiste weiterhin spinnt.
Gruß - Wolfgang
Danke dir Wolfgang. Was meinst du mit:
> arbeite nicht mir avrgcc
Welche Alternative gibt es dazu? (Ich arbeite unter Linux,
kann mir aber auch von jemandem nen Windowsrechner leihen).
Und warum soll ich den avr-gcc nicht nehmen?
Die Aenderungsvorschlaege habe ich mal in den Code eingebaut
und zwar an allen in Frage kommenden Stellen, damit es
einheitlich wird. Das Problem ist das gleiche, er tuts einfach
nicht, bzw. PB4 ist die ganze Zeit high und geht wie oben im
Anhang ab und an mal kurz auf low, allerdings in einem vollkommen
eigenen Rhythmus, der aber auch garnichts mit dem zu tun hat, was
an PB1 anliegt, der den Interrupt ausloesen soll.
Tippfehler; sollte heißen: "arbeite nicht mit avrgcc" und war nicht 2.
Person Sg. Imp., sondern 1. Pers. Sing. Ind.. 8-D
Jetzt sieht der Quelltext schon viel besser aus: lesbar. Es scheint
alles korrekt initialisiert zu sein.
Zwei mögliche Fehlerquellen fallen mir noch ein:
1. Der Compiler trägt Deine Interrupt-Routine nicht als ISR in die
Vektortabelle ein. Ist rel. unwahrscheinlich, da ja auf PB4
herumgezappelt wird.
2. Zwischen den beiden Zeilen innerhalb des ISRs liegt noch soviel Code,
den Du uns nicht mitgeteilt hast, daß ein ISR-Durchlauf zweieinhalb mal
soviel Zeit benötigt wie zwischen zwei Taktflanken Deines PB1 liegt.
Dann wird die ISR sofort wieder angesprungen, sobald sie beendet ist.
Das ließe sich auch damit feststellen, daß Du in der Hauptschleife
GIFR->INTF0 irgendwie ausgibst, z.B. auf einen Port-Anschluß.
Prüf das nochmal.
Gruß - Wolfgang
Wolfgang schrieb:> 2. Zwischen den beiden Zeilen innerhalb des ISRs liegt noch soviel Code,> den Du uns nicht mitgeteilt hast, daß ein ISR-Durchlauf zweieinhalb mal> soviel Zeit benötigt wie zwischen zwei Taktflanken Deines PB1 liegt.> Dann wird die ISR sofort wieder angesprungen, sobald sie beendet ist.
Ich lade das programm so runter, wie ichs hier gepostet habe.
> Das ließe sich auch damit feststellen, daß Du in der Hauptschleife> GIFR->INTF0 irgendwie ausgibst, z.B. auf einen Port-Anschluß.
Werd ich mal machen. Ich hab mal geschaut, ob ich generell die
Pins ansprechen kann und deswegen folgende Modifikation an
der Endlosschleife vorgenommen:
1
while(1){
2
PORTB|=(1<<PIN0);
3
}
Das Ergebnis ist im Anhang zu bestaunen. o_O
Kanal0: Clock
Kanal1: Signal an PB1 bzw INT0
Kanal2: PB4
Kanal3: PB0
Das ganze wiederholt sich regelmaessig in keinem erkennbaren Zusammehang
zum Signal an INT0/PB1. Ich aeussere mal eine Vermutung:
AVR startet -> alle Pins auf low. AVR setzt PB4 laut Programm auf high,
(siehe Bild), setzt die ganzen anderen Bits laut Programm, kommt dann
nach ein paar Clockcycles in die Endlosschleife und setzt PB0 auf
high (siehe Bild), danach crasht das Teil auf irgendein periodisch
wiederkehrendes Event hin und startet wieder von vorne.
Kann denn sowas sein? Ob ichs mal mit ner anderen Schaltung versuch?
Mal zur Hardware: beide Clocks, die schnelle und die langsame stammen
von einem Stereo-ADC. Der Attiny soll ein paar Shiftregistern dann
im richtigen Moment mitteilen, wann da drin valide Werte anzutreffen
sind. Die Stromversorgung kommt von einer USB-Leitung vom Rechner, ist
aber an einigen Stellen mit 1uF und 100nF Kondensatoren gefiltert.
Der Resetpin des Attiny ist ueber 10k an Vcc gelegt. Den ISP Programer
schliesse ich fuer die Messungen ab und trenne die Schaltung
mal kurz vom Strom, damit alles nochmal resettet wird. Die Shiftregister
sind noch nicht in ihren Fassungen drin, also ausser 1 Quarzoszi,
dem ADC und dem Attiny und besagten Filterkondensatoren ist nix
auf der Platine drauf.
Ich stehe vor einem Raetsel ^^
Jetzt hab ich mal grade noch folgendes mit der Endlosschleife
gemacht:
1
while(1){
2
if((GIFR&(1<<INTF0))!=0)
3
PORTB|=(1<<PIN0);
4
else
5
PORTB&=~(1<<PIN0);
6
}
Ergebnis: PB0 bleibt immer low.
oder das:
1
while(1){
2
PORTB|=(1<<PIN0);
3
PORTB|=(1<<PIN2);
4
}
Ergebnis: PB0 macht das gleiche wie im letzten Posting, PB2 bleibt immer
low.
Ich werd mal den Attiny wechseln und das ganze auf ner 2.
Platine aufbauen. Oder hat jemand nen besseren Vorschlag? ;]
Sachlich komme ich jetzt auch nicht viel weiter, also kurz
durchschnaufen. Vielleicht geht es dann wieder.
Was Du aber bis dann alles machen kannst: Der *Reset-Eingang (Anschluß
1, PB5) ist ganz sicher nicht mit einem anderen Anschluß gebrückt? Wie
ich bereits an anderer Stelle in diesem Forum ausführte, sind die AVRs
am *Reset-Eingang mit einem Pull-up-Widerstand ausgerüstet. Am Tiny13
ist es ein 60kR-Typ (30kR-80kR laut Datenblatt 2535I-AVR-05/08, S. 116).
Der 10k gegen +5V darf weg, dafür muß ein Kondensator (100n X7R
bevorzugt) gegen Masse geschaltet werden. Immer für saubere Rücksetzung
beim Kaltstart sorgen!
Du kannst auch einen Neustart des µCs auslösen, indem Du PB5 auf 0
programmierst.
Gruß - Wolfgang
Hoppla, Schnellschuß:
Das Datenblatt sagt zu INTF0 "The flag is cleared when the interrupt
routine is executed." Falls also nicht der wenig wahrscheinliche Fall
auftritt, die Hauptschleife so weit auszuführen, daß INTF0 als 1 erkannt
wird, bevor die ISR angesprungen wird und damit INTF0 gelöscht, wird
auch immer eine 0 'rauskommen.
Wolfgang schrieb:> Hoppla, Schnellschuß:>> Das Datenblatt sagt zu INTF0 "The flag is cleared when the interrupt> routine is executed." Falls also nicht der wenig wahrscheinliche Fall> auftritt, die Hauptschleife so weit auszuführen, daß INTF0 als 1 erkannt> wird, bevor die ISR angesprungen wird und damit INTF0 gelöscht, wird> auch immer eine 0 'rauskommen.
Stimmt ^^
ist aber auch erstmal egal, da das Ding ja aus irgend einem Grund
sowieso macht, was es will.
Danke dir fuer den Hinweis mit dem Resetpin, hab ich grad mal
umgeloetet,
tut aber auch keinen Unterschied :[
Ich werd jetzt erstmal wirklich ne 2. Platine aufbauen mit eigener
Stromversorgung und von der anderen wirklich nur das Signal rueberholen,
was den Interrupt ausloesen soll. Damit werd ich ne Weile beschaeftigt
sein. Ich lass heut abend mal von mir hoeren, inwiefern mein Treiben
erfolgreich war.
nochmals herzlichen Dank Wolfgang!
So jetzt bin ich einen Schritt weiter. Mein Messgeraet taugt nix ^^
Der Logikanalysator ist neu und extra fuer dieses Projekt besorgt.
Es ist ein Open Bench Logic Sniffer, den ich unter Linux mit der
OLS Software betreibe. Der zeigt mir immer nur 41us an und dann
wiederholt er die Anzeige. Soviel also zu dem merkwuerdigen
Takt, von dem ich nicht wusste woher er kommt. Leider war meine
langsame Clock grade irgendwie ein Teiler der Samplingclock,
mit der der Logic Sniffer sampelt, deswegen war der Anzeigefehler
nicht auf allen Kanaelen zu sehen.
Naja, es kann also erstmal weitergehen und ich kann mich wieder
dem eigentlichen Problem widmen, ausschliessen kann ich jetzt aber
einen Reset oder Neustart des Attinys :]
So, der Thread kann nicht gerade als "solved" markiert werden,
aber mit dem Assemblercode unten bekomme ich das Zeitverhalten,
das ich brauche ziemlich gut hin. Sollte es noch Probleme dabei
geben, hab ich immer noch die Moeglichkeit die Clock doppelt
so schnell zu machen. Schade, dass ich das mit dem C-Code nicht
hinbekomme. Auf die Idee mit Assembler bin ich gekommen, als ich
mal an den Compilerflags rumgefummelt hab, da hat sich jedes
Mal irgendwas geaendert und das kam mir spanisch vor. Bei der
Anwendung gehts um ganz exakte Zeiten und da ich leider von C
und den gcc flags nicht wirklich nen Plan habe bleib ich mal
bei Assembler. ^^
Im angehaengten Bild ist wieder
Kanal0: Clock
Kanal1: Interruptsignal
Kanal2/3: vom Interrupt gesteuerte Ausgaben
1
.include"tn13def.inc"
2
3
.defrmp=R16
4
.defrimp=R17
5
6
.cseg
7
.org$0000
8
9
rjmpmain
10
reti
11
rjmpintpcint
12
reti
13
reti
14
reti
15
reti
16
reti
17
reti
18
reti
19
20
intpcint:
21
nop;nopseinfuegenumdasTimingzukonfigurieren
22
nop
23
nop
24
nop
25
cbiPORTB,4
26
sbiPORTB,4
27
cbiPORTB,0
28
sbiPORTB,0
29
reti
30
31
main:
32
ldirmp,LOW(RAMEND)
33
outSPL,rmp
34
35
;HardwareInit
36
sbiDDRB,0;PB0alsAusgangdefinieren
37
sbiDDRB,2;PB2alsAusgangdefinieren
38
sbiDDRB,4;PB4alsAusgangdefinieren
39
cbiPORTB,0;PB0lowsetzen
40
cbiPORTB,2;PB2lowsetzen
41
cbiPORTB,4;PB4lowsetzen
42
cbiDDRB,1;PB1alsEingangdefinieren
43
44
;InterruptInit
45
ldirmp,0b00000010
46
outPCMSK,rmp;MaskierenderPinchangeinterrupts
47
ldirmp,0b00100000
48
outGIMSK,rmp;PCINT0Interruptszulassen
49
50
;Interruptan
51
sei
52
53
loop:
54
rjmploop
Zusammenfassung: solved durch Wechsel von C zu Assembler ^^