;=======================================================================
;		VARIATEUR pour moteur BRUSHLESS a 3 fils  : variat4.asm
;				pour ATMEGA8 et Qx=16,000 Mhz

;derniere mise a jour: 22/05/2006
; Version: 1.00
; Auteur: Silicium628
;=======================================================================									
;Cette realisation fait suite a celle utilisant un PIC16F628		
;=======================================================================
;PRINCIPE


;=======================================================================


;LISTE DES PARTIES:

;Declaration des Variables
;MACROS
;Declaration des Vecteurs d'interruptions
;Routines de traitement des interruptions
;Programme de RESET
;initialisation des ports
;PROGRAMME PRINCIPAL
;ROUTINES
;STOP
;pasMoteur
;demarre

;mul16_8	MULTIPLICATION 8 bits x 16 bits resultat sur 24 bits
;div24_8	DIVISION 24 bits par 8 bits, resultat sur 24 bits

;=======================================================================


.include "m8def.inc"	; nom du fichiers de references des registres (ATMEGA 8)


;------------------------------------------------------------------------
;Declaration des Variables		                 	
;------------------------------------------------------------------------

.def n_pas = r0

.def SAUVREG = r15	; registre de sauvegarde de SREG

.def a=r16
.def AA=r17
.def BB=r18

.def Flags1 = r19	;"mesflags1"
;Flags1[0]= incrementation demande
;Flags1[1]= 
;Flags1[2]=
;Flags1[3]= MODE : (actuellement inutilise)
;Flags1[4]= Attente relachement des touches demande

;r20..25 reserve pour les variables locales
;r26,27 reserve comme registre d'adresse d'indexation (X)



;r30,31 reserve comme registre d'adresse d'indexation (Z) permet la lecture en memoire de programme

.DSEG
	nombre1:		.BYTE 3	;nombre code sur 3 octets (binaire) 0...16 777 216
	nombre2:		.BYTE 3	;""

	dividende: 	.BYTE 3
	numerateur:	.BYTE 1
	denominateur:	.BYTE 1
 


;------------------------------------------------------------------------
;MACROS
;------------------------------------------------------------------------
	
;cette macro fait @0(variable en RAM, 24bits)  := @1 valeur(24bits) pasee en parametre
.MACRO	Mset24
	ldi	a,BYTE1(@1)
	sts	@0+0,a
	ldi	a,BYTE2(@1)
	sts	@0+1,a
	ldi	a,BYTE3(@1)
	sts	@0+2,a

.ENDMACRO	

;------------------------------------------------------------------------
;cette macro fait @0(variable en RAM, 24bits)  := r20,21,22
.MACRO	Mstore24
	sts	@0+0,r20
	sts	@0+1,r21
	sts	@0+2,r22

.ENDMACRO	

;------------------------------------------------------------------------
;cette macro fait 3 registres successifs  := @0 (variable en RAM, 24bits, pasee en parametre)
.MACRO	Mload24
	lds	r20,@0+0
	lds	r21,@0+1
	lds	r22,@0+2


.ENDMACRO	


;------------------------------------------------------------------------
;Declaration des Vecteurs d'interruptions
;------------------------------------------------------------------------

.CSEG
.ORG 0x0000			;debut zone memoire programme
	rjmp	RESET		;RESET
	rjmp	EXT_INT0		;Interruption externe INT0
	rjmp 	EXT_INT1		;Interruption externe INT1
	rjmp 	TIM2_COMP		;Interrution comparaison reussie TIMER2
	rjmp 	TIM2_OVF		;Interrution debordement compteur TIMER2  
	rjmp 	TIM1_CAPT		;Interrution entree capture TIMER1
	rjmp	TIM1_COMPA	;Interrution comparateurA TIMER1
	rjmp 	TIM1_COMPB	;Interrution comparateurB TIMER1
	rjmp	TIM1_OVF		;Interrution debordement compteur TIMER1 
	rjmp 	TIM0_OVF		;Interrution debordement compteur TIMER0 
	rjmp 	SPI_STC		;Interrution transmissions SPI terminee
	rjmp 	UART_RXC		;Interrution reception UART termine RX
	rjmp 	UART_DRE		;Interrution UART vide 
	rjmp 	UART_TXC		;Interrution emission UART termine TX
	rjmp 	ADC_ok		;Interrution Conversion A/D terminee
	rjmp 	EE_RDY		;Interrution EEPROM prete
	rjmp 	ANA_COMP		;Interrution comparaison analogique effectuee
	
;------------------------------------------------------------------------
;Routines de traitement des interruptions
;------------------------------------------------------------------------
;declenchee par les signaux de BEMF
;fait avancer le moteur d'un pas
			
EXT_INT0:	in	sauvreg,sreg
	push 	sauvreg
	push	a

	rcall	pasMoteur

fin_int0:	pop	a
	pop 	sauvreg
	out 	sreg,sauvreg 
	reti
	reti

;------------------------------------------------------------------------
EXT_INT1:	reti
;------------------------------------------------------------------------
TIM2_COMP:reti
;------------------------------------------------------------------------
TIM2_OVF:	reti
;------------------------------------------------------------------------
TIM1_CAPT:reti
;------------------------------------------------------------------------
TIM1_COMPA:reti
;------------------------------------------------------------------------
TIM1_COMPB:reti
;------------------------------------------------------------------------
TIM1_OVF:	reti	
;------------------------------------------------------------------------
TIM0_OVF:	reti
;------------------------------------------------------------------------
SPI_STC:	reti
;------------------------------------------------------------------------
UART_RXC:	reti
;------------------------------------------------------------------------
UART_DRE: reti
;------------------------------------------------------------------------
EE_RDY:	reti
;------------------------------------------------------------------------
ANA_COMP:	reti
;------------------------------------------------------------------------
ADC_ok:	reti
;------------------------------------------------------------------------
UART_TXC:	reti
;------------------------------------------------------------------------
UART_RXC1:reti
;------------------------------------------------------------------------


;------------------------------------------------------------------------
;Programme de RESET
;------------------------------------------------------------------------
	
	cli

texte:	.DB	'V','A','R','I','A','T','E','U','R'	;Pour reperer facilement le bon .ASM dans PonyProg!
;(evite de grosses meprises lorsque je travaille sur plusieurs softs en meme temps...)
 
RESET:	ldi	a,low(RAMEND)
	out	SPL,a		; Initialisation de la pile a   
	ldi	a,high(RAMEND)	; l'adresse haute de la SRAM
	out	SPH,a	
;------------------------------------------------------------------------
;initialisation des ports
;PORT A:
	ldi 	a,0b00000000	;toutes en entree
	out 	ddrd,a
	ldi	a,0b11111111	;R de tirage
	out 	portd,a	
		
;PORT B:
	ldi 	a,0b11111111	;toutes en sorties
	out 	ddrb,a

;PORT C:
	ldi 	a,0b11111111	;toutes en sorties	
	out 	ddrc,a
	clr 	a
	out 	portc,a		;sorties = 0

;------------------------------------------------------------------------
;wachtdog	
;	wdr			
;	ldi 	a,0b00001111	; wachtdog enable; delai = 2s (voir p:82)
;	out 	wdtcr,a

	wdr
	ldi	a,0b00011111
	out 	wdtcr,a
	ldi	a,0b00010111
	out 	wdtcr,a		; disable le wachtdog. (voir p:83)


;------------------------------------------------------------------------
;TIMSK
;Timer Interrupt Mask; voir pdf p:70
;bit7 (OCIE2)
;bit6 (TOIE2)
;bit5 (TICIE1) Timer/Counter1, Input Capture Interrupt Enable
;bit4 (OCIE1A) Timer/Counter1, Output Compare A Match Interrupt Enable
;bit3 (OCIE1B) Timer/Counter1, Output Compare B Match Interrupt Enable
;bit2 (TOIE1)  Timer/Counter1, Overflow Interrupt Enable
;bit1 inutilise
;bit0 (TOIE0) Timer/Counter0 Overflow Interrupt Enable - voir Tavernier p:96

		;   76543210
	ldi	a,0b00010001	;Timer1 Output Compare A Match Interrupt Enable ;Timer0 Overflow Interrupt Enable	
	out	TIMSK,a
;------------------------------------------------------------------------
;TCCR0
;definit le mode de fonctionnement du Timer0
;bits7a3 = non utilise
;bits2,1,0 = taux de predivision de l'horloge voir Tavernier p:87
;16MHz/1024 = 15625 Hz

		;   76543210
	ldi	a,0b00000101	;1/1024	(voir tableau Tavernier p:88)
	out	TCCR0,a
;------------------------------------------------------------------------
;TCCR1A
;definit le mode de fonctionnement du Timer1
;voir Tavernier p:93

;bit7 (COM1A1)	;definit le comportement de la sortie OC1A
;bit6 (COM1A0)
;bit5 (COM1B0)
;bit4 (COM1B1)
;bit3,2 NC
;bit1 (PWM11)
;bit0 (PWM10)

		;   76543210
	ldi	a,0b00000000	;voir tableau Tavernier p:93
	out	TCCR1A,a
;------------------------------------------------------------------------
;TCCR1B
;definit le mode de fonctionnement  du Timer1
;voir Tavernier p:94-95 ;et p:81-82 du datasheet.pdf

;bit7 (ICNC1): enable/disable reducteur de bruit
;bit6 (ICES1)=1: transfert du registre de comptage TCNT1 dans le registre de capture ICR1 sur front montant du pin ICP
;bit5 : inutilise
;bit4 : inutilise
;bit3 (WGM12 ou CTC1): raz registre de comptage (TCNT1) apres comparaison
;bits2,1,0: taux de predivision applique a l'horloge systeme. voir Tavernier p:95

		;   76543210
	ldi	a,0b00001110	;horloge externe pour le Timer1, RAZ du compteur (TCNT1) lors de comparaison OK
	out	TCCR1B,a
;------------------------------------------------------------------------
;MCUCR 
;voir datasheet p:31
;bits[3,2] -> ISC11 ISC10 Description
;0 0 The low level of INT1 generates an interrupt request.
;0 1 Any logical change on INT1 generates an interrupt request.
;1 0 The falling edge   of INT1 generates an interrupt request.
;1 1 The rising  edge   of INT1 generates an interrupt request.

;bits[1,0] -> ISC01 ISC00 Description
;0 0 The low level of INT0 generates an interrupt request.
;0 1 Any logical change on INT0 generates an interrupt request.
;1 0 The falling edge   of INT0 generates an interrupt request.
;1 1 The rising  edge   of INT0 generates an interrupt request.

		;   76543210
	ldi	a,0b00000001	;Any logical change on INT0 generates an interrupt request.
	out	MCUCR,a		;voir p:64 du datasheet.pdf et Tavernier p:30

;------------------------------------------------------------------------
;GICR (GENERAL INTERRUPT CONTROL REGISTER)
;page 47 et 65 du datasheet
;bit 7 = INT1 enable
;bit 6 = INT0 enable

		;   76543210
	ldi	a,0b01000000	;INT0 enable
	out	GICR,a

;------------------------------------------------------------------------
initvar:	
	
	ldi	Flags1,0b00000000
	clr	n_pas
	rcall	STOP

;chargement du registre de comparaison (A) du Timer1
;	cli
;	ldi	r20,LOW(59)	;588
;	ldi	r21,HIGH(59)	;588
;	out 	OCR1AH,r21	
;	out 	OCR1AL,r20
;	sei	;Sets the Global Interrupt flag (I) in SREG (status register)


;------------------------------------------------------------------------
;zone de tests de procedures
	

;------------------------------------------------------------------------
;PROGRAMME PRINCIPAL
;------------------------------------------------------------------------

	sei	;Sets the Global Interrupt flag (I) in SREG (status register)

	rcall	demarre
;------------------------------------------------------------------------
;BOUCLE PRINCIPALE

bcl0:	nop

	rcall	tp1ms

	rjmp	bcl0

;------------------------------------------------------------------------
;ROUTINES
;------------------------------------------------------------------------
STOP:	cli
	clr	a
	out	pinc,a
	ret

;------------------------------------------------------------------------
pasMoteur:inc	n_pas
	mov	a,n_pas
	cpi	a,6
	brlo	int0b
	clr	n_pas

int0b:	mov	a,n_pas
	rcall	lire_Ph

	out	portc,a
	ret

;------------------------------------------------------------------------
demarre:	cli
	ldi	AA,20	;2

dema1:	ldi	BB,10	;8

dema2:	rcall	pasMoteur

	ldi	a,1	;2
	add	a,AA
	rcall	tx1ms		;delai proportionnel a AA +2 donc qui decroit avec AA -> f augmente
	dec	BB
	brne	dema2		;boucle interieure courte, BB fois
		
	dec	AA
	brne	dema1		;boucle exterieure, AA fois
	
	cli
	rcall	STOP		;moteur en roue libre		
					
	ldi	a,10
	rcall	tx1ms

	sei	;re-autorie les INTs
	ret

;------------------------------------------------------------------------
;tableau des valeurs des bits de commande des phases (en memoire de programme)
;'a' doit contenir la position dans le tableau (0..7)
;la routine retourne la valeur lue dans 'a'
lire_Ph:	ldi 	ZH, high(Table_1<<1);Initialize Z pointer (le shift gauche because le LSB est reserve. voir doc)
	ldi 	ZL, low(Table_1<<1)
	andi	ZL,0b11111110	;RAZ LSB pour acceder aux octets de poids faible
	lsl	a		;shift gauche aussi
	add	ZL,a		;decallage dans le tableau (voir plus bas)
	clr	a
	adc	ZH,a
	lpm 	a, Z		;Load constant from program
	ret

Table_1:	.DB	0b00000110 ;phase 0
	.DB	0b00100100 ;phase 1
	.DB	0b00100001 ;phase 2
	.DB	0b00001001 ;phase 3
	.DB	0b00011000 ;phase 4
	.DB	0b00010010 ;phase 5


;------------------------------------------------------------------------
EE_write:	cli	;stop INT

	sbic 	EECR,EEWE	
	rjmp 	EE_write	; Wait for completion of previous write

	out 	EEARH, r18; Set up address (r18:r17) in address register
	out 	EEARL, r17
	out 	EEDR,a	; Write data (r16) to data register
	sbi 	EECR,EEMWE; Write logical one to EEMWE

	sbi 	EECR,EEWE	; Start eeprom write by setting EEWE

	sei	;INT ON
	ret

;------------------------------------------------------------------------
		
EE_read:	sbic 	EECR,EEWE
	rjmp 	EE_read	; Wait for completion of previous write

	out 	EEARH, r18; Set up address (r18:r17) in address register
	out 	EEARL, r17
	sbi 	EECR,EERE	; Start eeprom read by writing EERE

	in 	a,EEDR	; Read data from data register
	ret


;----------------------------------------------------------------------
;ADDITION de registres sur 3 octets
;r20,21,22:= r20,21,22 + r0,r1,r2

add24r:	add	r20,r0
	adc	r21,r1
	adc	r22,r2
	ret	


;----------------------------------------------------------------------
;ADDITION sur 3 octets (1)
;r20,21,22:= r20,21,22 + nombre1

add24a:	lds	a,nombre1+0
	add	r20,a
	lds	a,nombre1+1
	adc	r21,a
	lds	a,nombre1+2
	adc	r22,a
	ret	

;----------------------------------------------------------------------
;ADDITION sur 3 octets (2)
;nombre1:= nombre1 +nombre2

add24b:	push	AA
	push	BB
	lds	AA,nombre1+0
	lds	BB,nombre2+0
	add	AA,BB
	sts	nombre1+0,AA

	lds	AA,nombre1+1
	lds	BB,nombre2+1
	adc	AA,BB
	sts	nombre1+1,AA
	
	lds	AA,nombre1+2
	lds	BB,nombre2+2
	adc	AA,BB
	sts	nombre1+1,AA
	pop	BB
	pop	AA
	ret	

;----------------------------------------------------------------------
;MULTIPLICATION 8 bits x 16 bits resultat sur 24 bits
;multiplie r20(poids faible),r21 , r22(poids fort) par 'a'
;produit dans r20,r21,r22

.def produit0=r20	;produit poids faible
.def produit1=r21	;produit
.def produit2=r22	;produit poids fort
.def n1=r23

mul16_8:	ldi	n1,17		;compteur de boucle
		
mul16_81:	ror	produit2
	ror	produit1
	ror	produit0

	brcc	mul16_82		;lecture d'un bit de r20 ; test de ce bit
	add	produit2,a	;si c' est un '1' on ajoute 'a' a A2

mul16_82:	dec	n1
	brne	mul16_81

	ret

;----------------------------------------------------------------------
;DIVISION 24 bits par 8 bits, resultat sur 24 bits
;note; le quotient est stocke dans le dividende; permet de decaller les deux a la fois

;r20,21,22 doivent contenir le dividende (r20=LSB)
;r23 doit contenir le diviseur
;resultat (Quotient) dans r20 (LSB) et r21 et r22
;reste dans r24
;le bit T=1 indique un debordement

.def Dividend0=r20	;pour la routine Div24_8
.def Dividend1=r21	;pour la routine Div24_8
.def Dividend2=r22	;pour la routine Div24_8
.def Diviseur =r23	;pour la routine Div24_8.
.def Aux0=r24	;pour la routine Div24_8
.def Aux1=r25
.def n1=r16	;attention: ecrase r16 (=a)

div24_8:	ldi	n1,24	
	clr	Aux0		;clrf	Aux+0

div24_80:	lsl	Dividend0
	rol	Dividend1
	rol	Dividend2

div24_81:	rol	Aux0	;decalle le dividende dans 'Aux' (passage d'un bit par "c")
	rol	Aux1

	cp	aux0,Diviseur
	brlo	auxPetit
	
auxGrand:	sub	Aux0,Diviseur
	sec
	rjmp	saut1

auxPetit:	clc
	
saut1:	rol	Dividend0	;decalle a gauche en incorporant 'c' comme bit 0
	rol	Dividend1	;decalle a gauche avec passage d'un bit par "c"
	rol	Dividend2 ;decalle a gauche et envoie un bit par 'c' dans 'Aux' (apres le saut)

	dec	n1	;important: ne touche pas a 'c'
	brne	Div24_81
	
	ret

;----------------------------------------------------------------------
;TEMPO 1ms exactement avec un Qx=16.000MHz
;attention: sous reserve de ralentissement par les interruptions...

.def	i1=r20
.def	i2=r21

tp1ms:	push	r20
	push	r21

	ldi	i1,16
bcl2:	ldi	i2,248	
bcl3:	dec	i2
	brne	bcl3

	nop		;pour ajuster exactement la duree
	nop
	nop
	dec	i1
	brne	bcl2

	nop
	pop	r20
	pop	r21
	ret


;----------------------------------------------------------------------
;tempo a * 1ms
tx1ms:	push	r16
.def n=r16

	mov	n,a
bcl7:	rcall	tp1ms
	dec	n
	brne	bcl7

	pop	r16
	ret

;----------------------------------------------------------------------
;tempo a * 100ms
;a qui contient le nb de fois 100ms est affecte
.def n=r16

tx100ms:	push	r16

	ldi	n,100
bcl6:	rcall	tp1ms
	dec	n
	brne	bcl6
	pop	r16
	dec	a
	brne	tx100ms
	ret

;----------------------------------------------------------------------	
