PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] Assembler Mega16 Timer Probleme



HeSt
29.09.2013, 05:27
Hi,
ich bin dabei meine defekte Heizungselektronik durch einen Mega16 zu ersetzen.
Das soll natürlich relativ rasch geschehen, denn die Heizperiode steht vor der Tür bzw. hat schon begonnen ...!

Beim Tiny13 und Mega8 hatte ich bislang keine Probleme mit den Timern bzw. den Vektor-Sprüngen bei Overflow.
Den Mega16 verwende ich das erste Mal.
Ich benötige alle 3 Timer.
Beim debuggen mit dem AVR Studio staunte ich nicht schlecht, als kein einziger TmrOvf auf die richtige Vektoradresse gesprungen ist.
Nun habe ich ein Testprogramm zusammen gestellt.
Bei diesem ist es genauso der Fall!

Beim Testen dieses Testprogrammes (und in meinem eigentlichen ebenso) mit AVR Studio 4.12 und 4.19 springen die Timer Interrupts auf eine komplett andere Vectoradresse als es sein soll!!!

Der Tmr0-Ovf-Int springt auf INT2 External Interrupt Request 2,
der Tmr1-Ovf-Int auf ANA_COMP Analog Comparator und
der Tmr2-Ovf-Int auf TIMER1 OVF Timer/Counter1 Overflow!

Wo hab ich bloß meinen Gedanken- und Programmfehler!??
Kann mir bitte jemand helfen?

Gruß Heinz



#include "m16def.inc"
; Interrupt Vektoren lt. Datenblatt und m16def.inc
.cseg
.org 0x000
rjmp INIT ; POR oder Reset
reti ;INT0 External Interrupt Request 0
reti ;INT1 External Interrupt Request 1
reti ;TIMER2 COMP Timer/Counter2 Compare Match
rjmp TMR2OVF ;TIMER2 OVF Timer/Counter2 Overflow
reti ;TIMER1 CAPT Timer/Counter1 Capture Event
reti ;TIMER1 COMPA Timer/Counter1 Compare Match A
reti ;TIMER1 COMPB Timer/Counter1 Compare Match B
rjmp TMR1OVF ;TIMER1 OVF Timer/Counter1 Overflow
rjmp TMR0OVF ;TIMER0 OVF Timer/Counter0 Overflow
reti ;SPI, STC Serial Transfer Complete
reti ;USART, RXC USART, Rx Complete
reti ;USART, UDRE USART Data Register Empty
reti ;USART, TXC USART, Tx Complete
reti ;ADC ADC Conversion Complete
reti ;EE_RDY EEPROM Ready
reti ;ANA_COMP Analog Comparator
reti ;TWI Two-wire Serial Interface
reti ;INT2 External Interrupt Request 2
reti ;TIMER0 COMP Timer/Counter0 Compare Match
reti ;SPM_RDY Store Program Memory Ready

INIT:
cli ;disable Interrupts

; Stack anlegen
ldi R16,LOW(RAMEND)
out SPL,R16
ldi R16,HIGH(RAMEND)
out SPH,R16

; Interrupt enabling
ldi R16,69 ;Tmr0+1+2 IntEn
out TIMSK,R16
sei ;Interrupts freigeben

;************************************************* ****************
; Start Timer0
ldi R16,250
out TCNT0,R16 ;TimerCounter auf 250
ldi R16,1 ;no Prescaler
out TCCR0,R16 ;StartTimer0
; Start Timer1
ser R17
ldi R16,245
out TCNT1H,R17 ;TimerCounter auf 255
out TCNT1L,R16 ;TimerCounter auf 245
ldi R16,1 ;no Prescaler
out TCCR1B,R16 ;StartTimer1
; Start Timer2
ldi R16,240
out TCNT2,R16 ;TimerCounter auf 240
ldi R16,1 ;no Prescaler
out TCCR2,R16 ;StartTimer2

; Loop zum Testen der TmrOvf Interrupts
LOOP:
nop
rjmp loop

;******************** START INTERRUPTROUTINEN ********************
TMR0OVF:
in R18,SREG
cli
out SREG,R18
reti

TMR1OVF:
in R19,SREG
cli
out SREG,R19
reti

TMR2OVF:
in R20,SREG
cli
out SREG,R20
reti

;******************** ENDE INTERRUPTROUTINEN *********************
.EXIT

Klebwax
29.09.2013, 07:23
Hallo,

ich hab zwar mit AVRs nichts zu tun, was mir aber auffällt ist die Verwendung von zwei verschiedenen Befehlen in der Interrupt Tabelle: reti und rjmp. Ich kenne das eigentlich so, daß überall jumps sind, die bei unbenutzten Interrupts auf einen Errorhandler zeigen.

MfG Klebwax

seite5
29.09.2013, 08:37
Hi,
Solange diese jump-adressen nicht angesprungen werden sollte das "reti" nicht stören, ich kenns allerdings auch so,
das dort ein jmp 0 oder so steht.
Würde aber zunächst mal das "sei" nach timer-initialisierung stellen und vor allem im TIFR vorm "sei" alle betroffenen
Interrupt-Flags löschen.
mfg
Achim

wkrug
29.09.2013, 08:56
Guck noch mal genau ins Datenblatt, da steht nicht RJMP zum anspringen der Interrupts sondern JMP.
Die Sprungweite vin RJMP reicht bei einem ATMEGA16 nicht mehr aus um den kompletten Adressraum bedienen zu können, deshalb müssen hier die JMP Befehle verwendet werden. - Der Fehler ist mir auch schon passiert.

Denk auch dran die JTAGEN Fuse zu deaktivieren, sonst gehen ein paar Ports von PORT C nicht richtig.

SEI löscht übrigens keinen Interrupt, sondern ermöglicht nur dessen Ausführung.
Die entsprechenden Flags werden durch Aufruf der entsprechenden Interrupt Routine mit dem Befehl RETI, oder durch gezieltes Schreiben auf bestimmte Register Bits gelöscht.

So etwas wie eine Heizungssteuerung in Assembler zu programmieren halt ich schon für etwas mutig.
Ich würde da eher ne Hochsprache nehmen wie z.B. "C" oder BASCOM, aber das musst Du selber entscheiden.

Klebwax
29.09.2013, 09:08
Solange diese jump-adressen nicht angesprungen werden sollte das "reti" nicht stören, ich kenns allerdings auch so,
das dort ein jmp 0 oder so steht.

Sie wären dann ein Problem, wenn ein jmp mehr Bytes braucht als ein reti. Die Tabelle würde dann nicht mehr passen.

MfG Klebwax

robin
29.09.2013, 09:11
Ein RJMP geht auch bei den Interrupts, es muss nur ein .org vor jeden Interrupt-Vektor und man muss sich im klaren sein, dass man nicht alles anspringen kann (sagt einem aber idr. der Compiler).
Ein Vorteil für den RJMP kann aber sein, dass es schneller abgearbeitet werden kann (1 Takt weniger).

Das .org hätte auch den Vorteil, dass man auch mal einen Vektor vergessen kann, ohne dass das Programm gleich durch dreht und die Vektoren sicher an ihrem Platz stehen.

wkrug
29.09.2013, 09:31
Ein Vorteil für den RJMP kann aber sein, dass es schneller abgearbeitet werden kann (1 Takt weniger).
Wie gesagt, ein RJMP reicht aber nicht bis zum Ende des Adressbereiches.
Wenn man dort dann Interrupt routinen plaziert, können die nicht mehr angesprungen werden - "Out of Range" Fehler.

Das Problem mit dem RETI in der Vektortabelle hat sich bei mir noch nicht ergeben, da ich immer alle Vektoren mit JMP Befehlen verwende und die nicht gebrauchten einfach mit RETI am angesprungenen Label abschließe.
Das hat den Vorteil, das ich relativ problemlos diese Interrupt Vektoren aktivieren kann, wenn ich sie dann doch brauche.

HeSt
29.09.2013, 12:10
Danke für die vielen und raschen Antworten!
RJMP und RETI funktionieren in der Vektortabelle bei Tiny13 und Mega8 einwandfrei.
Arbeitet der Mega16 anders???
Zudem sollte das Problem mit dem Adressbereich zumindest im obigen Testprogramm kein Problem sein.
Weiters motzt der Compiler ja nicht, was er bei einem "BRANCH" sehr wohl tut/getan hat (in meinem Heizungsprogramm).


SEI setze ich deshalb vor dem Starten der Timer, weil ich sie zu unterschiedlichen Zeiten bzw. Bedingungen starte und bei Overflow wieder stoppe.
Also muss SEI generell vorher gesetzt sein. Macht bei T13 + M8 auch keine Probleme.



Denk auch dran die JTAGEN Fuse zu deaktivieren, sonst gehen ein paar Ports von PORT C nicht richtig.
Was funktioniert da dann nicht richtig?
Wie muss ich die setzen?
Ich hab bislang geflissentlich die Finger von Fuses gelassen - außer Takt.



So etwas wie eine Heizungssteuerung in Assembler zu programmieren halt ich schon für etwas mutig.
Ich würde da eher ne Hochsprache nehmen wie z.B. "C" oder BASCOM, aber das musst Du selber entscheiden.
Ich hab vor ein paar Jahren mit Assembler begonnen und mich damit bisher gut zurecht gefunden. Wenn man vorher einen guten Programmablauf (programflow) ausarbeitet und skizziert, dann geht das Programmieren auch ganz flott von der Hand.



Guck noch mal genau ins Datenblatt, da steht nicht RJMP zum anspringen der Interrupts sondern JMP.
Sollte im Prinzip egal sein welcher Befehl in der Vektortabelle an der Ansprungadresse steht.
Denn bei einem Interrupt (TOVF) springt AVR gar nicht dort hin!!!!!!!!
DAS IST MEIN PROBLEM!!

Wsk8
29.09.2013, 15:11
Schonmal so versucht?



.org PORTB_INT0_vect ; Vector adress
rjmp SW1_ISR

mfg

robin
29.09.2013, 15:24
Denn bei einem Interrupt (TOVF) springt AVR gar nicht dort hin!!!!!!!!
DAS IST MEIN PROBLEM!!

Im unterschied von jmp und Rjmp liegt dein Problem, klar kannst du mit beidem springen, aber ein jmp ist größer (32 Bit befehl) als ein rjmp (16 Bit Befehl). Wenn du jetzt ohne .org rjmps hinter einander hängst, dann verschiebt sich dein ganzer code um zwei byte.

sprich durch dein rjmp init ist dein darauf folgendes reti an Adresse 0x02h und nicht and 0x04h wo es sein sollte. deswegen .org vorne dran dann passieren solche fehler nicht, oder eben jmp verwenden wenn du mehr als 8k flash hast.

HeSt
29.09.2013, 16:18
BINGO!!

Schonmal so versucht?

.org PORTB_INT0_vect ; Vector adress
rjmp SW1_ISR

Genau das ist es!
Aber warum funktioniert das dann beim Tiny13 und beim Mega8 ohne dem .org !?!?!??
Da ich dort bislang immer so programmiert habe (mit RJMP und RETI) und keine Probleme damit hatte, kam ich auch nicht auf die Idee es hier anders zu machen.
Somit scheint der Mega16 doch etwas anders zu arbeiten.
[edit]:
Hab mir die Vectortabellen von T13/M8 und M16 nun genau angeschaut:
T13 und M8 sind gleich: $000, $001, $002, ...!
M16: $000, $002, $004, ... !!!
[endedit]

DANKE für die rasche Hilfe !!!

- - - Aktualisiert - - -

Das eigentliche Problem ist behoben!
Aber etwas hängt da noch:


Zitat von wkrug
Denk auch dran die JTAGEN Fuse zu deaktivieren, sonst gehen ein paar Ports von PORT C nicht richtig.


Was ist damit? Was muss ich machen, damit die C-Ports (bei mir digitale Eingänge 0/1) richtig funktionieren?

Wsk8
29.09.2013, 16:24
Du gehst einfach auf den Fuses-Reiter und stellst sicher, dass JTAGEN nicht aktiviert ist.
http://dl6gl.de/sites/default/files/pictures/BASCOM%20snippets/avr_studio_fuse_bits_neu.jpg

mfg

HeSt
29.09.2013, 16:36
OK, danke!

wkrug
30.09.2013, 08:26
Defaultmässig ist das JTAG ( Debugging Interface ) bei einem fabrikneuen ATMEGA 16 aktiviert.
Das JTAG Interface sitzt auf 3 Pins von Port C. Welche das genau sind müsste ich jetzt im Datenblatt nachschauen.
Dadurch reagieren die Ports nicht so wie man das erwarten würde. Das hat mich schon mal 2 Tage sucherei gekostet.
Wenn Du natürlich einen JTAG Debugger / Programmer benutzt musst Du Die Fuse natürlich im Auslieferungszustand belassen.
Normalerweise benutzen aber Hobbyisten eher ISP.
In der Elektor haben sie auch schon mal eine Heizungssteuerung mit nem ATMEGA 32 vorgestellt.
Eventuell kannst Du dir da ein paar Anregungen holen.

Nur mal so ein paar Anregungen:
Ich würd auf jeden Fall einen RTC Chip mit einbauen, damit Du auch Sachen wie Nachtabsenkung und andere Uhrzeit gesteuerte Funktionen realieren kannst und nicht auf das interne Timing des Controllers angewiesen bist.
Auch ne serielle Schnittstelle zum PC wär ne gute Idee ( FT232R !? ) , um Parameter auslesen und auch mal verändern zu können.
Mit Tasten auf der Steuerung ist das oft ne üble Fummelei.
Als Display wär eventuell ein grafisches schön.
Bei Pollin gibts die 128x64 LCD Displays (http://www.pollin.de/shop/dt/Njc1OTc4OTk-/Bauelemente_Bauteile/Aktive_Bauelemente/Displays/LCD_Modul_TG12864B_05.html) zum günstigen Preis.
2x16 Zeichen Displays sind auch nicht teuer.
Du kannst Dir auch mal den AVR-NET-IO Bausatz von Pollin angucken.
In den Sockel passt ein MEGA16, 32 oder 644. Damit sind dann auch Webserver Anwendungen möglich.
Die Heizungsparameter vom Büro aus abfragen zu können hat doch auch was.
Relais und periphere Elektronik müsste man da auf nem huckepack Bord unterbringen.

HeSt
30.09.2013, 17:23
Danke für die Erläuterung bzgl. der JTAG-Sache!

Zu den Anregungen:
Lassen wir die Kirche im Dorf !!!
Die Heizung ist relativ alt (es zahlt sich kein großer Aufwand dafür aus) und deren Elektronik hat vor 2 Jahren den Geist aufgegeben. :-(

Damals waren mir die kleinen schwarzen programmierbaren Käfer noch nicht geläufig. Deshalb habe ich auf die Schnelle (musste ja irgendwie heizen) mit einem 741er und einigem Drumrum die Heizung wieder zum Leben erweckt.
Das lief/läuft so gut, dass ich mich erst jetzt daran mache, das "Profisorium" mit dem Mega16 abzulösen und aufzuwerten.
Du erkennst schon, dass es sich um kein großes Unterfangen handeln kann, wenn derzeit noch nur ein 741er werkelt.

Die alte Elektronik war was ganz einfaches: die Kesseltemperatur (Brenner) wurde von einem Thermostat geregelt, der sich am Kessel befindet. Also fixe Vorlauftemperatur (ca. 70°) unabhängig von der Außentemperatur. Die Raumtemperatur wurde über ein Raumthermostat eingestellt und die Elektronik regelte die Temperatur über den Mischer. Eine Nachtabsenkung hatte das Ding auch - über eine mechanische Uhr.

Die 741er Lösung arbeitet derzeit nur mit der Kesseltemperatur abhängig von der Außentemperatur ohne Mischerverstellung (=offen).
Eine Nachtabsenkung hat sie auch: wird über eine externe Uhr gesteuert (eine dieser Steckdosenuhren um 5 Euro), die für jeden Tag einen Programmspeicher hat und einen für "oben drüber" - hat sich besten bewährt. Genau diese Uhr kommt auch wieder bei der neuen Steuerung zum Einsatz. Sehr einfach, effektiv und kostengüstig - mit 1 Monat Gangreserve bei Stromausfall! :wink:

Die neue Lösung berücksichtigt nun Außen-, Kessel- und Raumtemperatur, arbeitet mit Kesseltemperatur und Mischer, hat über die externe Uhr eine für jeden Tag einzeln programmierbare Nachtabsenkung, steuert mir auch das Warmwasser, ob von Solar oder Heizung mit allen dazu gehörenden Wenn's. Winter/Sommer-Automatik oder manuell. Programmier- und steuerbar von der Wohnung aus.

Den Mega16 brauch ich nur wegen der vielen Anschlüsse. Von der Programmgröße (Flash) würde der Mega8 auch reichen, weil keine Schnickschnacks geplant sind wie Display oder PC-Anbindung. Das ist mir derzeit auch noch zu hoch. Da bin ich viel zu wenig firm mit den AVR's und mach auch zu wenig. Eben nur dann, wenn etwas ansteht.

Danke jedefalls für die Hinweise wo ich mir Anregungen und Lösungsansätze holen kann !!!

HeSt
04.11.2013, 11:31
Hallo Leute,
bin nochmals da.

Für meine Anwendung ist 1MHz ein bisschen schnell. Gibt es eine Möglichkeit die Prozessorgeschwindigkeit weiter zu verringern (<1MHz) OHNE externe clock!? Also internal clock.

Der Fuse Calculator (http://www.engbedded.com/fusecalc) lässt keine zu.
Was aber nichts heißt, denn beim Tiny13 kennt er auch keine speed zwischen 128KHz und 4,8MHz, obwohl 16KHz, 600KHz und 1MHz sehr wohl möglich sind!!

Danke im Voraus für eure Hinweise
LG Heinz

robin
04.11.2013, 11:58
Kannst du den Tiny nich einfach schlafen legen und per timer alle paar ms aufwecken?

Ansonsten sehe ich keine möglichkeit weniger als 1/8 takt zu erhalten. Außer ein externer Quarz. Und selbst dann ist nicht gewährleistet, dass es mit solch geringen Takt noch läuft.

Klebwax
04.11.2013, 13:18
Für meine Anwendung ist 1MHz ein bisschen schnell.

Warum?

MfG Klebwax

HeSt
05.11.2013, 10:14
Warum?

MfG Klebwax

Ich habs noch nicht probiert, aber rein vom Gefühl bekomme ich zeitliche Probleme mit all meinen Timern und Verschachtelungen.
Hab eh überall Prüfungen eingebaut - so ich logisch keine übersehen hab ...
Ich will es einfach VORHER wissen, ob eine niedrigere Taktfrequenz möglich ist. Und wenn ja, elche Fusebits dafür zu setzen sind.
Denn wenn ich tatsächlich in Zeitprobleme laufe, möchte ich sofort probieren können und nicht erst dann fragen gehen ...

@robin,
beim Tiny13 hab ich eh kein Problem. Allerdings setze ich da die Taktfrequenz (so ich eine benötige die nicht im "fusecalc" aufscheint) nicht per Eingabe der Fuse-Werte (wie denn auch, kenne sie ja nicht), sondern über das Franzis-Lernpaket (LPMikros), wo die Taktfrequenzen angegeben sind, nicht aber welche Fusebits dabei gesetzt werden. Und LPMikros kann das leider nur für den Tiny13.
Hier gehts aber um den Mega16.

LGH