summaryrefslogtreecommitdiff
path: root/firmware/idp8_tx.asm
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/idp8_tx.asm')
-rw-r--r--firmware/idp8_tx.asm321
1 files changed, 321 insertions, 0 deletions
diff --git a/firmware/idp8_tx.asm b/firmware/idp8_tx.asm
new file mode 100644
index 0000000..4361696
--- /dev/null
+++ b/firmware/idp8_tx.asm
@@ -0,0 +1,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