; Reverse engineering tool for PLL ; in Uniden UH036SX UHF radio ; ; Ross Whenmouth 2007 ; ; ATtiny2313 target ; Atmel ATtiny2313 ; pin 1 RESET ; pin 2 RXD (PD0) Serial port RX data ; pin 3 TXD (PD1) Serial port TX data ; pin 4 XTAL2 18.432 MHz XTAL ; pin 5 XTAL1 18.432 MHz XTAL ; pin 6 PD2 ***SPARE*** ; pin 7 PD3 ***SPARE*** ; pin 8 PD4 ***SPARE*** ; pin 9 PD5 select CLOCK valid on rising or falling edge (high = rising, low = falling) ; pin 10 GND 0V ; pin 11 PD6 ***SPARE*** ; pin 12 PB0 DATA in ; pin 13 PB1 CLOCK in ; pin 14 PB2 STROBE in ; pin 15 PB3 ***SPARE*** ; pin 16 PB4 ***SPARE*** ; pin 17 PB5/MOSI ***SPARE*** ; pin 18 PB6/MISO ***SPARE*** ; pin 19 PB7/SCK ***SPARE*** ; pin 20 VCC +5V .include "tn2313def.inc" ; Register aliasing ; =r0 ; register for LPM instruction .def OLD =r15 ; previous input .def NEW =r16 ; latest input .def buffi =r17 ; ring buffer input pointer .def buffo =r18 ; ring buffer output pointer .def A =r20 ; working register A .def B =r21 ; working register B .def C =r22 ; working register C .def BUFF_OVF =r27 ; buffer overflow flag ;.def YL =r28 ; Y pointer low byte buffer input pointer ;.def YH =r29 ; Y pointer high byte ;.def ZL =r30 ; Z pointer low byte buffer ouput pointer ;.def ZH =r31 ; Z pointer high byte ; SRAM Memory Map ; ; 0x60 - 0x9F 64 byte Stack ; 0xA0 - 0xDF 64 byte ring buffer .cseg .org 0 ; interrupt table rjmp RESET ; Reset Handler ; rjmp INT0 ; External Interrupt0 Handle ; rjmp INT1 ; External Interrupt1 Handle ; rjmp TIM1_CAPT ; Timer1 Capture Handler ; rjmp TIM1_COMPA ; Timer1 CompareA Handler ; rjmp TIM1_OVF ; Timer1 Overflow Handler ; rjmp TIM0_OVF ; Timer0 Overflow Handler ; rjmp USART0_RXC ; USART0 RX Complete Handler ; rjmp USART0_DRE ; USART0,UDR Empty Handler ; rjmp USART0_TXC ; USART0 TX Complete Handler ; rjmp ANA_COMP ; Analog Comparator Handler ; rjmp PCINT ; Pin Change Interrupt ; rjmp TIMER1_COMPB ; Timer1 Compare B Handler ; rjmp TIMER0_COMPA ; Timer0 Compare A Handler ; rjmp TIMER0_COMPB ; Timer0 Compare B Handler ; rjmp USI_START ; USI Start Handler ; rjmp USI_OVERFLOW ; USI Overflow Handler ; rjmp EE_READY ; EEPROM Ready Handler ; rjmp WDT_OVERFLOW ; Watchdog Overflow Handler BOOTUP_start: ; system startup message, must be less than 63 bytes and be in first 0xff of program memory .db"Serial bus snooper v1.0a, by Ross Whenmouth, 2007 \n" BOOTUP_end: RESET: ldi A, 0b10000000 ; disable the analogue comaparator to save power out ACSR, A ldi A, 0b00000000 out DDRB, A ; PortB & D are all inputs out DDRD, A ldi A, 0b11111111 out PORTB, A ; turn on pullups on PortB & D out PORTD, A ldi A, 0x9F ; point the stack pointer at the top of Stack out SPL, A ldi YL, 0xA0 ; point buffer input pointer at start of buffer ldi YH, 0 ; Initalise the serial port ldi A, 0 ; set UART speed to 115,200 bps out UBRRH, A ldi A, 9 out UBRRL, A ldi A, 0b00000110 ; set 8 data bits, no parity, 1 stop bit out UCSRC, A ldi A, 0b00001000 ; enable transmitter ;ldi A, 0b00011000 ; enable receiver and transmitter out UCSRB, A ; put bootup message into buffer ldi ZH, 0x00 ; point X register at start of bootup message ldi ZL, LOW(BOOTUP_start) * 2 BOOTLOOP: cpi ZL, LOW(BOOTUP_end) * 2 brlo BOOTCHAR ; keep looping until we get to the end of the bootup message rjmp BOOTEND BOOTCHAR: lpm B, Z+ ; read character from bootup message in program memory rcall BUFF_IN ; add character in B to buffer BOOTEND: ; all done with bootup message ldi ZL, 0xA0 ; point buffer output pointer at start of buffer ldi ZH, 0 MAIN: sbis UCSRA,UDRE ; see if serial port is ready to send a byte rjmp POLL ; if not, keep polling PortB ldi BUFF_OVF, 0 ; clear the overflow flag cp ZL, YL ; if ZL == YL, then buffer is empty breq POLL ; keep polling PortB ld A, Z+ ; put byte from buffer into A and post increment Z pointer out UDR, A ; send byte to the UART cpi ZL, 0xE0 ; if ZL is off the end of the buffer, reset it to the start of buffer brlo POLL ldi ZL, 0xA0 POLL: ; Look for state change on PortB in NEW, PINB ; poll PortB cp OLD, NEW breq MAIN ; if PortB has not changed state then keep polling mov A, NEW ; make a copy of NEW PortB state EOR A, OLD ; XOR new state with old state sbrs A, 2 rjmp CLOCK ; if Strobe has not changed then check state of Clock input sbrs NEW, 2 ; if Strobe is 0 then send a "s" (ASCII 0x73) ldi B, 0x73 sbrc NEW, 2 ; if Strobe is 1 then send a "S" (ASCII 0x53) ldi B, 0x53 rcall BUFF_IN ; insert the ASCII character to send into the buffer ;rjmp END ; we are not interested in the state of Clock if Strobe has just changed state CLOCK: sbrs A, 1 ; if Clock input has not changed state then no need to output state of Data input rjmp END sbic PIND, 5 ; if PD5 is low then look for falling edge of Clock rjmp CLOCK_HI ; else look for rising edge of Clock CLOCK_LO: sbrs NEW, 1 ; if Clock is now low, then state change must have been high->low rjmp CLOCK_DATA ; output current state of Data input rjmp END ; else Clock change must have been low->high, so nothing to do. CLOCK_HI: sbrc NEW, 1 ; if Clock is now high, then state change must have been low->high rjmp CLOCK_DATA ; output current state of Data input rjmp END ; else Clock change must have been high->low, so nothing to do. CLOCK_DATA: sbrs NEW, 0 ; if Data is 0 then send a "0" (ASCII 0x30) ldi B, 0x30 sbrc NEW, 0 ; if Data is 1 then send a "1" (ASCII 0x31) ldi B, 0x31 rcall BUFF_IN ; insert the ASCII character to send into the buffer END: mov OLD, NEW ; OLD = NEW, so we can detect the next PortB state change rjmp MAIN BUFF_IN: sbrc BUFF_OVF, 0 ; if overflow flag set, return without putting data in buffer ret mov C, YL ; make a copy of pointer ZL to check for buffer overflow inc C inc C cpi C, 0xE0 ; if C is off the end of the buffer, reset it to the start of buffer brlo BUFF_IN_OVF ldi C, 0xA0 BUFF_IN_OVF: cpse C, ZL ; if C and ZL point to the same place, there is a buffer overflow! rjmp BUFF_IN_CHR ldi B, 0x21 ; stuff a "!" (ASCII 0x21) into the buffer so we know that there is an overflow ldi BUFF_OVF, 1 ; set the overflow flag BUFF_IN_CHR: st Y+, B ; put character in register B into the buffer with pointer post increment ldi C, 0xE0 ; if pointer has run off end of buffer then reset pointer to start of buffer cpse YL, C ret ; else return ldi YL, 0xA0 ret