; ; Function: collects clocked data bits from an RDS data decoder, ; then sends a block of them as six hex characters and a carriage return. ; ; This stream can be anaylsed in real time ; or recorded to a text file for later use. ; ; Written in 2000, source code lost, this is the commented disassembly. ; ; In 2000, I used an RS232 buffer, but today you can feed it into Serial-TTL-to-USB cable ; as made by FTDI. ; ; ; 2019-01-13 First draft. ; ; For the AVR AT90S2313 microcontroller: ; ; $08 ($28) ACSR Analog Comparator Control and Status Register ; $09 ($29) UBRR UART Baud Rate Register ; $0A ($2A) UCR UART Control Register ; $0B ($2B) USR UART Status Register ; $0C ($2C) UDR UART I/O Data Register ; $10 ($30) PIND Input Pins, Port D ; $11 ($31) DDRD Data Direction Register, Port D ; $12 ($32) PORTD Data Register, Port D ; $16 ($36) PINB Input Pins, Port B ; $17 ($37) DDRB Data Direction Register, Port B ; $18 ($38) PORTB Data Register, Port B ; $1C ($3C) EECR EEPROM Control Register ; $1D ($3D) EEDR EEPROM Data Register ; $1E ($3E) EEAR EEPROM Address Register ; $21 ($41) WDTCR Watchdog Timer Control Register ; $24 ($44) ICR1L T/C 1 Input Capture Register Low Byte ; $25 ($45) ICR1H T/C 1 Input Capture Register High Byte ; $2A ($4A) OCR1AL Output Compare Register 1 Low Byte ; $2B ($4B) OCR1AH Output Compare Register 1 High Byte ; $2C ($4C) TCNT1L Timer/Counter 1 Low Byte ; $2D ($4D) TCNT1H Timer/Counter 1 High Byte ; $2E ($4E) TCCR1B Timer/Counter 1 Control Register B ; $2F ($4F) TCCR1A Timer/Counter 1 Control Register A ; $32 ($52) TCNT0 Timer/Counter 0 (8-bit) ; $33 ($53) TCCR0 Timer/Counter 0 Control Register ; $35 ($55) MCUCR MCU general Control Register ; $38 ($58) TIFR Timer/Counter Interrupt Flag Register ; $39 ($59) TIMSK Timer/Counter Interrupt MaSK Register ; $3A ($5A) GIFR General Interrupt Flag Register ; $3B ($5B) GIMSK General Interrupt MaSK Register ; $3D ($5D) SPL Stack Pointer Low ; $3F ($5F) SREG Status Register ; ; Vector No. Program Address Source Interrupt Definition ; 1 $000 RESET Hardware Pin, Power-on Reset and ; Watchdog Reset ; 2 $001 INT0 External Interrupt Request 0 ; 3 $002 INT1 External Interrupt Request 1 ; 4 $003 TIMER1 CAPT1 Timer/Counter1 Capture Event ; 5 $004 TIMER1 COMP1 Timer/Counter1 Compare Match ; 6 $005 TIMER1 OVF1 Timer/Counter1 Overflow ; 7 $006 TIMER0 OVF0 Timer/Counter0 Overflow ; 8 $007 UART, RX UART, RX Complete ; 9 $008 UART, UDRE UART Data Register Empty ; 10 $009 UART, TX UART, TX Complete ; 11 $00A ANA_COMP Analog Comparator ; ; For this project. ; PD0 = RXD ; PD1 = TXD; ; ; According to my circuit: ; ; PB7 = SCK = RDS_CLK from LC7047M ; PB5 = MOSI = RDS_DATA from LC7047M ; ; But my code suggests I moved them later ; ; PB4 = RDS_DATA from LC7047M ; ; RDS CLK is interrupting the micro ; ; Anyway, I think this file will work with a little experimentation. ; I will post a corrected version when I have time to confirm the pins ; and recreate the source code. ; 0000 15 c0 rjmp 0x002c ; Reset handler 0002 37 c0 rjmp 0x0072 ; Interrupt handler ; ; Initialise UART ; RDS bit rate is 1,187.5 bits per second, 1/48th of the 57-kHz RDS subcarrier. ; So RS232 port only has to be fast enough to cope. ; Slower speed would allow a longer cable. ; 0004 2c e0 ldi r18, 0x0C ; 19200 baud at 4 MHz crystal 0006 29 b9 out 0x09, r18 ; $09 ($29) UBRR UART Baud Rate Register 0008 28 e1 ldi r18, 0x18 ; 000a 2a b9 out 0x0a, r18 ; $0A ($2A) UCR UART Control Register 000c 08 95 ret ; ; Wait until ready to send byte ; 000e 5d 9b sbis 0x0b, 5 ; Skip if bit 5 in USR UART Status Register is Set 0010 fe cf rjmp 0x000e ; loop back ; ; Okay, now send it. ; 0012 2c b9 out 0x0c, r18 ; $0C ($2C) UDR UART I/O Data Register 0014 08 95 ret ; ; send byte in r25 as hex ; 0016 92 95 swap r25 ; swap high and low nibbles 0018 01 d0 rcall 0x001c ; send l.s. nibble as hex 001a 92 95 swap r25 ; restore nibbles, fall into next routine. ; ; send l.s. nibble as hex ; 001c 89 2f mov r24, r25 001e 8f 70 andi r24, 0x0F ; least significant nibble 0020 8a 30 cpi r24, 10 ; compare with ten 0022 0c f0 brlt 0x0026 ; if less than ten, skip correction for A-F 0024 07 96 adiw r24, 7 ; add seven 0026 c0 96 adiw r24, '0' ; add ASCII '0' 0028 28 2f mov r18, r24 002a f1 cf rjmp 0x000e ; loop back to ; After reset - ; Intitialise port direction registers and stack pointer 002c 8b ee ldi r24, 0xEB ; binary 1110 1011 002e 87 bb out 0x17, r24 ; $17 ($37) DDRB Data Direction Register, Port B 0030 82 ef ldi r24, 0xF2 ; binary 1111 0010 0032 81 bb out 0x11, r24 ; $11 ($31) DDRD Data Direction Register, Port D 0034 8f ed ldi r24, 0xDF ; 223 0036 8d bf out 0x3d, r24 ; $3D ($5D) SPL Stack Pointer Low ; ; clear registers ; 0038 44 27 eor r20, r20 003a 00 24 eor r0, r0 003c 11 24 eor r1, r1 003e 22 24 eor r2, r2 0040 33 24 eor r3, r3 0042 44 24 eor r4, r4 0044 55 24 eor r5, r5 0046 11 27 eor r17, r17 0048 00 27 eor r16, r16 004a dc df rcall 0x0004 ; Initialise UART 004c 8f e0 ldi r24, 0x0F ; binary 0000 1111 004e 85 bf out 0x35, r24 ; $35 ($55) MCUCR MCU general Control Register 0050 80 e4 ldi r24, 0x40 ; binary 0100 0000 0052 8b bf out 0x3b, r24 ; $3B ($5B) GIMSK General Interrupt MaSK Register 0054 78 94 sei ; then do this endless loop. 0056 11 23 and r17, r17 ; test r17 0058 59 f0 breq 0x0070 ; might just as well do breq 0056 005a 95 2d mov r25, r5 005c dc df rcall 0x0016 ; send byte in r25 as hex 005e 94 2d mov r25, r4 0060 da df rcall 0x0016 ; send byte in r25 as hex 0062 93 2d mov r25, r3 0064 d8 df rcall 0x0016 ; send byte in r25 as hex 0066 11 27 eor r17, r17 ; r17 cleared 0068 2d e0 ldi r18, 0x0D ; Carriage Return marks end of block 006a d1 df rcall 0x000e ; Wait until ready to send byte 006c 77 24 eor r7, r7 ; r7 = 0 006e 78 ba out 0x18, r7 ; $18 ($38) PORTB Data Register, Port B 0070 f2 cf rjmp 0x0056 ; loop forever ; Interrupt handler ; it senses port B bits 2 and 4, ; so maybe my circuit is wrong? ; The RDS clock interrupts the micro ; to shift RDS data bits in. ; 0072 6f b6 in r6, 0x3f ; 63 0074 b2 9b sbis 0x16, 2 ; $16 ($36) Port B, bit 2 = 0076 08 e1 ldi r16, 0x18 ; $16 ($36) Port B = 00011000 0078 00 23 and r16, r16 ; test r16 007a 7a f0 brmi 0x009a ; r2,r1,r0 are some kind of shift register? 007c 00 0c add r0, r0 007e 11 1c adc r1, r1 0080 22 1c adc r2, r2 0082 b4 99 sbic 0x16, 4 ; skip if Port B, bit 4 = is clear 0084 03 94 inc r0 ; add the bit 0086 01 50 subi r16, 1 ; $16 ($36) Port B, decrement? 0088 00 00 nop 008a 39 f4 brne 0x009a 008c 1f ef ldi r17, 0xFF ; r17 tells foreground loop to send data 008e 77 24 eor r7, r7 ; r7 = 0 0090 73 94 inc r7 ; r7 = 1 0092 78 ba out 0x18, r7 ; $18 ($38) PORTB Data Register, Port B 0094 30 2c mov r3, r0 ; copy shift register into registers r3,4,5 to be sent as ASCII hex 0096 41 2c mov r4, r1 0098 52 2c mov r5, r2 009a 6f be out 0x3f, r6 ; $3F ($5F) SREG Status Register 009c 18 95 reti ; end of interrupt routine 009e ff ff .word 0xffff ; Blank = FF from here ; up to here. ; I think this must be configuration data, ; as the rjmp addresses are into the blank region. ; This micro has 2K = 8 x 256 = 0800 program words, ; so these bytes are not in program space. 0880 2a 02 muls r18, r26 0882 f8 e5 ldi r31, 0x58 ; 88 0884 2a 04 cpc r2, r10 0886 f8 e5 ldi r31, 0x58 ; 88 0888 cd 69 ori r28, 0x9D ; 157 088a 25 c1 rjmp 0x0ad6 088c c1 22 and r12, r17 088e 00 f8 bld r0, 0 0890 21 0a sbc r2, r17 0892 00 39 cpi r16, 0x90 ; 144 0894 e5 7e andi r30, 0xE5 ; 229 0896 23 66 ori r18, 0x63 ; 99 0898 6f 23 and r22, r31 089a 23 cd rjmp 0x02e2 089c 15 30 cpi r17, 0x05 ; 5 089e 21 08 sbc r2, r1 08a0 00 39 cpi r16, 0x90 ; 144 08a2 e5 7e andi r30, 0xE5 ; 229 08a4 23 66 ori r18, 0x63 ; 99 08a6 6f 23 and r22, r31 08a8 23 cd rjmp 0x02f0 08aa 15 30 cpi r17, 0x05 ; 5 08ac 2a 00 .word 0x002a ; ???? 08ae f8 2b or r31, r24