;************************************************
;* PROGRAM 20 [Mark 3] RC5 RECEIVER
;*
;* Chip Number 		: U1
;* File Name 		: Program 020_3 RC5MONO Receiver.asm
;* Date				: 07.28.2005
;* Last Update		: 12.16.2005
;* Version			: 3.0
;* Support Telephone: withheld
;* Support Fax		: withheld
;* Support E-mail	: digitan000@yahoo.com
;* Target MCU		: AT90S2313
;* Frequency		: 4.00MHz
;*
;* DESCRIPTION
;*
;* The following AVR program is designed for use as a 
;* "miniumum hardware" receiver for RC5 and similar 
;* data frames.
;*
;* This is a VERY basic RC5 decoder.  There is no error
;* checking.
;*
;* If IR input is used, the data must have the 38kHz or 36kHz
;* carrier removed.  Incoming bits must have the manchester
;* encoding format inverted.  The bit period is 1.778ms.  There are
;* 14 bits per frame, which each frame lasting for 24.892ms.
;* Frame are assumed to be seperated with a minimum 24.892ms
;* rest time.
;*
;* Useful IR detection modules that work with this program are
;* Radio Shack PN# 276-640, Sharp GP1U52X, Vishay TSOP1836, and
;* similar 3-pin modules.
;*
;* PORT USAGE SUMMARY
;* PortB:
;* Pins 0-7 are outputs.  Connect all Port B pins
;* to a LED bar display or similar
;*
;* PortD:
;* Pin #6 receives the carrier-free IR data.  The 
;* data source must send inverted (active-low) logic.
;*
;* DISCLAIMER
;*
;* ALL INFORMATION WITHIN THIS DOCUMENT IS PROVIDED
;* "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
;* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
;* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
;* I DO NOT GUARANTEE ANY INFORMATION IN THIS DOCUMENT IS 
;* ACCURATE, AND IT SHOULD BE USED FOR ABSTRACT EDUCATIONAL
;* PURPOSES ONLY. 
;*************************************************	
.nolist					; Stop listfile generation
.include "2313def.inc"	; Include command definitions file
.list					; Resume

;- Register Aliases -----
.def	group			= R1	; Frame's Group code
.def 	command			= R2	; Frame's Command code
.def 	remaining		= R3	; Half-bits remaining
.def	i_status		= R4	; Saves SREG during an interrupt
.def	status			= R5	; Zero = ready ; otherwise = busy
;.def					= R16	; General-purpose register by tradition
.def	loop			= R17	; Loop/increment counter by tradition
;.def	addr_a			= R18	; 8-bit Address-holder by tradition
;.def	addr_b			= R19	; 8-bit Address-holder by tradition
.def	i_temp			= R20	; Gen-purpose register for interrupts
.def	i_loop			= R21	; Interrupt-only loop counter

;- Define Constants -----
.equ 	frame_length	= 14	; Total Lenght of transmission
.equ	group_length	= 5		; Bits per group word (MUST NOT BE ZERO)
.equ	command_length	= 6		; Bits per data word
;- Macros ---------------
;------------------------

;########################
;# Flash Memory			#
;########################
.cseg					; Code (Flash) Segment Start
.org 0x00				; Start address: $0000

	rjmp main			; Reset Vector
;########################
;# Interrupt Vectors	#
;########################
	RETI			;Int0 Interrupt (IRQ0)
	RETI			;Int1 Interrupt (IRQ1)
	RETI			;TC1-Capture Event
	rjmp TC1_MATCHi	;TC1-Compare Match
	RETI			;TC1-Overflow
	RETI			;TC0-Overflow
	RETI			;UART Receive Transfer Complete
	RETI			;UART Data Register Empty
	RETI			;UART Transmit complete
	RETI			;Analog Comparator
;########################
;# End Interrupt Vectors#
;########################
main:
;---Port B Direction Set-
	ser R16				; R16 = 255
	out DDRB,R16		; All pins in output mode
;---Port D Direction Set-
	ldi R16,0b00011111	; Lowest bits in output mode
	out DDRD,R16		; Upper bits are inputs
;---Port D Initialize----
	ldi R16,0b00000000	; Bring output pins low
	out PORTD,R16		; No pull-up on IR input
;---PORT B Initialize----
	ser R16				; R16 = 255
	out PORTB,R16		; Bring output pins high
;---Stack Initialize-----
	ldi R16,(RAMEND)	; Address: 0xDF for AVR2313
	out SPL,R16			; (AVR2313 has low byte only)
LISTENING:
;---Check input for edge-
input_scan:
	lds R16,PIND + $20	; Load pin mirror value
	andi R16,0b01000000	; Mask all but input pin
	brne input_scan		; Hold until input pulls line low
;---Timer 1 Start--------
	ldi R16,(1<<CTC1)+(1<<CS11)	; Clear on compare match; Prescale: CLK/8
	out TCCR1B,R16		; Interval: 2.00us  Overflow: 512us
;---Timer 1 Compare Setup
	ldi R16,HIGH(221)	; Sent new compare-match overflow 
	out OCR1AH,R16		;
	ldi R16,LOW(221)	; New overflow: 443us (true quarter-bit period is 445us)
	out OCR1AL,R16		;
	ldi R16,(1<<OCIE1A)	; Sent: [6] Compare interrupt enabled
	out TIMSK,R16		;
	mov status,R16		; Put any non-zero value in "Status"
	SEI					; Global Interrupt Enable
;---Variable Set-up------
	clr R16				; R16 = 0
	mov group,R16		; Erase group code register
	mov command,R16			; Erase command/data register
	ldi R16,frame_length+1	; Total number of bits to collect?
	mov remaining,R16		; Copy
hold:
	or status,status	; Test status for "busy" state
	breq LISTENING		; Transfer done
	rjmp hold


TC1_MATCHi:
	in i_status,SREG	; Save system flags
	mov i_temp,remaining; Check bits remaining
	cpi i_temp,frame_length
	brcc GET_START		; No carry?  These are start bits
	cpi i_temp,frame_length - 1
	breq GET_PARITY		; Parity read on 3rd bit
	cpi i_temp,frame_length - group_length - 1
	brcc GET_GROUP		; Group read on 4th through 6th bits
	cpi i_temp,frame_length - group_length - command_length - 1
	brcc GET_COMMAND	; Command read on 7th thru 14th
	rjmp DO_DELAY		; 15th step is a 24.192ms delay

GET_START:
;---Adjust Interrupt Rate
	ldi R16,HIGH(888)	; Sent new compare-match overflow 
	out OCR1AH,R16		;
	ldi R16,LOW(888)	; New overflow: 1.776ms (true bit period is 1.778us)
	out OCR1AL,R16		;
	rjmp tc1_matchi_escape
GET_PARITY:
	rjmp  tc1_matchi_escape		; Ignore parity in this file version
GET_GROUP:
	rcall input_to_carry		; Copy bit on input pin to carry flag
	rol group					; Data arrives MSB first, so rotate left
	rjmp tc1_matchi_escape
GET_COMMAND:
	rcall input_to_carry		; Copy bit on input pin to carry flag
	rol command					; Data arrives MSB first, so rotate left
	rjmp tc1_matchi_escape
DO_DELAY:
	or remaining,remaining
	breq receiver_reset	; 16th step resets the receiver (when counter hits -1
	ldi i_temp,HIGH(12445)		; New timer1 overflow: 24.892ms
	out OCR1AH,i_temp			;
	ldi i_temp,LOW(12445)		;
	out OCR1AL,i_temp			;
;	rjmp tc1_matchi_escape

tc1_matchi_escape:
	dec remaining				; Decrement RC5 bits counter
	out SREG,i_status			; Restore system flags
tc1_matchi_done:
	reti
			
receiver_reset:
;---Set RC5 status to "ready"
	clr i_temp			; i_temp register = 0
	mov status,i_temp	; Reset status register to "ready"
;---Stop Timer 1---------
	ldi i_temp,(1<<CTC1); Clear on Timer1 Compare-match 
	out TCCR1B,i_temp	; Timer stopped
;---Print the RC5 Data---
	mov i_temp,command	; Load received command
	out PORTB,i_temp	; Send code to port B latch
	rjmp tc1_matchi_done; RC5 complete

input_to_carry:
	lds i_temp,PIND + $20	; Load port containing RC5 pin
	andi i_temp,0b01000000	; Mask all but input pin
	brne input_high
input_low:
	clc						; Clear carry flag
	ret						; Return to TC1 Match interrupt
input_high:
	sec						; Set carry flag
	ret						; Return to TC1 Match interrupt 