; Infrared remote control for Nikon D70 with Atmel 8bit MCU
;
; Copyright (C) 2005, 2006 Michele Bighignoli - Laives (BZ) - ITALY # www.bigmike.it/ircontrol
;
; Version 2.0.- 03/2006
;
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
;
;
; Implementation note:
; ---------------------------
; IR led is controlled by PD0 (with NPN transistor).
; Led is "on" when PD0 is high.
;
; This code has tested with ATTiny2313 and ATMEGA8535 with 8.0 MHz Xtal
;
; Should work with every Atmel 8bit MCU
;
;
; Special thanks to:
; ------------------
; Gerhard Schmidt (DG4FAC) - http://www.avr-asm-tutorial.net/index.html
; Brian Hammill - http://www.ipass.net/~hammill
;
;
; WaveForm data (03/2006 version):
;
; Infrared period = 26us (~38.4kHz)
;
; Strart pulse:  2000us
; pause:  27830us
; 1st pulse:   390us
; pause:   1580us
; 2nd pulse:   410us
; pause:   3580us
; 3rd pulse:   400us
; longpause: 63200us
;
; REPEAT ONE TIME
;

;.include "tn2313def.inc" ; ATTiny2313
;.include "2313def.inc" ; AT90S2313
.include "m88def.inc" ; Atmega88

.def Delayreg = R23
.def Mainloopc = R22
.def Counter = R21
.def Counter2 = R20


Reset:
 rjmp startup
 reti    ; ext int 0 (not used)
 reti    ; ext int 1 (not used)
 reti    ; timer1 (not used)
 reti    ;
 reti    ;
 reti    ; timer0 (not used)
 reti    ; UART RRF Not Used
 reti    ; UART TRE Not Used
 reti    ; UART TRDE Not Used
 reti    ; analog comparator not used


Delay130:
; This is a 13.0 uS delay (104 cycles @ 8MHz)
;
; sbi/cbi = 2 cycles
; rcall = 3 cycles
;
 nop
 nop
;
Delay130_led_on:
 nop
 nop
 nop
;
Delay130_led_off:
 nop
 nop
 ldi DelayReg,30  ; 1 cycle
Delay130_loop:
 dec  DelayReg   ; 1 cycle
 brne delay130_loop  ; 2 cycle if jump to label, 1 if not
 ret    ; 4 cycles


; Code executed at startup

Startup:
; stack is needed!
; initialize the stack pointer
;
; ENABLE IF "SPH" EXISTS
 ldi R16,HIGH(RAMEND)
 Out Sph , R16

 ldi R16,LOW(RAMEND)
 Out Spl , R16

; Set PortD = IN/OUT
 ldi R16,0b11111011
 Out Ddrd , R16

; ldi R16, 0b00000100 ; Pullup-Widerstand fuer Port D.2 setzen
; out PortD, R16  ; Bei Ansteuerung durch anderen Prozessor herausnehmen

; Set PortB = IN/OUT
 ldi R16,0b11111011
 Out Ddrb , R16

; ldi R16, 0b00000100 ; Pullup-Widerstand fuer Port B.2 setzen
; out PortB, R16  ; Bei Ansteuerung durch anderen Prozessor herausnehmen

Tastenschleife:
; Abfrage Rote  Taste
 in r16, PIND
 ldi R17,0b00000100
 And R17,R16
 brne Tastenschleife ; PD.2 gesetzt? (Rote Taste gedrueckt?)

; Abfrage auf Sleepmode-Anfrage an Port B.2
 in r16, PINB
 ldi R17,0b00000100
 And R17,R16
 breq Tastenschl1 ; Pb.2 gesetzt? (High). Anforderung für den Sleep-Modus
 rjmp ContinueToSleep

Tastenschl1:
 in r16, PIND
 ldi R17,0b00000100
 And R17,R16
 breq Tastenschl1 ; PD.2 gesetzt? (Rote Taste wieder losgelassen?)



 ldi  MainLoopC,; Send a complete waveform 2 times

Mainloop:

; Send start pulse (2000 uS)
 ldi Counter,77  ; (13 uS * 2 ) * 77 = 2002 uS
Startpulse:
 sbi PORTD,0   ; LED on
 rcall delay130_led_on  ; Wait 13.0 uS
 cbi PORTD,0   ; LED off
 rcall delay130_led_off  ; wait 13.0 uS
 dec Counter
 brne startpulse

; Pause (27830 uS)
 ldi Counter,237
Startpause:
 rcall delay130
 rcall delay130
 rcall delay130
 rcall delay130
 rcall delay130
 rcall delay130
 rcall delay130
 rcall delay130
 rcall delay130
 dec Counter
 brne startpause

 rcall delay130_led_off

; Send first pulse (390 uS)
 ldi Counter,15
Pulse1:
 sbi PORTD,0   ; LED on
 rcall delay130_led_on
 cbi PORTD,0   ; LED off
 rcall delay130_led_off
 dec Counter
 brne pulse1

; Pause (1580 uS)
 ldi Counter,118
Pause1:
 rcall delay130
 dec Counter
 brne pause1

 ldi Counter,5
Pause1b:
 dec Counter
 brne pause1b


; Send 2nd pulse (410 uS)
;
; NOTE: with Counter=16 the pulse width is 416 uS (counting the last "led off" time)
; using Counter=15 and an additional "led on", it           's possible to add the last 7 uS (led off) to the pause 2
;
; Counter=15 = 390 uS +
; "led on"   =  13 uS =
; TOTAL      = 403 uS
;

 ldi Counter,15
Pulse2:
 sbi PORTD,0   ; LED on
 rcall delay130_led_on
 cbi PORTD,0   ; LED off
 rcall delay130_led_off
 dec Counter
 brne pulse2

 sbi PORTD,0   ; LED on
 rcall delay130_led_on
 cbi PORTD,0   ; LED off

; Pause (3580 uS + 7 uS from pulse2 = 3587 uS)
 ldi Counter,136
Pause2:
 rcall delay130
 rcall delay130
 dec Counter
 brne pause2

; Send 3th pulse (400 uS) - (in real world = 403 uS)
 ldi Counter,15
Pulse3:
 sbi PORTD,0   ; LED on
 rcall delay130_led_on
 cbi PORTD,0   ; LED off
 rcall delay130_led_off
 dec Counter
 brne pulse3

 sbi PORTD,0   ; LED on
 rcall delay130_led_on
 cbi PORTD,0   ; LED off

 dec MainLoopC
; No long pause before sleep
 breq ContinueToSleep


; Pause for 63200 uS
 ldi Counter,239
Longpause:
 ldi Counter2,10
Longpause1:
 rcall delay130
 rcall delay130
 dec Counter2
 brne longpause1
 dec Counter
 brne longpause

; At moment : 63126 uS + 3 uS from pulse3 = 63129 uS

 ldi Counter,5
Longpause2:
 rcall delay130
 dec Counter
 brne longpause2

; At moment 63193 uS + 3 uS from pulse3 = 63196 uS

 ldi Counter,10  ; 3,75 uS
Longpause3:
 dec Counter
 brne longpause3

 rjmp mainloop

Continuetosleep:
 sleep
 rjmp reset
 rjmp ContinueToSleep