Example Program

;***************************************************************************
;* A P P L I C A T I O N N O T E F O R T H E A V R F A M I L Y
;*
;* Number : AVR410
;* File Name :"rc5.asm"
;* Title :RC5 IR Remote Control Decoder
;* Date :97.08.15
;* Version :1.0
;* Support telephone :+47 72 88 43 88 (ATMEL Norway)
;* Support fax :+47 72 88 43 99 (ATMEL Norway)
;* Target MCU :AT90S1200
;*
;* DESCRIPTION
;* This Application note describes how to decode the frequently used
;* RC5 IR remote control protocol.
;*
;* The timing is adapted for 4 MHz crystal
;*
;***************************************************************************
.include "1200def.inc"
.device AT90S1200

.equ    INPUT      =2              ;PD2
.equ    SYS_ADDR   =0              ;The system address

.def    S          =R0             ;Storage for the Status Register
.def    inttemp    =R1             ;Temporary variable for ISR
.def    ref1       =R2
.def    ref2       =R3             ; References for timing

.def    temp       =R16            ; Temporary variable

.def    timerL     =R17            ; Timing variable updated every 14 us
.def    timerH     =R18            ; Timing variable updated every 16 ms
.def    system     =R19            ; Address data received
.def    command    =R20            ; Command received

.def    bitcnt     =R21            ; Counter

.cseg
.org 0
        rjmp       reset
;********************************************************************
;* "TIM0_OVF" – Timer/counter overflow interrupt handler
;*
;* The overflow interrupt increments the "timerL" and "timerH"
;* every 64us and 16,384us.
;*
;* Crystal Frequency is 4 MHz
;*
;* Number of words:7
;* Number of cycles:6 + reti
;* Low registers used:1
;* High registers used: 3
;* Pointers used:0
;********************************************************************
.org OVF0addr
TIM0_OVF:
        in         S,sreg          ; Store SREG
        inc        timerL          ; Updated every 64us 
        inc        inttemp
        brne       TIM0_OVF_exit
        
        inc        timerH ; if 256th int inc timer

TIM0_OVF_exit:
        out        sreg,S ; Restore SREG
reti
;********************************************************************
;* Example program
;*
;* Initializes timer, ports and interrupts.
;*
;* Calls "detect" in an endless loop and puts the result out on
;* port B.
;*
;* Number of words: 16
;* Low registers used: 0
;* High registers used: 3
;* Pointers used: 0
;********************************************************************
reset:
        ;ldi        temp,low(RAMEND)   ;Initialize stackpointer for parts with SW stack
        ;out        SPL,temp
        ;ldi        temp,high(RAMEND)  ; Commented out since 1200 does not have SRAM
        ;out        SPH,temp

        ldi         temp,1             ;Timer/Counter 0 clocked at CK
        out         TCCR0,temp

        ldi         temp,1<<TOIE0      ;Enable Timer0 overflow interrupt
        out         TIMSK,temp

        ser         temp               ; PORTB as output
        out         DDRB,temp
        sei                            ;Enable global interrupt

main:
        rcall       detect             ;Call RC5 detect routine

        cpi         system,SYS_ADDR    ;Responds only at the specified address
        brne        release

        andi        command,0x3F       ;Remove control bit
        out         PORTB,command

        rjmp        main

release:
        clr         command            ;Clear PORTB
        out         PORTB,command
        rjmp        main

;********************************************************************
;* "detect" – RC5 decode routine
;*
;* This subroutine decodes the RC5 bit stream applied on PORTD
;* pin "INPUT".
;*
;* If success: The command and system address are
;* returned in "command" and "system".
;* Bit 6 of "command" holds the toggle bit.
;*
;* If failed: $FF in both "system" and "command"
;*
;* Crystal frequency is 4MHz
;*
;* Number of words:72
;* Low registers used: 3
;* High registers used: 6
;* Pointers used: 0
;********************************************************************
detect:
        clr         inttemp            ; Init Counters
        clr         timerH

detect1:
        clr         timerL

detect2:
        cpi         timerH,8           ;If line not idle within 131ms
        brlo        dl1
        rjmp        fault              ;then exit

dl1:
        cpi         timerL,55          ;If line low for 3.5ms
        brge        start1             ;then wait for start bit

        sbis        PIND,INPUT         ;If line is
        rjmp        detect1            ;low – jump to detect1
        rjmp        detect2            ;high – jump to detect2

start1:
        cpi         timerH,8           ;If no start bit detected
        brge        fault              ;within 130ms then exit
        
        sbic        PIND,INPUT         ;Wait for start bit
        rjmp        start1

        clr         timerL             ;Measure length of start bit

start2:
        cpi         timerL,17          ;If startbit longer than 1.1ms,
        brge        fault              ;exit

        sbis        PIND,INPUT
        rjmp        start2             ;Positive edge of 1st start bit

        mov         temp,timerL        ;timer is 1/2 bit time
        clr         timerL

        mov         ref1,temp
        lsr         ref1
        mov         ref2,ref1
        add         ref1,temp          ;ref1 = 3/4 bit time
        lsl         temp
        add         ref2,temp          ;ref2 = 5/4 bit time

start3:
        cp          timerL,ref1        ;If high period St2 > 3/4 bit time
        brge        fault              ;exit

        sbic        PIND,INPUT         ;Wait for falling edge start bit 2
        rjmp        start3
        clr         timerL
        ldi         bitcnt,12          ;Receive 12 bits
        clr         command
        clr         system

sample:
        cp          timerL,ref1        ;Sample INPUT at 1/4 bit time
        brlo        sample

        sbic        PIND,INPUT
        rjmp        bit_is_a_1         ;Jump if line high

bit_is_a_0:
        clc                            ;Store a '0'
        rol         command
        rol         system
                                       ;Synchronize timing
bit_is_a_0a:
        cp          timerL,ref2        ;If no edge within 3/4 bit time
        brge        fault              ;exit
        sbis        PIND,INPUT         ;Wait for rising edge
        rjmp        bit_is_a_0a        ;in the middle of the bit

        clr         timerL
        rjmp        nextbit

bit_is_a_1:
        sec                            ;Store a ’1’
        rol         command
        rol         system
                                       ;Synchronize timing
bit_is_a_1a:
        cp          timerL,ref2        ;If no edge within 3/4 bit time
        brge        fault              ;exit
        sbic        PIND,INPUT         ;Wait for falling edge
        rjmp        bit_is_a_1a        ;in the middle of the bit
        
        clr         timerL

nextbit:
        dec         bitcnt             ;If bitcnt > 0
        brne        sample             ;get next bit
                                       ;All bits sucessfully received!
        mov         temp,command       ;Place system bits in "system"
        rol         temp
        rol         system
        rol         temp
        rol         system

        bst         system,5           ;Move toggle bit
        bld         command,6          ;to "command"
                                       ;Clear remaining bits
        andi        command,0b01111111
        andi        system,0x1F
        
        ret

fault:
        ser         command            ;Both "command" and "system"
        ser         system             ;0xFF indicates failure
        ret