PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ATtiny15 in Simulation wacht auf, bei Hardware nicht



rogerberglen
17.09.2019, 18:10
Wie der Titel schon sagt, im Simulator funktioniert das mit dem Sleep (PowerDown-Modus). Der Prozessor hält an. Und bei einer Änderung am INT0-Eingang (Taster gegen 0 mit internen PullUp-Widerstand) Pinchange-Interrupt wacht der Prozessor auf und arbeitet weiter.
Aber in der realen Schaltung tut sich nichts. Kein Aufwecken.
Im Programm habe ich zum Testen des Restes mal die Sleeps auskommentiert.

Hier mal der bisherige Quellcode:




.include "TN15def.inc" ; Prozessor ATtiny15



.cseg ; Kennung für Programmcode


.def TMP = R0 ; Allgemeine Variable für Rückgabewerte
.def TMP1 = R16 ; Allgemeine Variable
.def Status = R20 ; Statusregister für Betriebszustände
.def Helligkeit = R21 ; Wert für PWM Regelung
.def KeyOld = R26 ; Taster die gedrückt waren
.def KeyNew = R27 ; Taster die gedrückt sind
.def KeyEnter = R28 ; Taster die neu gedrückt wurden
.def KeyExit = R29 ; Taster die neu losgelassen wurden
.def ZL = R30 ; 16-Bit Variable L-Byte
.def ZH = R31 ; 16-Bit Variable H-Byte


; Status 7 6 5 4 3 2 1 0
; ^- 0=Lampe aus, 1=Lampe an




.org 0x0000 ; Programm Startadresse $0000


rjmp Init ; Einsprung ins Hauptprogramm


.org 0x0001 ; Interrupt Pin 7 (INT0)


rjmp Test ; Sprung zur Testroutine


Init:


; ************************************************** *****
; * Internen Oszillator kalibrieren *
; ************************************************** *****



ldi ZL, low (2*Kalibrierung) ; Low-Byte Endadresse Flashspeicher lesen
ldi ZH, high(2*Kalibrierung) ; High-Byte Endadresse Flashspeicher lesen
lpm ; Kalibrierungsbyte auslesen
ser ZL ; $FF in ZL setzen für Vergleich
cpse TMP, ZL ; Kalibrierungsbyte gültig? (Nein, wenn $FF)
out OSCCAL, TMP ; Ja, dann Chip kalibrieren und danach
clr ZL ; den Vergleich löschen.
mov Status, ZL ; Statusregister löschen.
in TMP1, MCUCR ; Controllregister des Prozessors einlesen
sbr TMP1, 1<<ISC00 ; PowerDown-Modus freischalten
out MCUCR, TMP1 ; und speicehrn.


; ************************************************** *****
; * Ports des ATtiny15 einstellen *
; ************************************************** *****


ldi TMP1, 1<<DDB4 | 1<<DDB3 | 1<<DDB1 ; Pin 2, 3, 6 auf Ausgabe schalten.
out DDRB, TMP1 ; schalten und entsprechende
com TMP1
out PORTB, TMP1 ; PullUp-Widerstände einschalten.
in TMP1, PORTB ; Aktuellen Portinhalt einlesen und
ori TMP1, 0b011000 ; grüne + rote LED ausschalten
out PORTB, TMP1 ; neuen Zustand ausgeben.


; ************************************************** *****
; * Interrupts freigeben *
; ************************************************** *****


in TMP1, GIMSK ; Interrupt an INT0 (Taster Aus/Ein) freigeben
sbr TMP1, 1<<INT0
out GIMSK, TMP1 ; und speichern.
sei ; Interrupts freigeben.
in TMP1, MCUCR
sbr TMP1, 1<<SE | 1<<SM1
out MCUCR, TMP1
; sleep


; >>>>>>> Hauptprogramm Anfang <<<<<<<


Start:


rcall KeyCheck ; Tasten abfragen
cpi KeyExit, 0x04 ; Taste "Ein/Aus" gedrückt $04
brne Weiter1 ; Nein, dann weiter, sonst
rcall PinInt0 ; Sprung nach Ein- Ausschaltroutine


Weiter1:


rjmp Start


; >>>>>>>> Hauptprogramm Ende <<<<<<<<








; >>>>>>>> INTERRUPTPROGRAMME <<<<<<<<




; ************************************************** *****
; * Testinterrupt um PowerDown-Mode zu beenden *
; ************************************************** *****


Test:


nop
reti


PinInt0:


; ************************************************** *****
; * Ein- / Ausschalter $04 an INT0 *
; ************************************************** *****


cpi Status, 0x00 ; Lampe ausgeschaltet?
breq LampeEin ; Dann Lampe einschalten
cbr Status, 1 ; Ist die Lampe an? Dann Lampe aus und
in TMP1, PORTB
sbr TMP1, 0b001000
out PORTB, TMP1
; in TMP1, MCUCR ; Prozessorcontrollregister auslesen um
; sbr TMP1, 1<<SE | 1<<SM1 ; PowerDown-Mode zu aktivieren
; out MCUCR, TMP1 ; Speichern.
; sleep ; Prozessor in PowerDown-Mode versetzen.
reti ; Rücksprung.

LampeEin:


sbr Status, 1 ; Kennung für Lampe an setzen


; --------- TEST -----------


in TMP1, PORTB
cbr TMP1, 0b001000
out PORTB, TMP1
reti


; >>>>>>>>>> UNTERPROGRAMME <<<<<<<<<<

; ************************************************** *****
; * Tasterabfrage mit Entprellung *
; ************************************************** *****
; * Keyenter (R28) = Rückgabe neu gedrückte Taste *
; * Keyexit (R29) = Rückgabe der losgelassenen Taste *
; * Taste an PB0 (Hell/Dunkel) = 01 *
; * Taste an PB2 (Ein/Aus) = 04 *
; ************************************************** *****


KeyCheck: ; Unterprogramm zur Tastaturabfrage


ldi KeyEnter, 0
ldi KeyExit, 0
in KeyNew, PINB ; Lade PB
com KeyNew ; invertieren
andi KeyNew, 0b000101 ; Maskieren der nicht verwendeten Pins
cpse KeyOld, KeyNew ; Test ob Veränderung
rjmp KeyAction ; Veränderung
ret
; alles gleich
KeyAction:


rcall Wait12ms ; etwas warten
in ZL, PINB ; nochmal einlesen
com ZL ; invertieren bei neg. Logik
andi ZL, 0b000101 ; maskieren der nicht verwendeten Pins
cpse KeyNew, ZL ; ist es stabil
ret ; war nix, da nicht stabil

mov KeyEnter, KeyOld
com KeyEnter ; invertieren
and KeyEnter, KeyNew ; steigende Flanken, !alt & neu
mov KeyExit, KeyNew
com KeyExit ; invertieren
and KeyExit, KeyOld ; fallende Flanken, alt & !neu
mov KeyOld, KeyNew ; alt := neu
ret ; Interrupt verlassen


; ************************************************** *****
; * Warteschleife mit ca. 12ms *
; ************************************************** *****


Wait12ms:


ldi ZL, low (2500) ; 16-Bit Zähler mit Startwert laden
ldi ZH, high(2500) ; für Taktfrequenz 1.6MHz


WaitMs1:


dec ZL ; Low-Byte des Zählers erniedrigen
brne WaitMs1 ; wenn 0, dann
dec ZH ; High-Byte des Zählers erniedrigen
brne WaitMs1 ; wenn auch0, dann Warteschleife
ret ; verlassen.






Kalibrierung: .db 0x79 ; Kalibrierungswert für int. Oszillator


.exit

rogerberglen
22.09.2019, 14:10
Hat keiner eine Idee woran das liegen könnte? Probiere jetzt schon seit 3 Tagen das hinzubekommen. Leider ohne Erfolg. Prozessor wacht nicht mehr auf.

Ceos
23.09.2019, 07:51
Mein bascom ist quasi non-existent, also kann ich nciht erkennen wie dein INT0 konfiguriert ist, aber aus dem Sleep bekommst du ihn nur mit dem LOW LEVEL Interrupt (und das low muss auch etwas länger sein als es gewöhnlich für den Interrupt braucht) um die CPU vollständig zu wecken.

rogerberglen
23.09.2019, 18:24
Danke für den Hinweis mit dem Low-Level. habe ich jetzt so umgesetzt und es funktioniert. Laut dem Datenblatt steht bei PowerDown-Modus, dass sich dieser wohl auch mit PinChange aufwecken liese, aber das hat nicht funktioniert.
Hier der Quellcode, so wie ich es jetzt umgesetzt habe:


.include "TN15def.inc" ; Prozessor ATtiny15



.cseg ; Kennung für Programmcode


.def TMP = R0 ; Allgemeine Variable für Rückgabewerte
.def TMP1 = R16 ; Allgemeine Variable
.def Status = R20 ; Statusregister für Betriebszustände
.def Helligkeit = R21 ; Wert für PWM Regelung
.def KeyOld = R26 ; Taster die gedrückt waren
.def KeyNew = R27 ; Taster die gedrückt sind
.def KeyEnter = R28 ; Taster die neu gedrückt wurden
.def KeyExit = R29 ; Taster die neu losgelassen wurden
.def ZL = R30 ; 16-Bit Variable L-Byte
.def ZH = R31 ; 16-Bit Variable H-Byte


; Status 7 6 5 4 3 2 1 0
; |_ 0=Lampe aus, 1=Lampe an




.org 0x0000 ; Programm Startadresse $0000


rjmp Init ; Einsprung ins Hauptprogramm


.org 0x0001 ; Interrupt Pin 7 (INT0)


rjmp Int0i ; Sprung zu INT0-Interrupt


Init:


; ************************************************** *****
; * Internen Oszillator kalibrieren *
; ************************************************** *****



ldi ZL, low (2*Kalibrierung) ; Low-Byte Endadresse Flashspeicher lesen
ldi ZH, high(2*Kalibrierung) ; High-Byte Endadresse Flashspeicher lesen
lpm ; Kalibrierungsbyte auslesen
ser ZL ; $FF in ZL setzen für Vergleich
cpse TMP, ZL ; Kalibrierungsbyte gültig? (Nein, wenn $FF)
out OSCCAL, TMP ; Ja, dann Chip kalibrieren und danach
clr ZL ; den Vergleich löschen.


; ************************************************** *****
; * Statusregister löschen und PowerDown vorbereiten *
; ************************************************** *****


mov Status, ZL ; Statusregister löschen.
in TMP1, MCUCR ; Controllregister des Prozessors einlesen
cbr TMP1, 1<<ISC01 | 1<<ISC00 ; Interrupt an INT0 auf Low-Level stellen
out MCUCR, TMP1 ; und speichern.
in TMP1, TCCR1 ; Timer1 Kontrollregister für PWM
sbr TMP1, 1<<PWM1 | 1<<CS12 | 1<<CS11 | 1<<CS10 ; vorbereiten und
out TCCR1, TMP1 ; speichern..


; ************************************************** *****
; * Ports des ATtiny15 einstellen *
; ************************************************** *****


ldi TMP1, 1<<DDB4 | 1<<DDB3 | 1<<DDB1 ; Pin 2, 3, 6 auf Ausgabe schalten.
out DDRB, TMP1 ; schalten und entsprechende
com TMP1
out PORTB, TMP1 ; PullUp-Widerstände einschalten.
in TMP1, PORTB ; Aktuellen Portinhalt einlesen und
ori TMP1, 0b011000 ; grüne + rote LED ausschalten
out PORTB, TMP1 ; neuen Zustand ausgeben.
ldi Helligkeit, 0xC0 ; Startwert 40% Helligkeit


; ************************************************** *****
; * Interrupts freigeben *
; ************************************************** *****


in TMP1, GIMSK ; Interrupt an INT0 (Taster Aus/Ein) freigeben
sbr TMP1, 1<<INT0
out GIMSK, TMP1 ; und speichern.
sei ; Interrupts freigeben.
rcall PowerDown ; Prozessor in PowerDown-Modus versetzen.



; >>>>>>> Hauptprogramm Anfang <<<<<<<


Start:


rcall KeyCheck ; Tasten abfragen
cpi KeyExit, 0x01 ; Taste Helligkeit gedrückt $01
brne Taste1 ; Nein, dann nächste Taste.
tst Status ; Ist die Lampe ausgeschaltet? Ja, dann
breq TastEnde ; nicht Taste heller/dunkler auswerten.
rcall Dimmer ; Sprung nach Dimmroutine
rjmp TastEnde ; Spung an Auswerteende.


Taste1:


cpi KeyExit, 0x04 ; Taste "Ein/Aus" gedrückt $04
brne TastEnde ; Nein, dann weiter, sonst
rcall EinAus ; Sprung nach Ein- Ausschaltroutine


TastEnde:


rjmp Start


; >>>>>>>> Hauptprogramm Ende <<<<<<<<








; >>>>>>>> INTERRUPTPROGRAMME <<<<<<<<




; ************************************************** *****
; * INT0-Interrupt *
; ************************************************** *****


Int0i:


in TMP1, GIMSK ; Interrupt-Freigaberegister einlesen und
cbr TMP1, 1<<INT0 ; INT0-Interrupt sperren um Prozessor
out GIMSK, TMP1 ; beim Aufwachen nicht zu stören.
reti ; Rücksprung.






; >>>>>>>>>> UNTERPROGRAMME <<<<<<<<<<

; ************************************************** *****
; * Tasterabfrage mit Entprellung *
; ************************************************** *****
; * Keyenter (R28) = Rückgabe neu gedrückte Taste *
; * Keyexit (R29) = Rückgabe der losgelassenen Taste *
; * Taste an PB0 (Hell/Dunkel) = 01 *
; * Taste an PB2 (Ein/Aus) = 04 *
; ************************************************** *****


KeyCheck: ; Unterprogramm zur Tastaturabfrage


ldi KeyEnter, 0
ldi KeyExit, 0
in KeyNew, PINB ; Lade PB
com KeyNew ; invertieren
andi KeyNew, 0b000101 ; Maskieren der nicht verwendeten Pins
cpse KeyOld, KeyNew ; Test ob Veränderung
rjmp KeyAction ; Veränderung
ret
; alles gleich
KeyAction:


rcall Wait12ms ; etwas warten
in ZL, PINB ; nochmal einlesen
com ZL ; invertieren bei neg. Logik
andi ZL, 0b000101 ; maskieren der nicht verwendeten Pins
cpse KeyNew, ZL ; ist es stabil
ret ; war nix, da nicht stabil

mov KeyEnter, KeyOld
com KeyEnter ; invertieren
and KeyEnter, KeyNew ; steigende Flanken, !alt & neu
mov KeyExit, KeyNew
com KeyExit ; invertieren
and KeyExit, KeyOld ; fallende Flanken, alt & !neu
mov KeyOld, KeyNew ; alt := neu
ret ; Interrupt verlassen




Dimmer:


; ************************************************** *****
; * Taster für Dimmstufen $01 *
; ************************************************** *****


subi Helligkeit, 0x40 ; Bei jedem Aufruf Helligkeitswert -40
out OCR1A, Helligkeit ; Neuen wert ins PWM-Vergleichsregister
ret ; Lampe wird heller. Rücksprung




EinAus:


; ************************************************** *****
; * Ein- / Ausschalter $04 an INT0 *
; ************************************************** *****


cpi Status, 0x00 ; Lampe ausgeschaltet?
breq LampeEin ; Dann Lampe einschalten, sonst im
cbr Status, 1 ; Statusregister Lampe ein löschen..
in TMP1, PORTB ; PortB einlesen und.
sbr TMP1, 0b001000 ; LED grün durch H-Pegel ausschalten.
out PORTB, TMP1 ; PortB ausgeben.
in TMP1, TCCR1 ; PWM-Timer Steuerregister laden und
cbr TMP1, 1<<COM1A1 | 1<<COM1A0 | 1<<CS12 | 1<<CS11 | 1<<CS10 ; diesen ausschalten.
out TCCR1, TMP1 ; Alles Speichern.
in TMP1, PORTB ; Falls Scheinwerfer-LED Ausgang geschaltet
cbr TMP1, 1<<PORTB1 ; ist, diesen auf jeden Fall ausschalten.
out PORTB, TMP1 ; LED wird sonst zerstört!
in TMP1, GIMSK ; Vor PowerDown-Modus Interrupt
sbr TMP1, 1<<INT0 ; INT0 wieder freigeben. Über diesen wird
out GIMSK, TMP1 ; der Prozessor aufgeweckt.
rcall PowerDown ; PowerDown-Modus aktivieren.
ret ; Rücksprung.



LampeEin:


sbr Status, 1 ; Kennung für Lampe an setzen
ldi TMP1, 0xA0 ; LED-Scheinwerfer ein mit ca. 60% Helligkeit
out OCR1A, Helligkeit ; Wert in Timer-Vergleichsregister laden.
out TCNT1, TMP1 ; Timercounter ebenfalls laden.
in TMP1, TCCR1 ; Und Timer im PWM-Modus
sbr TMP1, 1<<COM1A1 | 1<<COM1A0 | 1<<CS12 | 1<<CS11 | 1<<CS10 ; starten.
out TCCR1, TMP1 ; Alles im Timer-Steuerregister speichern.







; --------- TEST -----------


in TMP1, PORTB ; PortB einlesen und LED grün durch Ausgabe
cbr TMP1, 0b001000 ; von L-Pegel einschalten.
out PORTB, TMP1 ; PortB ausgeben.
ret ; Rücksprung.




; ************************************************** *****
; * Warteschleife mit ca. 12ms *
; ************************************************** *****


Wait12ms:


ldi ZL, low (2500) ; 16-Bit Zähler mit Startwert laden
ldi ZH, high(2500) ; für Taktfrequenz 1.6MHz


WaitMs1:


dec ZL ; Low-Byte des Zählers erniedrigen
brne WaitMs1 ; wenn 0, dann
dec ZH ; High-Byte des Zählers erniedrigen
brne WaitMs1 ; wenn auch0, dann Warteschleife
ret ; verlassen.


; ************************************************** *****
; * Prozessor in PowerDown-Modus versetzen *
; ************************************************** *****


PowerDown:


in TMP1, MCUCR ; Prozessorcontrollregister auslesen um
sbr TMP1, 1<<SE | 1<<SM1 ; PowerDown-Mode zu aktivieren
out MCUCR, TMP1 ; Speichern.
sleep ; Prozessor in PowerDown-Mode versetzen
ret ; Nach Aufwecken Rücksprung




Kalibrierung: .db 0x79 ; Kalibrierungswert für int. Oszillator




.exit

avr_racer
29.09.2019, 14:26
Wenn PinChange den AVR aus den SLEEPmode holen soll, muss auch PINCHANGE aktiviert sein

GIMSK -> PCINT aktivieren seite 19/20

POWER-DOWN lesen Seite 24

http://ww1.microchip.com/downloads/en/devicedoc/doc1187.pdf

Ceos
30.09.2019, 07:50
@avr_racer sofern ich das bascom richtig deute, hat er exakt das gemacht

Das Problem ist ein technisches, irgendwas in dem Wakeup dauert bei einem Pin Change Interrupt zu kurz und löst deswegen nicht erfolgreich den WakeUp aus (ich kann nur das Errata dazu nicht mehr finden)

avr_racer
30.09.2019, 19:38
@coes Bascom ?? Er schreibt es doch in ASM und nur darauf bin ich eingegangen. Deine Aussage findest sich in meinen ersten POST im LINK Power Down Seite 24 ;)

Ceos
01.10.2019, 07:49
Bascom und ASM sehen für mich gleichartig aus, sorry für das Missverständnis :)

Mir war klar dass du darauf eingegangen bist, aber ich meinte mit meiner Aussage ja, dass er genau das Flag auch gesetzt hat oder nicht?!


in TMP1, GIMSK ; Interrupt an INT0 (Taster Aus/Ein) freigeben
sbr TMP1, 1<<INT0
out GIMSK, TMP1 ; und speichern.

avr_racer
01.10.2019, 19:17
Bascom und ASM sehen für mich gleichartig aus, sorry für das Missverständnis :)

Mir war klar dass du darauf eingegangen bist, aber ich meinte mit meiner Aussage ja, dass er genau das Flag auch gesetzt hat oder nicht?!

WAHTT?? Gleichartig ?? Niemals Do/IF ELSE ist deutlich anders als genau zu wissen was welcher Befehl tut und NUR dann macht! ;)

Es wird nur der INT0 als Interrupt freigegeben aber nicht PCIE
siehe Code


.include "tn15def.inc"
;---------------------
; Interrupt Vektoren
;---------------------
.cseg
.org $0000 ; Interrupt Vektoren
rjmp Init_int0 ;oder _PCIE
.org $0001
rjmp INT0_addr
.org $0002
rjmp PCI0_addr
;---------------------

init_INT0: ;PINB 2 im Simulator setzen
in r16,GIMSK
ori r16,(1<<INT0)
out GIMSK,r16

in r16,MCUCR
ori r16,( 1<<ISC01 | 1<<ISC00 ) ;Hier Flanken/levelaktivität aktivieren NUR FÜR INT0
out MCUCR,r16
sei
rjmp start

init_PCIE: ;PINB 0-5 kann gesetzt werden wird immer die gleiche Routine angesprungen
in r16,GIMSK
ori r16,(1<<PCIE)
out GIMSK,r16
sei
rjmp start


start:
rjmp start

INT0_addr:
nop
nop
nop
nop
reti

PCI0_addr:
nop
nop
nop
nop
nop
reti