summaryrefslogtreecommitdiff
path: root/firmware/idp8_rx.asm
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/idp8_rx.asm')
-rw-r--r--firmware/idp8_rx.asm481
1 files changed, 481 insertions, 0 deletions
diff --git a/firmware/idp8_rx.asm b/firmware/idp8_rx.asm
new file mode 100644
index 0000000..cad5ae8
--- /dev/null
+++ b/firmware/idp8_rx.asm
@@ -0,0 +1,481 @@
+
+; *************************************
+; * IDP8 (RX) assembler source *
+; * Written by: Dylan Muller *
+; * Target architecture: AVR ATtiny85 *
+; *************************************
+
+; IDP8 = Infrared Data Protocol 8
+
+ .NOLIST
+ .INCLUDE "tn85def.inc"
+ .LIST
+
+ .equ CLK_DEL = 99
+ .equ TIM_THRESH = 5
+
+ ;f(t_timeout) = 25.5ms (25500μs) * TIM_THRESH
+ ; The desired packet timeout time must be multiplied by 25.5ms as a result of register (R25) overflow ,
+ ; used in conjunction with R26 to achieve longer time delays (see below)
+ ; and because our clock/counter has a 100us resolution.
+ ; The relative time-out delay is achieved by overflowing the 8-bit t_timeout(R25) register and thereafter
+ ; incrementing t_timeout_2(R26), continuously comparing R26 with TIM_THRESH,
+ ; until we exceed our delay threshold.
+
+.def packet_info = R24
+.def dinv_info = R19
+.def t_timeout = R25
+.def t_timeout_2 = R26
+
+; Protocol definitions (Specified as a multiple of 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)
+; Defines pulse delay tolerance
+.equ SIG_TOLERANCE = 1 ; +/- 100μs
+
+ ; Reserved registers
+ .def pflags = R21
+ .def tlapse = R20
+
+ ;TX packet data to be compared with
+.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
+
+; packet_info (R24) register explanation
+; 7 6 5 4 3 2 1 0 (bit positions) LSB
+; - - - - - - - - (packet_info) register
+; - - - - (packet_info mask bits)
+; The packet_info mask bits determine which bit should be validated upon a
+; jump to pk_dtest
+; 0 = Packet header validated
+; 1 = Data bit 1 validated
+; 2 = Data bit 2 validated
+; 3 = Data bit 3 validated
+; 4 = Data bit 1 value
+; 5 = Data bit 2 value
+; 6 = Data bit 3 value
+; 7 = Reserved
+
+; dinv_info (R19) register explanation
+; 7 6 5 4 3 2 1 0 (bit positions) LSB
+; - - - - - - - - (packet_info) register
+; The dinv_info (data inverted) information register is used to
+; capture and validate the 3 inverted data bits which are transmitted after
+; the 3 normal data bits, this mechanism is used to verify data integrity.
+
+; 0 = INV Data bit 1 validated
+; 1 = INV Data bit 2 validated
+; 2 = INV Data bit 3 validated
+; 3 = Reserved
+; 4 = INV Data bit 1 value
+; 5 = INV Data bit 2 value
+; 6 = INV Data bit 3 value
+; 7 = Reserved
+
+; pflags (R21) register explanation
+; 7 6 5 4 3 2 1 0 (bit positions) LSB
+; - - - - - - - - (pflags) register
+
+; 0 = Last pin status of pin 0 (PINB0)
+; 1 = tlapse register available for processing
+; Status bit 1 is set upon a low-high logic transition on input pin 0 (PINB0)
+
+.CSEG
+.ORG 0x00
+; Define ISR (Interrupt Service Routine) vectors
+; Reset vector
+rjmp reset
+reti
+; PCINT0 (Pin change interrupt) vector
+rjmp pc_int
+reti
+reti
+reti
+reti
+reti
+reti
+reti
+;TIMER0_COMPA - Timer 0 (Output Compare Match A) ISR
+rjmp tim0_compa
+;TIMER0_COMPA - Timer 0 (Output Compare Match B) ISR
+rjmp tim0_compb ; Timer compare interrupt
+
+;.org 0xF
+; Reset vector sub-routine
+reset:
+; Stack initialize
+ldi R16, low(RAMEND) ;
+out SPL, R16
+; Enable output drivers
+ldi R16, 0x1E
+out DDRB, R16
+; Initialize CTC mode + (CLK/8) prescaler select (TIMER 0)
+ldi R16, (1 << WGM01)
+out TCCR0A,R16
+ldi R16, (1 << CS01)
+out TCCR0B,R16
+ldi R16, CLK_DEL
+out OCR0A, R16
+ldi R16, CLK_DEL
+out OCR0B, R16
+;Enter power reduction mode | Disable: USI
+ldi R16, (1 << PRUSI)
+out PRR, R16
+; Enable pin change interrupts for wake up
+; Set PCINT masks via PCMSK
+ldi R16, (1 << PCIE)
+out GIMSK, R16
+ldi R16, (1 << PCINT0)
+out PCMSK, R16
+sei ; Enable interrupts
+
+; Main loop
+main:
+; Jump if we have a reading
+sbrc pflags,0x1
+rjmp smp_match
+rjmp main
+
+set_packet:
+ldi packet_info, 0x1
+rjmp smp_end
+packet_reset:
+clr packet_info
+rjmp smp_end
+
+smp_match:
+cli
+in R22, SREG
+; Has the packet header been validated?
+; i.e the packet header validation bit in the packet_header register
+; been set?
+sbrc packet_info, 0
+rjmp pd_aquire
+; If not test for packet header
+pkheader_test:
+cpi tlapse, (DPACKET_HEADER - SIG_TOLERANCE)
+brge pkht_upper
+rjmp smp_end
+pkht_upper:
+cpi tlapse, (DPACKET_HEADER + (SIG_TOLERANCE+1))
+brlo set_packet
+
+; Our packet header has been validated at this stage.
+pd_aquire:
+; Test if any of the 3 data bits in our packet have been processed.
+; If not jump to the respective handler routines
+sbrs packet_info, 1
+rjmp data_1
+sbrs packet_info, 2
+rjmp data_2
+sbrs packet_info, 3
+rjmp data_3
+; Testing remaining 3 inverted data bits
+sbrs dinv_info, 0
+rjmp dinv_1
+sbrs dinv_info, 1
+rjmp dinv_2
+sbrs dinv_info, 2
+rjmp dinv_3
+
+
+; At this stage all the data bits have been
+; successfully captured and validated.
+; We are ready to process our captured packet
+rjmp data_proc
+
+
+; Handler routines pass the relevant bit mask of the packet_info
+; register to the pk_dtest sub-routine.
+; This sub-routine's purpose is to validate the pulse delay
+; between high-low and low-high logic transitions (stored in tlapse)
+; on pin 0 (PINB0)
+; Furthermore the sub-routine uses this information to differentiate between logic 1
+; and logic 0 bit information provided the pulse delay is within configured bounds
+; for those respective logic levels.
+; The relevant packet bits are then set accordingly and a jump to smp_end
+; is executed
+data_1:
+ldi R23, 0x1
+rjmp pk_dtest
+data_2:
+ldi R23, 0x2
+rjmp pk_dtest
+data_3:
+ldi R23, 0x4
+rjmp pk_dtest
+
+dinv_1:
+ldi R23, 0x1
+rjmp dinv_test
+dinv_2:
+ldi R23, 0x2
+rjmp dinv_test
+dinv_3:
+ldi R23, 0x4
+rjmp dinv_test
+
+; Process data packet
+data_proc:
+; Optional unused status bit. Not needed in this case
+;sbr packet_info, 0x80
+;extract data bit values
+andi packet_info, 0x70
+ldi R16, 4
+shift_4:
+lsr packet_info
+dec R16
+brne shift_4
+; Compare packet data
+mov R16, packet_info
+cpi R16, I0_PACKET_DATA
+breq led
+mov R16, packet_info
+cpi R16, I1_PACKET_DATA
+breq led2
+mov R16, packet_info
+cpi R16, I2_PACKET_DATA
+breq led3
+mov R16, packet_info
+cpi R16, I3_PACKET_DATA
+breq led4
+rjmp smp_clear
+
+;data handler 1
+led:
+ldi R16, 0x2
+out PORTB, R16
+rjmp smp_clear
+;data handler 2
+led2:
+ldi R16, 0x4
+out PORTB, R16
+rjmp smp_clear
+;data handler 3
+led3:
+ldi R16, 0x10
+out PORTB, R16
+rjmp smp_clear
+;data handler 4
+led4:
+ldi R16, 0x8
+out PORTB, R16
+
+smp_clear:
+clr t_timeout
+clr t_timeout_2
+; Activate TIMER0_COMPB (tim0_compb) ISR
+in R16, TIMSK
+ori R16, (1<< OCIE0B)
+out TIMSK, R16
+rjmp packet_reset
+
+smp_end:
+clr tlapse
+clr R23
+; Clear second bit in pflags
+andi pflags, 0x1
+out SREG, R22
+sei
+rjmp main
+
+; Packet data test sub-routine
+; R23 = packet_info bit mask. This mask describes
+; which data bit is to be processed if it has not already.
+; As noted above, the individual bit meanings in the packet_info register
+; are as follows, starting with the least significant bit (LSB)
+; 7 6 5 4 3 2 1 0 (bit positions) LSB
+; - - - - - - - - (packet_info) register
+; - - - - (packet_info bit mask bits)
+; The packet_info mask bits determine which bit should be validated upon a
+; jump to pk_dtest
+; 0 = Packet header validated
+; 1 = Data bit 1 validated
+; 2 = Data bit 2 validated
+; 3 = Data bit 3 validated
+; 4 = Data bit 1 value
+; 5 = Data bit 2 value
+; 6 = Data bit 3 value
+; 7 = Reserved
+
+; After the sub-routine has finished execution
+; the relevant bits in the packet_info register
+; would have been set
+pk_dtest:
+
+; Shift R23 one bit to the left
+; All bit shifting found in this sub-routine
+; is used for setting the correct bits in the
+; packet_info register
+lsl R23
+; Perform validation via boundary checks,
+; taking into account pulse delay tolerances
+test_high:
+cpi tlapse, (DPDATA_1 - SIG_TOLERANCE)
+brge dhtest_upper
+rjmp test_low
+dhtest_upper:
+cpi tlapse, (DPDATA_1 + (SIG_TOLERANCE+1))
+brlo dset_high
+test_low:
+cpi tlapse, (DPDATA_0 - SIG_TOLERANCE)
+brge dltest_upper
+rjmp packet_reset
+dltest_upper:
+cpi tlapse, (DPDATA_0 + (SIG_TOLERANCE+1))
+brlo dset_low
+rjmp packet_reset
+
+; The tlapse register (pulse delay) has been validated to logic 1
+; the requested validation bit, set by the relevant mask,
+; is now set as well as the respective data value bit.
+dset_high:
+or packet_info, R23
+; shift 3 left
+ldi R16, 3
+shift_3:
+lsl R23
+dec R16
+brne shift_3
+or packet_info, R23
+rjmp smp_end
+
+; The tlapse register (pulse delay) has been validated to logic 0
+; the requested validation bit, obtained by the relevant mask,
+; is now set and the data value bit cleared.
+dset_low:
+or packet_info, R23
+rjmp smp_end
+
+dinv_reset:
+clr packet_info
+clr dinv_info
+rjmp smp_end
+
+
+dinv_test:
+dinvtest_high:
+cpi tlapse, (DPDATA_1 - SIG_TOLERANCE)
+brge dhtest_invupper
+rjmp invtest_low
+dhtest_invupper:
+cpi tlapse, (DPDATA_1 + (SIG_TOLERANCE+1))
+brlo dinv_hcheck
+invtest_low:
+cpi tlapse, (DPDATA_0 - SIG_TOLERANCE)
+brge dltest_invupper
+rjmp dinv_reset
+dltest_invupper:
+cpi tlapse, (DPDATA_0 + (SIG_TOLERANCE+1))
+brlo dinv_lcheck
+rjmp dinv_reset
+
+dinv_lcheck:
+or dinv_info, R23
+rjmp dinv_checkl
+dinv_hcheck:
+or dinv_info, R23
+lsl R23
+ldi R16, 3
+shiftinv_3:
+lsl R23
+dec R16
+brne shiftinv_3
+or dinv_info, R23
+dinv_checkl:
+mov R16, packet_info
+andi R16, 0x70
+and R16, R23
+cp R16, R23
+brne dinvchk_end
+rjmp dinv_reset
+dinvchk_end:
+rjmp smp_end
+
+
+; PCINT0 ISR
+; Pin change interrupt service routine
+; This ISR is used for timing the delay between
+; high-low and low-high state transitions.
+; This time delay is then stored in the tlapse register
+pc_int:
+in R22, SREG ; Save SREG
+sbrc pflags, 0
+rjmp pcint_htol
+
+; Status bit 0 in pflags was low before interrupt
+pcint_ltoh:
+sbic PINB, 0
+sbr pflags, 1
+
+sbrs pflags, 0
+rjmp pcint_ret
+in R16, TIMSK
+andi R16, (1 << OCIE0B)
+out TIMSK, R16
+; Signal reading status
+ori pflags, 0x2
+rjmp pcint_ret
+
+; Status bit 0 in pflags was high before interrupt
+pcint_htol:
+sbis PINB, 0
+cbr pflags, 1
+
+sbrc pflags, 0
+rjmp pcint_ret
+in R16, TIMSK
+ori R16, (1 << OCIE0A)
+out TIMSK, R16
+clr R16
+clr tlapse
+out TCNT0, R16
+
+pcint_ret:
+out SREG, R22
+reti
+
+; TIMER0_COMPA - Timer 0 (Output Compare Match A) ISR
+; This ISR is used as the 100μs clock counter
+tim0_compa:
+inc tlapse
+reti
+
+; TIMER0_COMPB - Timer 0 (Output Compare Match B) ISR
+; This ISR is activated upon setting any of the output
+; bits in the PORTB register.
+; The ISR serves as a timeout function ,setting all output
+; bits in the PORTB register to a logic 0 if a packet is not
+; received within the specified time threshold.
+; The TIM_THRESH preprocessor definition defines this time threshold.
+tim0_compb:
+in R22, SREG ; Save status register
+; Increment until t_timeout overflows
+inc t_timeout
+brne tim0_ret
+inc t_timeout_2
+; If t_timeout_2 matches our threshold value carry
+; on with execution
+cpi t_timeout_2, TIM_THRESH
+brlo tim0_ret
+
+; Clear respective registers
+clr R16
+out PORTB, R16
+out TCNT0, R16
+out TIMSK, R16
+clr tlapse
+clr t_timeout
+clr t_timeout_2
+clr pflags
+clr packet_info
+clr dinv_info
+
+tim0_ret:
+out SREG, R22 ; Restore status register
+reti