;******************************************************
;* SPI_kijelzo.asm
;* 7 digites kijelző
;* Proc: ATTiny2313
;*
;* Snieder László
;* 2008.03.20
;* laszlo.snieder@gmail.com
;*
;******************************************************
; v0.0.1	2008.03.20

.include "tn2313def.inc"
.include "estudio.inc"


.equ	FOSC		= 8000		;8000 kHz
.equ	BGCLOCK		= 1			;1 kHz

.def 	_Status		= r0	;low register to preserve status register
;r1
;r2
;r3
;r4
;r5
;r6
;r7
;r8
;r9
;r10
.def	_DPpos		= r11	;DP Position
.def	_Mode		= r12
.def	_Oreg		= r13
.def	_Freg		= r14
.def	_0			= r15	;Permanent zero
.def 	_Temp 		= r16	;scratch space for work
.def 	_Work 		= r17	;scratch space for work
.def	_State		= r18	;Main state: 	IDLE,ACTIVE,ERROR
.def	_Istate		= r19	;Input state:	READY,1BYTE,2BYTE,3BYTE,4BYTE
.def	_Itimeout	= r20	;Input timeout
;r21
;r22
;r23

;Istate enumeration
.equ	I_READY		= 0
.equ	I_1BYTE		= 1
.equ	I_2BYTE		= 2
.equ	I_3BYTE		= 3
.equ	I_4BYTE		= 4

.equ	DCK			= PORTB0
.equ	DOUT		= PORTB1
.equ	DCLR		= PORTB2

.equ	G1			= PORTD0
.equ	G2			= PORTD1
.equ	G3			= PORTD2
.equ	F1			= PORTD3
.equ	F2			= PORTD4
.equ	F3			= PORTD5
.equ	F4			= PORTD6

.equ	STEP_MODE	= 0
.equ	MM_MODE		= 1

.equ	Ag		= 1 << 0
.equ	Bg		= 1 << 1
.equ	Cg		= 1 << 2
.equ	Dg		= 1 << 3
.equ	Eg		= 1 << 4
.equ	Fg		= 1 << 5
.equ	Gg		= 1 << 6
.equ	DPg		= 1 << 7

.equ	Ch_0	= Ag+Bg+Cg+Dg+Eg+Fg		;0
.equ	Ch_1	= Bg+Cg					;1
.equ	Ch_2	= Ag+Bg+Gg+Eg+Dg		;2
.equ	Ch_3	= Ag+Bg+Cg+Dg+Gg		;3
.equ	Ch_4	= Fg+Gg+Bg+Cg			;4
.equ	Ch_5	= Ag+Fg+Gg+Cg+Dg		;5
.equ	Ch_6	= Ag+Fg+Eg+Dg+Cg+Gg		;6
.equ	Ch_7	= Ag+Bg+Cg				;7
.equ	Ch_8	= Ag+Bg+Cg+Dg+Eg+Fg+Gg	;8
.equ	Ch_9	= Gg+Fg+Ag+Bg+Cg+Dg		;9
.equ	Ch_A	= Eg+Fg+Ag+Bg+Cg+Gg		;A
.equ	Ch_B	= Fg+Eg+Dg+Cg+Gg		;B
.equ	Ch_C	= Ag+Fg+Eg+Dg			;C
.equ	Ch_D	= Bg+Cg+Dg+Eg+Gg		;D
.equ	Ch_E	= Ag+Fg+Eg+Dg+Gg		;E
.equ	Ch_F	= Ag+Fg+Eg+Gg			;F
.equ	Ch_sp	= 0						;Space
.equ	Ch_mi	= Gg					;Minus
.equ	Ch_G	= Ag+Fg+Eg+Dg+Cg		;G
.equ	Ch_H	= Fg+Eg+Gg+Bg+Cg		;H
.equ	Ch_I	= Fg+Eg					;I
.equ	Ch_J	= Bg+Cg+Dg				;J
.equ	Ch_L	= Fg+Eg+Dg				;L
.equ	Ch_N	= Eg+Gg+Cg				;n
.equ	Ch_O	= Eg+Gg+Cg+Dg			;o
.equ	Ch_R	= Eg+Gg					;r
.equ	Ch_U	= Eg+Dg+Cg				;u

.ESEG

E_HexTo7:
		.DB		Ch_0,Ch_1,Ch_2,Ch_3,Ch_4,Ch_5,Ch_6,Ch_7
		.DB		Ch_8,Ch_9,Ch_A,Ch_B,Ch_C,Ch_D,Ch_E,Ch_F
		;Test for Digits
		.DB		Ch_sp,Ch_sp,Ch_sp,Ch_sp,Ch_sp,Ch_sp,Ch_sp
		;Test for Value buffer
		.equ val = -123456
		.DB		(val & 255),((val>>8) & 255),((val>>16) & 255)
E_dataend:	.byte	0
.equ 	E_size		= E_dataend - E_HexTo7

.DSEG
HexTo7:		.byte	16
Digits:		.byte	7
Value:		.byte	3
Voffset:	.byte	3
Vcenter:	.byte	3
Gstatus:	.byte	1

D_dataend:	.byte	0
.equ 	D_size		= D_dataend - HexTo7
	
.CSEG
.org	0x00
;irq table
	rjmp 	RESET 		;Reset Handler
	reti			 	;External Interrupt0 Handler
	reti			 	;External Interrupt1 Handler
	reti			 	;Timer1 Capture Handler
	rjmp	_1Hz	 	;Timer1 CompareA Handler
	reti			 	;Timer1 Overflow Handler
	reti			 	;Timer0 Overflow Handler
	reti			 	;USART0 RX Complete Handler
	reti			 	;USART0,UDR Empty Handler
	reti			 	;USART0 TX Complete Handler
	reti			 	;Analog Comparator Handler
	reti			 	;Pin Change Interrupt
	reti			 	;Timer1 Compare B Handler
	rjmp	_1KHz	 	;Timer0 Compare A Handler
	reti			 	;Timer0 Compare B Handler
	reti			 	;USI Start Handler
	rjmp	Ser_int	 	;USI Overflow Handler
	reti			 	;EEPROM Ready Handler
	reti			 	;Watchdog Overflow Handler

;-----------
;RESET
;-----------
RESET: ;Main program start
	outi 	SPL,RAMEND				; Locate stack
	clr		_0

	;Clear RAM
	ldi		AL,D_size
	ldiw	Z,Digits
res_clrram:
	st		Z+,_0
	dec		AL
	brne	res_clrram

	;Copy params into RAM
	;--------------------
	ldiw	Y,E_HexTo7
	ldiw	Z,HexTo7
	ldi		AH,E_size
	rcall	CopyToRam

	;PortB
	;-----
	outi	DDRB, (1<<DCK | 1<<DOUT | 1<<DCLR | 1<<PORTB6)
	;PortD
	;-----
	outi	DDRD, (1<<F1 | 1<<F2 | 1<<F3 | 1<<F4)
	outi	PORTD,(1<<G1 | 1<<G2 | 1<<G3)
	stsi	Gstatus,(1<<G1 | 1<<G2 | 1<<G3)

	;Timer0
	;------
	outi	TCCR0A,(1<<WGM01)			;CTC
	outi	TCCR0B,(0<<CS02 | 1<<CS01 | 1<< CS00)	;Prescaler:64 (125 kHz)
	;Timer1
	;------
	outi	TCCR1A,0								;CTC
	outi	TCCR1B,(1<<WGM12 | 1<<CS12 | 1<< CS10)	;Prescaler:1024 (7.8 kHz)


	outi	TIMSK, (1<<OCIE0A | 1<<OCIE1A)			;Timer interrupt
	outi	OCR0A,120								;1 kHz
	outi	OCR1AH,high(7800)						;1 Hz
	outi	OCR1AL,low(7800)

	;SPI
	;---
	outi USICR,(1<<USIWM0)|(1<<USICS1)|(1<<USIOIE)	;3-wire, Ext.pos.clock, Counter int enabled
	outi USISR,0									;Clear counter

	sbi		PORTD,F1
	sbi		PORTD,F2
	sbi		PORTD,F3
	sbi		PORTD,F4
	sbi		PORTB,DCLR

	ldi		AL,STEP_MODE
	mov		_Mode,AL
	ldi		AL,9
	mov		_DPpos,AL
	ldi		AL,0x11
	mov		_Freg,AL

	ldi		_Istate,I_READY
	ldi		_Itimeout,255

	stsi3	Voffset,0
	rcall	ValToDigits
	rcall	DigitOut

	sei

Main:
	rjmp	Main


;-------
;Ser_int
;-------
Ser_int:
	push	_Status
	in		_Status,SREG
	pushw	A
	pushw	E
	in		EL,USIDR		;Received byte
	cpi		_Istate,0
	brne	Ser_int1
	;1'st byte received
	inc		_Istate
	rjmp	Ser_int_ret

Ser_int1:
	cpi		_Istate,1
	brne	Ser_int2
	;2'nd byte received
	inc		_Istate
	sts		Value+0,EL
	rjmp	Ser_int_ret

Ser_int2:
	cpi		_Istate,2
	brne	Ser_int3
	;3'th byte received
	inc		_Istate
	sts		Value+1,EL
	rjmp	Ser_int_ret

Ser_int3:
	;4'th byte received
	clr		_Istate
	sts		Value+2,EL
	rcall	ValToDigits
	rcall	DigitOut
	rjmp	Ser_int_ret

Ser_int_ret:
	ldi		_Itimeout,120
	outi	USISR,(1<<USISIF|1<<USIOIF)
	popw	E
	popw	A
	out		SREG,_Status
	pop		_Status
	reti

;---------------
;_1KHz Interrupt
;---------------
_1KHz:
	push	_Status
	in		_Status,SREG
	pushw	A
	pushw	B

	mov		BH,_Freg
	ror		BH
	andi	BH,(1<<F1 |1<<F2 |1<<F3 |1<<F4)
	brne	_1KHz_Fok
	ldi		BH,(1<<F4)
_1KHz_Fok:
	mov		_Freg,BH
	in		BL,PIND
	andi	BL,~(1<<F1 |1<<F2 |1<<F3 |1<<F4)
	or		BL,_Freg
	ori		BL,(1<<G1 |1<<G2 |1<<G3)
	out		PORTD,BL

	;Gombok
	in		BL,PIND
	andi	BL,(1<<G1 |1<<G2 |1<<G3)
	lds		BH,Gstatus
	eor		BH,BL
	breq	G_nochange
	sbrc	BH,G1
	rcall	G1_handler
	sbrc	BH,G2
	rcall	G2_handler
	sbrc	BH,G3
	rcall	G3_handler
	sts		Gstatus,BL
	rcall	ValToDigits
	rcall	DigitOut
G_nochange:

	;Input state
	dec		_Itimeout
	brne	Istate_active
	outi 	USISR,0						;Clear counter
	ldi		_Itimeout,120
Istate_active:

	popw	B
	popw	A
	out		SREG,_Status
	pop		_Status
	reti

G1_handler:
	sbrc	BL,G1
	ret
	stsi3	Value,1000
	ret

G2_handler:
	sbrc	BL,G2
	ret
	stsi3	Value,2000
	ret

G3_handler:
	sbrc	BL,G3
	ret
	stsi3	Value,3000
	ret

;----
;_1Hz
;----
_1Hz:
	push	_Status
	in		_Status,SREG
	pushw	A
	pushw	Z

;	inc		_State
;	andi	_State,1
;	brne	do_value
;	ldiw	Z,(2*St_Error)
;	rcall	putstr
;	rjmp	_1Hz_ret

;do_value:
;	rcall	ValToDigits
;	rcall	DigitOut

_1Hz_ret:	
	popw	Z
	popw	A
	out		SREG,_Status
	pop		_Status
	reti


;----------------
;SlaveSPITransfer
;----------------
SlaveSPITransfer:
	out 	USIDR,r16
	ldi 	r16,(1<<USIOIF)
	out 	USISR,r16
SlaveSPITransfer_loop:
	sbis 	USISR,USIOIF
	rjmp 	SlaveSPITransfer_loop
	in 		r16,USIDR
	ret


.def 	rem24L 		= r3
.def 	rem24M 		= r4
.def 	rem24H 		= r5
.def 	result24L 	= r9
.def 	result24M 	= r10
.def 	result24H 	= r11
.def 	dvd24L 		= r9
.def 	dvd24M 		= r10
.def 	dvd24H 		= r11
.def 	dvr24L 		= r18
.def 	dvr24M 		= r19
.def 	dvr24H 		= r20
.def 	rLoopCnt	= r21
.def 	rDigitCnt	= r22

;-----------
;ValToDigits
;-----------
ValToDigits:
	push 	rem24L
	push 	rem24M
	push 	rem24H
	push 	dvd24L
	push 	dvd24M
	push 	dvd24H
	push 	dvr24L
	push 	dvr24M
	push 	dvr24H
	push 	rLoopCnt
	pushw	Z

	lds		dvd24L,Value+0
	lds		dvd24M,Value+1
	lds		dvd24H,Value+2

	lds		dvr24L,Voffset+0
	sub		dvd24L,dvr24L
	lds		dvr24L,Voffset+1
	sbc		dvd24M,dvr24L
	lds		dvr24L,Voffset+2
	sbc		dvd24H,dvr24L

	lds		dvr24L,Vcenter+0
	sub		dvd24L,dvr24L
	lds		dvr24L,Vcenter+1
	sbc		dvd24M,dvr24L
	lds		dvr24L,Vcenter+2
	sbc		dvd24H,dvr24L

	stsi	Digits+6,Ch_sp
	tst		dvd24H
	brpl	ValPositive
	stsi	Digits+6,Ch_mi
	com		dvd24L
	com		dvd24M
	com		dvd24H
	adc		dvd24L,_0
	adc		dvd24M,_0
	adc		dvd24H,_0
ValPositive:
	ldi		dvr24L,10
	clr		dvr24M
	clr		dvr24H
	clr		rDigitCnt
	ldi		rLoopCnt,6

ValToDigitsLoop:
	rcall	CalcDigit
	ldiw	Z,Digits
	add		ZL,rDigitCnt
	adc		ZH,_0
	st		Z,rem24L
	inc		rDigitCnt
	dec		rLoopCnt
	brne	ValToDigitsLoop

	rcall	DigitOut

	popw	Z
	pop 	rLoopCnt
	pop	 	dvr24H
	pop	 	dvr24M
	pop	 	dvr24L
	pop	 	dvd24H
	pop	 	dvd24M
	pop	 	dvd24L
	pop	 	rem24H
	pop	 	rem24M
	pop	 	rem24L
	ret

;---------
;CalcDigit
;---------
CalcDigit:
	cp		dvd24L,_0
	cpc		dvd24M,_0
	cpc		dvd24H,_0
	breq	CalcDigitZero
	rcall	div24u
	ldiw	Z,HexTo7
	add		ZL,rem24L
	ld		rem24L,Z
	ret
CalcDigitZero:
	cpi		rDigitCnt,0
	brne	CalcDigitZeroSpace
	ldiw	Z,HexTo7
	ld		rem24L,Z
	ret
CalcDigitZeroSpace:
	ldi		ZL,Ch_sp
	mov		rem24L,ZL
	ret

;--------
;DigitOut
;--------
DigitOut:
	outi	PORTD,(1<<G1 |1<<G2 |1<<G3)
	ldiw	Y,Digits
	ldi		AL,7
DigitOut_loop:
	ld		_Oreg,Y+
	cp		_DPpos,AL
	brne	DigitOut_nodp
	ldi		AH,DPg
	or		_Oreg,AH
DigitOut_nodp:
	rcall	ShiftOut
	dec		AL
	brne	DigitOut_loop
	mov		AL,_Freg
	ori		AL,(1<<G1 |1<<G2 |1<<G3)
	out		PORTD,AL
	ret

;--------
;ShiftOut
;--------
ShiftOut:
	push	AL
	ldi		AL,8
ShiftOut_loop:
	tst		_Oreg
	brmi	ShiftOut_High
	cbi		PORTB,DOUT
	rjmp	ShiftOut_send
ShiftOut_High:
	sbi		PORTB,DOUT
ShiftOut_send:
	sbi		PORTB,DCK
	cbi		PORTB,DCK
	rol		_Oreg
	dec		AL
	brne	ShiftOut_loop
	pop		AL
	ret
	
;-----------
;CopyToRam
;-----------
CopyToRam:
	rcall	EEPROM_read
	st		Z+,AL
	adiw 	Y,1
	dec		AH
	brne	CopyToRam
	ret

;-----------
;EEPROM_read
;-----------
EEPROM_read:
	sbic 	EECR,EEPE					;Wait for completion of previous write
	rjmp 	EEPROM_read
	out 	EEAR,YL						;Set up address (r18:r17) in address register
	sbi 	EECR,EERE					;Start eeprom read by writing EERE
	in 		_Temp,EEDR					;Read data from data register
	ret


;******** div24u *********** 
;*Unsigned* Division 24bit/24bit 
;* Dividend(dvd) 
;* Result = --------------- 
;* Divisor(dvr) 
;* 
;* 

div24u: 
	push 	rLoopCnt
	clr 	rem24L 				;clear remainder Low byte 
	clr 	rem24M 				;clear remainder mid byte 
	sub 	rem24H,rem24H 		;clear remainder High byte and carry 
	ldi 	rLoopCnt,25 		;init loop counter 

d16u_1: 
	rol 	dvd24L 				;shift left dividend 
	rol 	dvd24M 
	rol 	dvd24H 
	dec 	rLoopCnt 			;decrement counter 
	brne 	d16u_2 				;if done 
	pop 	rLoopCnt
	ret 						; return 

d16u_2: 
	rol 	rem24L 				;shift dividend into remainder 
	rol 	rem24M 
	rol 	rem24H 
	sub 	rem24L,dvr24L 		;remainder = remainder - divisor 
	sbc 	rem24M,dvr24M 		; 
	sbc 	rem24H,dvr24H 
	brcc 	d16u_3 				;if result negative 
	add 	rem24L,dvr24L 		; restore remainder 
	adc 	rem24M,dvr24M 
	adc 	rem24H,dvr24H 
	clc 						; clear carry to be shifted into result 
	rjmp d16u_1 				;else 
d16u_3: 
	sec 						; set carry to be shifted into result 
	rjmp d16u_1 


;------
;putstr
;------
putstr:
	;Call:	Z = string pointer
	pushw	B
	pushw	Y
	ldiw	Y,Digits+7
	lpm		BH,Z+
putstr_loop:
	lpm		BL,Z+
	st		-Y,BL
	dec		BH
	brne	putstr_loop
putstr_ret:
	rcall	DigitOut
	popw	Y
	popw	B
	ret

St_Error:	.DB		7,Ch_E,Ch_r,Ch_r,Ch_o,Ch_r,Ch_sp,Ch_sp

