Source file: /~heha/basteln/m/Kram/dccrail-avrgcc.zip/binärgleich/interrupt.S

/********************************************************************************
 * DCC Wagen Decoder Software V1.0						*
 * Copyright 2011 Toralf Wilhelm						*
 *										*
 * private Nutzung erwünscht, gewerbliche Nutzung erfordert zwingend meine Zustimmung! *
 * Datei:	interrupt.S							*
 * Kontakt:	toralfwilhelm@web.de						*
 * Webseite:	www.toralfwilhelm.de						*
 * Version:	01/2011 Version 1 Start						*
 * Beschreibung: enthält die Interruptschleifen der DCC Lichtdecoder Software 	*
 ********************************************************************************/

/***************************
 * Register und Konstanten *
 ***************************/

;	intsreg
;	DCCport
;	DCCpin
;	Lowpegel
;	Highpegel
;	DCCreg
;	analog_sw
;	analog_sw_zeit
;	w
;	flag
;	EmpPos
;	Bitzaehler
;	DCC_xor
;	ByteA-ByteF
;	Zaehler_10us
;	U_LED

#include "definitionen.h"

.text

/***********************
 * Timer_0/2_interrupt *
 ***********************
bei tiny44/45 Timer0 bei mega8 Timer2
wird alle 10us ausgelöst und liest dann bit von int0/d2 (auch jeder andere pin möglich) ein
dazu teiler auf1 (8tackte=1us) -> bis 80 zählen lassen und einen Compare interrupt auslösen
zw 26 und 34 cpu tackte -> 25-30% cpu leistung werden hier verbraucht!
es werden die register intsreg,lowpegel,highpegel belegt
das ergebnis wird mit dem flag neuerBefehl angezeigt und in ByteA-F zurückgegeben
*/

#ifdef __AVR_ATmega8__
TIM2_COMP:
#elif defined (__AVR_ATtiny44__) || defined(__AVR_ATtiny45__)
TIM0_COMPA:
#endif
	in	intsreg,SREG	// sreg sichern bewußt nicht im fifo abgelegt, da so schneller
	sbic	DCCport,DCCpin	// wenn aktueller Pegel=0 1x springen
	rjmp	DCC_PIN_HIGH
	inc	Lowpegel	// Lowpegel inc
	brne	DCC_BIT_SET	// wenn beim inc kein Überlauf (z=0) weiter mit..
	rjmp	KEIN_DCC_SETZTEN	// sonst zu..

DCC_PIN_HIGH:
	inc	Highpegel	// Highpegel inc
	brne	DCC_BIT_SET	// wenn beim inc kein Überlauf (z=0) weiter mit..
KEIN_DCC_SETZTEN:
	ldi	Lowpegel,11	// wenn Überlauf war, Lowpegel auf min für Lowbit setzen
	sbrs	DCCreg,analog	// wenn analog erlaubt 1x springen
	 rjmp	DCC_BIT_SET	// sonst fertig gleich weiter mit
	push	w	// Arbeitsregister sichern (nur machen wenn kein DCC Signal verhanden
		// dadurch verlängert sich die interruptschleife)
	 lds	w,analog_sw
	 inc	w	// analog_sw erhöhen (Umschaltverzögerung)
	 cpi	w,analog_sw_zeit	// analog_zw_zeit*255*10us= ca 100ms auf DCC Pulse warten (bei analog_zw_zeit=40)
	 brlo	KEIN_DCC_SETZTEN_END	// dann auf analog umschalten
	 clr	w
	 sbr	DCCreg,1<<keinDCC
	pop	w
	rjmp	DCC_BIT_SET
KEIN_DCC_SETZTEN_END:
	 sts	analog_sw,w
	pop	w

DCC_BIT_SET:
	cpi	Lowpegel,3	// wenn mindestens 3x Low eingetroffen
	brne	1f		// dann 1x springen
	clr	Highpegel	// sonst erst Highpegel löschen
1:	cpi	Highpegel,3	// ist jetzt Highpegel = 3
	brne	ZU_TIM2_COMP_ENDE	// wenn ungleich, dann zu 
	cbr	flag,(1<<bit)	// neues bit löschen
	cpi	Lowpegel,7	// ist Lowpegel kleiner 7
	brsh	1f		// wenn größer/gleich 1x springen
	sbr	flag,(1<<bit)	// neues bit setzen
1:	clr	Lowpegel	// Lowpegel wieder löschen
	inc	Highpegel	// zur sicherheit 1x erhöhen, damit nicht noch ein Byte erkannt wird

DCC_SCHLEIFE:			// DCC Bits zu Befehl zusammensetzten
	cpi	EmpPos,Preamble	// auf Empfangsposition Preamble testen 
	brne	LESE_BYTE_A
	sbrs	flag,bit	// wenn das neue Bit = 1 dann erhöhe Zähler
	 rjmp	PRE_END		// ansonsten Signal für Präambel Ende
	inc	bitzaehler	//
ZU_TIM2_COMP_ENDE:	// (Sprungverlängerungslabel)
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
PRE_END: 
	cpi	bitzaehler,10	// wenn Bitzähler kleiner 10
	brlo	PRE_FEHLER	// dann Fehler
	clr	bitzaehler	// lösche Zähler
	ldi	EmpPos,ByteA_lesen
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
PRE_FEHLER:
	rjmp	DCC_NEUSTART	// Endlosschleife
LESE_BYTE_A:
	cpi	EmpPos,ByteA_lesen	// auf Empfangsposition Byte A testen
	brne	LESE_BYTE_B
	sbrc	flag,neuerBefehl	// nur neuen Befehl einlesen, wenn letzter abgearbeitet
	rjmp	DCC_NEUSTART	// sonst DCC Neustart machen
	cpi	bitzaehler,8	// vergleiche mit Bytelänge
	breq	BYTE_A_END	// und springe wenn Byte eingelesen
	sec			// setzte Carry
	sbrs	flag,bit	// wenn empfangenes Bit=1 1x springen
	clc			// lösche Carry
	rol	byteA		// schiebe Carry von rechts in das Register
	inc	bitzaehler	// erhöhe Zähler
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
BYTE_A_END:
	mov	DCC_xor,byteA	// sichere Byte
	sbrc	flag,bit	// springe 1x wenn empfangenes Bit=0
	rjmp	DCC_NEUSTART	// sonst Byte nicht korrekt abgeschlossen
	clr	bitzaehler	// lösche Zähler
	ldi	EmpPos,ByteB_lesen
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
LESE_BYTE_B:
	cpi	EmpPos,ByteB_lesen	// auf Empfangsposition Byte B testen 
	brne	LESE_BYTE_C
	cpi	bitzaehler,8	// vergleiche mit Bytelänge 
	breq	BYTE_B_END	// und springe wenn Byte eingelesen
	sec			// setzte Carry
	sbrs	flag,bit	// wenn empfangenes Bit=1 1x springen
	clc			// lösche Carry
	rol	byteB		// schiebe Carry von rechts in das Register
	inc	bitzaehler	// erhöhe Zähler
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
BYTE_B_END:
	eor	DCC_xor,byteB	// bilde XOR
	sbrc	flag,bit	// springe 1x wenn empfangenes Bit=0
	rjmp	DCC_NEUSTART	// sonst Byte nicht korrekt abgeschlossen
	clr	bitzaehler	// lösche Zähler
	ldi	EmpPos,ByteC_lesen
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
LESE_BYTE_C:
	cpi	EmpPos,ByteC_lesen	// auf Empfangsposition Byte C testen 
	brne	LESE_BYTE_D
	cpi	bitzaehler,8	// vergleiche mit Bytelänge
	breq	BYTE_C_END	// und springe wenn Byte eingelesen
	sec			// setzte Carry
	sbrs	flag,bit	// wenn empfangenes Bit=1 1x springen
	clc			// lösche Carry
	rol	byteC		// schiebe Carry von rechts in das Register
	inc	bitzaehler	// erhöhe Zähler
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
BYTE_C_END:
	eor	DCC_xor,byteC	// bilde XOR
	sbrc	flag,bit	// springe 1x wenn empfangenes Bit=0
	rjmp	DATENPRUEFEN	// ansonsten Telegrammende
	clr	bitzaehler	// lösche Zähler
	ldi	EmpPos,ByteD_lesen
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
LESE_BYTE_D:
	cpi	EmpPos,ByteD_lesen	// auf Empfangsposition Byte D testen 
	brne	LESE_BYTE_E
	cpi	bitzaehler,8	// vergleiche mit Bytelänge
	breq	BYTE_D_END	// und springe wenn Byte eingelesen
	sec			// setzte Carry
	sbrs	flag,bit	// wenn empfangenes Bit=1 1x springen
	clc			// lösche Carry
	rol	byteD		// schiebe Carry von rechts in das Register
	inc	bitzaehler	// erhöhe Zähler
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
BYTE_D_END:
	eor	DCC_xor,byteD	// bilde XOR
	sbrc	flag,bit	// springe 1x wenn empfangenes Bit=0
	rjmp	DATENPRUEFEN	// ansonsten Telegrammende
	clr	bitzaehler	// lösche Zähler
	ldi	EmpPos,ByteE_lesen
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
LESE_BYTE_E:
	cpi	EmpPos,ByteE_lesen	// auf Empfangsposition Byte E testen 
	brne	LESE_BYTE_F
	cpi	bitzaehler,8	// vergleiche mit Bytelänge
	breq	BYTE_E_END	// und springe wenn Byte eingelesen
	sec			// setzte Carry
	sbrs	flag,bit	// wenn empfangenes Bit=1 1x springen
	clc			// lösche Carry
	rol	byteE		// schiebe Carry von rechts in das Register
	inc	bitzaehler	// erhöhe Zähler
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
BYTE_E_END:
	eor	DCC_xor,byteE	// bilde XOR
	sbrc	flag,bit	// springe 1x wenn empfangenes Bit=0
	rjmp	DATENPRUEFEN	// ansonsten Telegrammende
	clr	bitzaehler	// lösche Zähler
	ldi	EmpPos,ByteF_lesen
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
LESE_BYTE_F:
	cpi	EmpPos,ByteF_lesen	// auf Empfangsposition Byte F testen 
	brne	DCC_NEUSTART
	cpi	bitzaehler,8	// vergleiche mit Bytelänge
	breq	BYTE_F_END	// und springe wenn Byte eingelesen
	sec			// setzte Carry
	sbrs	flag,bit	// wenn empfangenes Bit=1 1x springen
	clc			// lösche Carry
	rol	byteF		// schiebe Carry von rechts in das Register
	inc	bitzaehler	// erhöhe Zähler
	rjmp	TIM2_COMP_ENDE	// erst einmal fertig
BYTE_F_END:
	eor	DCC_xor,byteF	// bilde XOR
	sbrc	flag,bit	// springe 1x wenn empfangenes Bit=0
	rjmp	DATENPRUEFEN	// ansonsten Telegrammende
	rjmp	DCC_NEUSTART	// wenn nicht DCC_NEUSTART
DATENPRUEFEN:	// Datenprüfung und Übergabe
	tst	DCC_xor		// prüfe DCC_xor auf 0
	brne	DCC_NEUSTART	// wenn nicht 0 dann Fehler
		// wenn byteA = 0 oder byteA = eigene Adresse oder RESET Flag gesetzt
		// Bit für neue daten setzen alle anderen Telegramme gleich verwerfen
	tst	byteA		// wenn 0 = Broadcast an alle
	breq	2f		// dann ok
	cp	byteA,Adresse	// wenn eigene Adresse
	breq	2f		// dann OK
	sbrc	flag,resetbit	// wenn 1 war reset
	 rjmp	2f		// dann auch ok
	rjmp	DCC_NEUSTART	// alles andere gleich verwerfen und DCC Neustart
2:
	sbrc	DCCreg,(keinDCC)
	rjmp	Reset		// wenn vorher im analog Modus, dann jetzt Neustart im DCC Modus
	sbr	flag,(1<<neuerBefehl)	// neuer DCC Befehl eingetroffen
	cbr	DCCreg,(1<<analog)	// wenn 1x DCC, dann analog Modus sperren
	rjmp	TIM2_COMP_ENDE	// fertig
DCC_NEUSTART:
	clr	bitzaehler	// loesche den BitCounter wieder
	clr	EmpPos		// EmpPos auf Preamble
TIM2_COMP_ENDE:
	inc	Zaehler_10us	// Zaehler register alle 10us inc
	out	SREG,intsreg	// sreg wiederherstellen
	reti	// und fertig

/****************************
 * ADC Wert einlesen fertig *
 ****************************/

ADC_Complete:
	in	intsreg,SREG	// sreg sichern bewußt nicht im fifo abgelegt, da so schneller
	push	w		// Arbeitsregister sichern

ADC_WERTE_EINLESEN:
	in	w, ADCL		// immer zuerst LOW Byte lesen
	in	w, ADCH		// danach das mittlerweile gesperrte High Byte
				// beides in w einlesen, da nur 8 bit nötig
	cp	w,U_LED
	brlo	U_LED_ZU_KLEIN
U_LED_ZU_GROSS:
	in	w,OCR1AL
	tst	w
	breq	ADC_ende
	dec	w 
	out	OCR1AL,w
	rjmp	ADC_ende
U_LED_ZU_KLEIN:
	in	w,OCR1AL
	inc	w
	tst	w
	breq	ADC_ende
	out	OCR1AL,w
ADC_ende:
	pop	w		// w wiederherstellen
	out	SREG,intsreg	// sreg wiederherstellen
	reti
Detected encoding: UTF-80