Hallo liebe Foren Community,
ich beschäftige mich gerade etwas mit mit einem AT90S2313 auf einem
aTeVaL Board und mir ist bewusst, dass der uC outdated ist. Ich habe mir
bereits das AVR-GCC Tutorial hier angeschaut, als auch aus anderen
Quellen Informationen gezogen. Dennoch bin ich etwas durcheinander.
Der AT90S2313 hat zwei Sleep Modi, den IDLE und Power-down Mode, soweit
sogut.
Um den, sagen wir mal Power-down Mode zu aktivieren, muss ich laut
Datenblatt (Datei angehängt) die SE (Sleep enable) und SM (Sleep mode)
im MCUCR (MCU Control Register) auf 1 setzen, wobei hierauf zu achten
ist, dass der SE erst kurz vor dem Sleep mode ausgeführt werden soll.
Laut meinem laienhaften Verständnis, müsste der Code also folgendermaßen
aussehen:
1
intmain(void){
2
3
DDRD=0b01100000;// Output = 1; Input = 0
4
MCUCR=0b00010000;// Sleep mode: power down
5
6
while(1){
7
LED_RD_ON;// Debugging
8
_delay_ms(1000);
9
LED_RD_OFF;
10
_delay_ms(1000);
11
12
MCUCR|=(1<<SE);// Enable sleep mode
13
sleep_mode();// Activate sleep mode
14
}
15
return0;
16
}
Jetzt lese ich aber im AVR-GCC Tutorial man müsse...
1
// set sleep mode
2
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
...setzen.
Hier nun die eigentliche Frage: Habe ich das denn nicht bereits durch
das setzen der Bits "eingestellt"?
[edit]
Ich glaube, ich habe es selbst herausgefunden.
Laut Library Reference setzt die Funktion sleep_mode(): This macro
automatically sets the sleep enable bit, goes to sleep, and clears the
sleep enable bit.
Und dann wird wohl durch die Funktion set_sleep_mode(<mode>) in dem Fall
das SM Bit gesetzt, richtig?
[/edit]
Beides sind verschiedene Dinge.
set_sleep_mode() legt fest, in welchen der mögliche Sleep-Modi (bei dir
sind es nur zwei, bei anderen MCUs mehr) das Teil schlafen gehen soll,
wenn man das nächste Mal sleep_mode() aufruft.
sleep_mode() kümmert sich wiederum um die Sequenz, die es benötigt, um
tatsächlich die CPU in den Schlaf zu versetzen.
Wenn du kein set_sleep_mode() aufrufst, dann ist der default sleep mode
"IDLE", d.h. die CPU legt sich zwar schlafen, aber alle Takte laufen
weiter.
Der Vorteil von set_sleep_mode() gegenüber dem manuellen "Herumhacken"
auf MCUCR (welches bei anderen MCUs anders heißen kann) ist halt, dass
1
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
deutlich besser ausdrückt, was beabsichtigt ist, als
Eine Frage noch bzgl. Sleep Mode, besser gesagt dem dazugehörigen
External Interrupt.
Wie im Eingangspost erwähnt, nutze ich einen AT90S2313. Weil mir das
jetzt nach Stunden zu bunt wurde, habe ich einen ATmega328P eingesetzt
und mit diesem Programm instant die gewünschte Funktion zum Laufen
gebracht.
Mit Taste an PD2 aktiviere ich den Power Down. Angezeigt wird mir das
duch eine LED an PD6. Mit dem aktivierten External Interrupt an PD3 wird
der uC wieder aufgeweckt.
1
ISR(INT1_vect){}
2
3
4
intmain(void)
5
{
6
DDRD=0b01100000;// Output = 1; Input = 0
7
PORTD=0b00011100;// Enable internal pull-up
8
9
while(1)
10
{
11
if(BUTTON_1_PRESSED)
12
{
13
// Debugging
14
LED_RD_ON;
15
_delay_ms(1000);
16
LED_RD_OFF;
17
18
// Pin change interrupt setup
19
cli();// Disable interrupt for programming
20
// PCICR |= (1<<PCIE2); //
21
// PCMSK2 |= (1 << PD3); // Turn on pin PB4, which is PCINT4
22
EICRA|=(1<<ISC11);
23
EICRA&=~(1<<ISC10);
24
EIMSK|=(1<<INT1);
25
sei();// Enable interrupt
26
27
// Activate sleep mode
28
set_sleep_mode(SLEEP_MODE_PWR_DOWN);// Sleep mode: Power down
29
sleep_mode();// Activate sleep mode
30
}
31
}
32
return0;
33
}
Anschließend habe ich die Register EICRA -> MCUCR und EIMSK -> GIMSK an
den AT90S2313 angepasst, aber es funktioniert trotzdem nicht.
Was ist daran bitte falsch?
1
ISR(INT1_vect)
2
{
3
}
4
5
6
intmain(void)
7
{
8
DDRD=0b01100000;// Output = 1; Input = 0
9
PORTD=0b00011100;// Enable internal pull-up
10
11
while(1)
12
{
13
if(BUTTON_1_PRESSED)
14
{
15
// Debugging
16
LED_RD_ON;
17
_delay_ms(1000);
18
LED_RD_OFF;
19
20
// Interrupt setup
21
cli();// Disable interrupt for programming
22
MCUCR|=(1<<ISC11);
23
MCUCR&=~(1<<ISC10);
24
GIMSK|=(1<<INT1);
25
sei();// Enable interrupt
26
27
// Activate sleep mode
28
set_sleep_mode(SLEEP_MODE_PWR_DOWN);// Sleep mode: Power down
Mirko schrieb:> ich beschäftige mich gerade etwas mit mit einem AT90S2313 auf einem> aTeVaL Board und mir ist bewusst, dass der uC outdated ist.
Der ist in der Tat seit 23 Jahren obsolet.
Der Nachfolger heißt ATtiny2313A.
Mirko schrieb:> Was ist daran bitte falsch?
Du mußt schon einen vollständigen Code posten, der auch compiliert.
Mirko schrieb:> Was ist daran bitte falsch?
Wenn ich deinen Code richtig deute, willst du auf eine fallende Flanke
des Externinterrupts reagieren.
Damit kannst du die CPU nicht aufwecken.
"Only an External Reset, a Watchdog Reset (if enabled), an external
level interrupt on INT0 or INT1 can wake up the MCU."
Die Betonung liegt auf external level interrupt.
Aufwachen per Pin-Change-Interrupt ging erst zwei AVR-Generationen
später.
Jörg W. schrieb:> Mirko schrieb:>> Was ist daran bitte falsch?>> Wenn ich deinen Code richtig deute, willst du auf eine fallende Flanke> des Externinterrupts reagieren.
Korrekt.
> Damit kannst du die CPU nicht aufwecken.> "Only an External Reset, a Watchdog Reset (if enabled), an external> level interrupt on INT0 or INT1 can wake up the MCU."> Die Betonung liegt auf external level interrupt.> Aufwachen per Pin-Change-Interrupt ging erst zwei AVR-Generationen> später.
Das im ATmega328 Programm noch Pinchange steht ist falsch. Ich habe das
nur als Vorlage genommen und die Register dem External Interrupt
angepasst. Die Pinchange Register sind auch auskommentiert.
External Level Interrupt... das ist doch ein External Interrupt mit
einer sich ändernden (Falling/Rising) Flanke/Level?
Mirko schrieb:> External Level Interrupt... das ist doch ein External Interrupt mit> einer sich ändernden (Falling/Rising) Flanke/Level?
Nein, eben nicht. Ein pegelgesteuerter Interrupt, kein
flankengetriggerter. Ist übrigens die Voreinstellung im MCUCR beim
AT90S2313.
Außerdem steht noch da, dass der (Low-)Pegel lange genug anliegen muss,
bis der Oszillator und die CPU gestartet sind. Aber das sollte bei einem
mit der Hand betätigten Taster kein Problem sein.
Hintergrund ist einfach, dass die Flankenerkennung einen Takt benötigt,
den du im power-down mode nicht hast.
Jörg W. schrieb:> "Only an External Reset, a Watchdog Reset (if enabled), an external> level interrupt on INT0 or INT1 can wake up the MCU."
Ja, das ist der Unterschied zum ATmega328P.
Peter D. schrieb:> Ja, das ist der Unterschied zum ATmega328P.
So halb: ein „normaler“ Externinterrupt muss auch dort low-level sein
zum Aufwachen. Allerdings gehört er eben besagter übernächster
Generation AVRs an, die einen pin-change interrupt haben (der separat
vom normalen Externinterrupt ist), und dieser kann ebenfalls die MCU aus
dem power-down aufwecken.
Peter D. schrieb:> Jörg W. schrieb:>> So halb: ein „normaler“ Externinterrupt muss auch dort low-level sein>> zum Aufwachen.>> Nö.
"Only an External Reset, a Watchdog System Reset, a Watchdog Interrupt,
a Brown-out Reset, a 2-wire Serial Interface address match, an external
level interrupt on INT0 or INT1, or a pin change interrupt can wake up
the MCU."
INT0/INT1 also nach wie vor level-only.
(Datenblatt 10.5 Power-down Mode)
PS: Ab AVR0 hat sich da wirklich was getan, aber wie ich gerade
feststellen musste, war ich auch hier für ein aktuelles Projekt
geringfügig zu blauäugig und hätte besser vorher ins Datenblatt schauen
müssen. Dort wird zwischen "fully asynchronous pins" und "partially
asynchronous pins" unterschieden. Letztere können allerdings zusätzlich
zum level-triggered interrupt jetzt auch mit (dem neu hinzu gekommenen)
"both edges" Interrupt aufwachen.
Also kann man final sagen, so wie ich mir das vorstelle funktioniert es
nicht.
Und wie kann ich diesen pegelgesteuerten Externen Level Interrupt
"nutzen"?
Mirko schrieb:> Und wie kann ich diesen pegelgesteuerten Externen Level Interrupt> "nutzen"?
Indem du ihn konfigurierst (d.h. die entsprechenden Bits in MCUCR auf 0
lässt) und dann auslöst. Am einfachsten also sicher, indem du den
internen Pullup benutzt und den Pin mit dem Taster auf Low ziehst.
Du musst dann aber auch in der ISR gucken, dass du ihn abschaltest und
erst nach einer Wartezeit wieder aktiviert, und nachdem der Pin wieder
"high" ist.
Jörg W. schrieb:> Indem du ihn konfigurierst (d.h. die entsprechenden Bits in MCUCR auf 0> lässt) und dann auslöst. Am einfachsten also sicher, indem du den> internen Pullup benutzt und den Pin mit dem Taster auf Low ziehst.
Wo steht das, mit den Voreinstellungen? Ich finde es nicht :X
[edit]
Hab es in der Tabelle 5 selbst gefunden...
[/edit]
> Du musst dann aber auch in der ISR gucken, dass du ihn abschaltest und> erst nach einer Wartezeit wieder aktiviert, und nachdem der Pin wieder> "high" ist.
Hast du vielleicht ein Beispiel?
Mirko schrieb:>> Du musst dann aber auch in der ISR gucken, dass du ihn abschaltest und>> erst nach einer Wartezeit wieder aktiviert, und nachdem der Pin wieder>> "high" ist.>> Hast du vielleicht ein Beispiel?
Auf Anhieb nicht.
In der ISR musst du das Bit in GIMSK zurück nehmen. Bevor du es wieder
setzt, musst du warten, bis der Pin (ausreichend lange) "high" war.
Ansonsten rennt deine ISR einfach nur Kreise, solange der low-Pegel
anliegt.
Jörg W. schrieb:> In der ISR musst du das Bit in GIMSK zurück nehmen. Bevor du es wieder> setzt, musst du warten, bis der Pin (ausreichend lange) "high" war.>> Ansonsten rennt deine ISR einfach nur Kreise, solange der low-Pegel> anliegt.
Jep. Das ist eine Falle, in die viele Anfänger tappen. Ein
levelgesteuerter Interrupt feuert, solange der aktive Level beibehalten
wird. Man sieht das aber nicht gleich, weil Atmel (gerade deswegen) beim
Einsprung in die ISR (jede ISR) erstmal jegliche Interrupts sperrt.
Sonst würde sich die ISR nämlich gleich wieder selber unterbrechen und
bei 1MHz+ CPU-Takt wäre der Stack ratzfatz übergelaufen.
Jörg W. schrieb:> "Only an External Reset, a Watchdog System Reset, a Watchdog Interrupt,> a Brown-out Reset, a 2-wire Serial Interface address match, an external> level interrupt on INT0 or INT1, or a pin change interrupt can wake up> the MCU."
Aber nur beim AT90S2313, ATTiny2313A.
Beim ATmega328P fehlt diese Einschränkung und deshalb funktioniert der
Code dort. Siehe obige Table 10-1 aus dem Datenblatt.
Peter D. schrieb:> Siehe obige Table 10-1 aus dem Datenblatt.
Siehe mein Zitat aus dem Datenblatt des ATmega328P. Dem trau ich mehr
Detailtreue zu als einer zusammenfassenden Tabelle.
Die Tabelle besagt ja lediglich, dass INT0, INT1 und
Pin-Change-Interrupts überhaupt die CPU aufwecken – aber nicht, unter
welchen Bedingungen.
Dass ein INT0 oder INT1 die CPU aufwecken kann, ist wiederum auch beim
AT90S2313 der Fall.
Jörg W. schrieb:> Die Tabelle besagt ja lediglich, dass INT0, INT1 und> Pin-Change-Interrupts überhaupt die CPU aufwecken – aber nicht, unter> welchen Bedingungen.
Die Tabelle ist da eindeutig, X bei Power-Down.
Außerdem wir das nochmal explizit erklärt:
"13. External Interrupts
Low level interrupts and the edge interrupt on INT2:0 are detected
asynchronously. This implies that these interrupts can be used for
waking the part also from sleep modes other than Idle mode."
Und sein ATmega328P Code funktioniert ja mit falling edge.
Peter D. schrieb:> Die Tabelle ist da eindeutig, X bei Power-Down.
Nö, das ist nicht eindeutig, denn dass ein Externinterrupt aufwecken
kann, war schon immer so.
> Außerdem wir das nochmal explizit erklärt:> "13. External Interrupts> Low level interrupts and the edge interrupt on INT2:0 are detected> asynchronously. This implies that these interrupts can be used for> waking the part also from sleep modes other than Idle mode."
Das wiederum akzeptiere ich – allerdings steht es im Widerspruch zu
Abschnitt 10.5 des gleichen Datenblatts, aus dem ich oben zitiert habe.
Interessant, dass solche Fehler noch nach so vielen Jahren da drin sind
…
Mirko schrieb:> Hier nun die eigentliche Frage:
Ergänzend eine Frage, die Du noch nicht gestellt hast:
"Braucht der AT90S2313 ein zusätzliches /Reset-IC, welches beim
Abschalten den µC sperrt?"
Unbedingt, sonst kann er sich ab und zu den Programmspeicher/EEPROM
löschen! (MC34164, TS809)
Mi N. schrieb:> Unbedingt
Naja. Nein, nicht unbedingt.
Wenn man den EEPROM benutzt, könnte es wohl maximal passieren, dass
statt der gewünschten Zelle die von Adresse 0 zerschossen wird, wenn
während des Schreibens die Spannung wegbricht.
Oder worauf wolltest du hinaus?
Da das Ganze aber (so wie ich es verstehe) eh nur ein Spiel- und
Bastel-Board ist, dürfte das alles gar keine Rolle spielen.
Die ersten AVRs (AT90S) hatten keine Spannungsüberwachung, sondern nur
ein einfaches Zeitglied als Reset.
Als ich das bei einer Produktvorstellung gegenüber Haakon Skar
bemängelte, hat er nur abgewinkt. Ich habe daraufhin mein AVR-Projekt
beendet und erst weiter mit den AVRs gebastelt, als dann doch das
Brownout-Reset implementiert wurde.
Die ersten AVRs hatten massive Probleme, die Fusebits richtig
einzulesen, wenn die VCC nicht schnell und monoton von 0V anstieg. Da
half dann auch kein externer Reset-IC, wenn statt des internen Taktes
auf eine externe Taktquelle gewartet wurde.
Peter D. schrieb:> Die ersten AVRs hatten massive Probleme, die Fusebits richtig> einzulesen, wenn die VCC nicht schnell und monoton von 0V anstieg.
Klar, aber entgegen obiger Behauptung löschen sie sich nicht EEPROM oder
Flash. Außerdem hat man gerade bei einem Bastel-Board das ja in der
Hand, dass der Spannungsanstieg schnell genug ist.
In irgendeinem Seriengerät wiederum wird wohl heute keiner mehr einen
AT90S2313 einsetzen.
Jörg W. schrieb:> Klar, aber entgegen obiger Behauptung löschen sie sich nicht EEPROM oder> Flash.
Gut, dann formuliere ich anders: Sie funktionieren nicht mehr ;-)
Woran das wohl liegen mag?
Mi N. schrieb:> Jörg W. schrieb:>> Klar, aber entgegen obiger Behauptung löschen sie sich nicht EEPROM oder>> Flash.>> Gut, dann formuliere ich anders: Sie funktionieren nicht mehr ;-)> Woran das wohl liegen mag?
Bleibt trotzdem eine zumindest missverständliche Behauptung: sie
funktionieren ja nur bei zu langsamem Spannungsanstieg unter den
gegebenen Umständen nicht. Wenn du sie danach "normal" betreibst,
funktionieren sie.
Für irgendeine Bastelplatine halte ich ein separates Reset-IC für
komplett überflüssig, trotz der genannten potenziellen Probleme. (Ich
habe auch selbst bei keinem AVR je eins benutzt, nichtmal bei den ersten
AT90S1200 damals.)
@Jörg W.
Vielen Dank für die hilfreichen Hinweise. Damit habe ich glaube ich nun
das Problem lösen können.
Das Programm verhält sich wie gewünscht...
Wie vorhin bereits beschrieben, mit Taste 1 PD2 geht die LED PD6 für 1s
an, danach verfällt der uC in den Power-Down Sleep Mode. Eine weitere
Betätigung von Taste 1 bringt nichts mehr. Erst wenn ich Taste 2 PD3
drücke, kann ich mit PD2 wieder die LED/Sleep Mode aktivieren.
Wäre es noch möglich wenn vielleicht jemand den Code so überblicken
könnte, ob etwas falsch ist oder ergänzt werden sollte?
Ich war mir nicht sicher z.B., ob es sinnvoll ist, den Interrupt 1 Sense
Control Low level aktiv auf 0 zu setzen, oder lieber einfach
wegzulassen. Wobei dann vieleicht nicht klar ist was gewünscht ist...
wenn ihr mich versteht, so zum Codeverständnis wenn man sich das mal
später wieder durchlesen sollte.
Diesmal auch den kompletten Code zum compilieren @peda.
Btw, ich wußte gar nicht, dass du DER Peter D. bist... jetzt weiß ich es
^^
Jörg W. schrieb:>> Gut, dann formuliere ich anders: Sie funktionieren nicht mehr ;-)>> Woran das wohl liegen mag?>> Bleibt trotzdem eine zumindest missverständliche Behauptung: sie> funktionieren ja nur bei zu langsamem Spannungsanstieg unter den> gegebenen Umständen nicht. Wenn du sie danach "normal" betreibst,> funktionieren sie.
Nein, wenn sie einmal nicht mehr liefen, liefen sie anschließend erst
wieder nach Neuprogrammierung.
Wenn ich dem TO einen Reset-Baustein empfehle, dann in der Hoffnung, daß
er diese Erfahrung nicht selber machen muß und an völlig anderen Stellen
nach einem Fehler sucht. Ein ähnlicher 'Pferdefuß' war UART mit internem
RC-Takt.
Mi N. schrieb:> Nein, wenn sie einmal nicht mehr liefen, liefen sie anschließend erst> wieder nach Neuprogrammierung.
Habe ich nie erlebt. Verpfuschte Fuses bei missglückten
Programmierversuchen waren was anderes, aber da hat man ja vorsätzlich
die Programmierung eingeleitet.
> Ein ähnlicher 'Pferdefuß' war UART mit internem> RC-Takt.
Der AT90S2313 hat weder UART noch internen RC-Oszillator.
Peter D. schrieb:> Jörg W. schrieb:>> Der AT90S2313 hat weder UART noch internen RC-Oszillator.>> - Full Duplex UART
OK, sorry, hätte ich nochmal nachlesen sollen. ;-) Aber RC-Oszillator
hat er nicht, hatte ich nachgelesen … Damals musste man noch mindestens
einen Resonator dranbammeln, weshalb auch die ersten Lowcost-Programmer
sowas an Bord hatten.