diff options
Diffstat (limited to 'firmware/idp8_tx.asm')
-rw-r--r-- | firmware/idp8_tx.asm | 321 |
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 |