summaryrefslogtreecommitdiff
path: root/firmware/idp8_tx.asm
blob: 4361696585512cea14c5a2d431cfcaf819642865 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321

; *************************************
; * IDP8 (TX) assembler source        *
; * Written by: Dylan Muller          *
; * Target architecture: AVR ATtiny85 *
; *************************************

; IDP8 = Infrared Data Protocol 8

 .NOLIST
 .INCLUDE "tn85def.inc"
 .LIST 
 
 ; OCR1C timer value
 ; T_TOP ~ 50% (duty cycle) 38095 Hz square output on 0C1A
 ; Fo = Frequency output on 0C1A
 ; Fo = (8000000)/(2*(104+1))

.equ      T_TOP = 0x68
.def      tlapse = R21

; Protocol definitions (Specified in 100 microseconds)
; This is our chosen timer resolution
.equ      DPACKET_HEADER = 30  ; 3ms (3000μs)
.equ      DPDATA_0 =       20  ; 2ms (2000μs)
.equ      DPDATA_1 =       10  ; 1ms (1000μs)
.equ      TX_SLEEP =       200 ; 20ms
; Time our 38kHz burst pulse is high (IR receiver specific)
.equ      TXPULSE_HIGH =   6   ; 0.6ms (600μs)

; Define packet data to be transmitted for respective inputs
.equ      I0_PACKET_DATA = 0x1 ; 001  (last bit)(middle bit)(first bit) LSB
                               ; Least significant bit first
.equ      I1_PACKET_DATA = 0x4 ; 100
.equ      I2_PACKET_DATA = 0x5 ; 101
.equ      I3_PACKET_DATA = 0x7 ; 111

; Define input bit masks for PORTB
.equ      I0_MASK = (1 << PB0)
.equ      I1_MASK = (1 << PB2)
.equ      I2_MASK = (1 << PB3)
.equ      I3_MASK = (1 << PB4)


.CSEG
.ORG      0x00

; Define ISR (Interrupt Service Routine) vectors
; Reset vector
rjmp      reset
reti
reti  ; PCINT0 dummy vector for wake-up
reti
reti
reti
reti
reti
reti
reti
;TIMER0_COMPA - Timer 0 (Output Compare Match A) ISR
rjmp      tim0_compa ; 



;.org  0xF
; Reset vector ISR
reset:
; Stack initialize
ldi      R16,	low(RAMEND) ; 
out      SPL,	R16

; Load timer 1 TOP value
ldi      R16,	T_TOP 
out      OCR1C,	R16


; Initialize CTC mode + (CLK/8) prescaler select (TIMER 0)
ldi      R16,   (1 << WGM01)
out      TCCR0A,R16
ldi      R16,   (1 << CS01)
out      TCCR0B,R16

; Load OCR0A value for 0.1ms (100us) resolution on timer 0
; Each compare match calls the OCIE0A vector's ISR
; which increments the time lapsed (tlapse).
ldi      R16,   99 ; 0.1ms
out      OCR0A, R16    

; Initialize CTC mode + (CLK/1) prescaler select (TIMER 1)
ldi      R16,	(1 << CS10) | (1 << CTC1) 
out      TCCR1,	R16

; Enable output driver (0C1A)
sbi      DDRB,	1

;Enter power reduction mode | Disable: USI
ldi      R16,   (1 << PRUSI)
out      PRR,   R16

; Enable pin change interrupts for MCU wake up
; Set PCINT masks via PCMSK
ldi      R16,   (1 << PCIE)
out      GIMSK, R16
ldi      R16,   (1 << PCINT0) | (1 << PCINT2) | (1 << PCINT3) | (1 << PCINT4)
out      PCMSK, R16

sei ; Enable interrupts

; Main loop
main:
; Enters idle-sleep and waits for input
; Sleep mode is terminated upon an external pin change event/interrupt.

ldi      R16,   (1 << SE) ; Set SE bit + Idle mode
out      MCUCR, R16
sleep
clr      R16
out      MCUCR, R16

; Pin status checks
; Jumps to respective stub if relative status port (PINB) bit(s) are set

sbic	 PINB,  0
rjmp     istub0
sbic	 PINB,  2
rjmp     istub1
sbic	 PINB,  3
rjmp     istub2
sbic	 PINB,  4
rjmp     istub3

rjmp     main


; 0C1A output connect | Mode: Toggle on compare
oc1a_enable:
in       R16, TCCR1
ori      R16, (1 <<  COM1A0)
out      TCCR1, R16
clr      R16
out      TCNT1,	R16
ret

; 0C1A output disconnect
oc1a_disable: 
in       R16, TCCR1
andi     R16, ~(1 <<  COM1A0)
out      TCCR1, R16
ret

; Timer sub-routines for generating pulse delays
; specified in our protocol definition
; These functions are used when sending data packet(s)

; Reset time
tim0_reset:
clr      R16
out      TCNT0,	R16  
clr      tlapse
ret

; TIMER0_COMPA enabled 
tim0_start:
ldi      R16,   (1 << OCIE0A)
out      TIMSK, R16
rcall    tim0_reset
ret
; TIMER0_COMPA disabled 
tim0_stop:
clr      R16
clr      tlapse
out      TIMSK, R16
ret

; R23 = Time to wait in number of .1ms (100μs)
tim0_wait:
push     R16
rcall    tim0_start
tim0_loop:
cp       tlapse,R23
brne     tim0_loop
rcall    tim0_stop
pop      R16
ret

; * Pulse sub-routine *
; This sub-routine is responsible for the repeated 
; transmission of data packets.
; R20 = pin mask
; R22 = packet data

pulse_ms:  
push     R16
in       R16,	SREG ; Save status register
push     R20
push     R22

; Continuously transmit data packets until input release
pulse_loop:
rcall    transmit_packet
ldi      R23,TX_SLEEP
rcall    tim0_wait

in       R19,   PINB
and      R19,	R20
brne     pulse_loop

pop      R22
pop      R20
out      SREG,  R16
pop      R16
ret

; TIMER0_COMPA - Timer 0 (Output Compare Match A) ISR
; This ISR is used as the 100μs clock counter
tim0_compa:
inc  tlapse 
reti

; R22 = Packet data
transmit_packet:
; Transmit packet header
rcall    tx_ph

; Send all 3 data bits

sbrc     R22, 0
rcall    txd1
sbrs     R22, 0
rcall    txd0

sbrc     R22, 1
rcall    txd1
sbrs     R22, 1
rcall    txd0

sbrc     R22, 2
rcall    txd1
sbrs     R22, 2
rcall    txd0

; Send all 3 data bits inverted

sbrc     R22, 0
rcall    txd0
sbrs     R22, 0
rcall    txd1

sbrc     R22, 1
rcall    txd0
sbrs     R22, 1
rcall    txd1

sbrc     R22, 2
rcall    txd0
sbrs     R22, 2
rcall    txd1

rjmp tx_ret

; Generate 38kHz IR burst
tx_38irp:
rcall    oc1a_enable
ldi      R23,    TXPULSE_HIGH
rcall    tim0_wait
rcall    oc1a_disable
ret
txd1:
; Transmit logic 1
rcall    tx_38irp
ldi      R23,    DPDATA_1
rcall    tim0_wait
ret

txd0:
; Transmit logic 0
rcall    tx_38irp
ldi      R23,    DPDATA_0
rcall    tim0_wait
ret

tx_ph:
; Transmit packet header
rcall    tx_38irp
ldi      R23,    DPACKET_HEADER
rcall    tim0_wait
ret

tx_ret:
; Transmit stop pulse
rcall    tx_38irp
ret

; Input stub handlers & masks
istub0:

ldi      R20,	I0_MASK
ldi      R22,	I0_PACKET_DATA
rcall    pulse_ms
rjmp     main

istub1:

ldi      R20,	 I1_MASK
ldi      R22,	 I1_PACKET_DATA
rcall    pulse_ms
rjmp     main

istub2:

ldi      R20,    I2_MASK
ldi      R22,	 I2_PACKET_DATA
rcall    pulse_ms
rjmp     main

istub3:

ldi      R20,    I3_MASK
ldi      R22,	 I3_PACKET_DATA
rcall    pulse_ms
rjmp     main