;*************************************************************************** ;* ;* IPOD test application ;* ;* Copyright 2003, John Maushammer. Released under GPL license. ;* http://www.maushammer.com/systems/ipod-remote/ipod-remote.html ;* ;*************************************************************************** ;* ;* Target: ATtiny12-8PI ;* +---v---+ ;* pull high -> reset/PB5|1 8|vcc ;* rev button -> PB3|2 7|PB2 <-- output to ipod ;* fwd button -> PB4|3 6|PB1 not used ;* gnd|4 5|PB0 not used ;* +-------+ ;* ;* Buttons are pulled high by internal pullups; connect inputs through ;* normally open switches to ground. Output goes to VCC - if using a ;* VCC=+3.3v, then protect the ipod with a 1k ohm resistor. If using a ;* VCC=+5v, then you must use a divider to bring down the voltage and ;* provide a high output impedence. ;* ;* Internal oscillator @ 1.2MHz ;* ;* Program with: stk500 -dATTINY12 -iftest.hex -O -e -pf -vf -Sf3ff ;* (stores osc cal value at last byte in memory) ;* ;*************************************************************************** .include "tn12def.inc" ;***** Pin definitions .equ ipodTx =2 ;Transmit pin is PB2 .equ btnRev =3 ;reverse button PB3 .equ btnFwd =4 ;forward button PB4 (normally high, pulled low) ;***** Global register variables .def temp =R16 ;temporary storage register .def temp2 =R17 .def bitcnt =R18 ;bit counter .def TXipod =R21 ;***** OSCCAL value set by programmer .equ osccal_value =$1ff ;last byte of memory .cseg .org 0 ;interrupt table: rjmp reset rjmp ext_int0 rjmp pin_change ;pin change rjmp tim0_ovf ;timer rjmp ee_rdy ;eeprom ready rjmp ana_comp ;comparator ;***** Program Execution Starts Here reset: ldi ZH, high((osccal_value<<1)+1) ;get value set by programmer ldi ZL, low((osccal_value<<1)+1) lpm ; R0<-(Z) out OSCCAL, R0 ldi temp, 0b00000110 ; 1=out out DDRB, temp ldi temp, 0b00011000 ; pull up buttons (PB3 & 4) out PORTB, temp ;*************************************************************************** ;* Main loop ;* ;*************************************************************************** ;*************************************************************************** ;* ;* ipod remote control application ;* ;* Warning: uses all 3 stack levels: ipod_packet> putchar > delay main_loop: sbis PINB,btnFwd ;if button not pressed, skip rjmp ipod_fwd sbis PINB,btnRev rjmp ipod_rev ; other button inputs would go here... rjmp main_loop ipod_fwd: ldi TXipod, 0xf4 rcall ipod_wake ipod_fwd2: rcall ipod_packet sbis PINB,btnFwd ;if button not pressed, skip out of loop rjmp ipod_fwd2 rjmp ipod_rel ipod_rev: ldi TXipod, 0xf5 rcall ipod_wake ipod_rev2: rcall ipod_packet sbis PINB,btnRev ;if button not pressed, skip out of loop rjmp ipod_rev2 rjmp ipod_rel ipod_rel: ldi TXipod, 0xF0 ;button release code rcall ipod_packet rjmp main_loop ;*************************************************************************** ;* Unused interrupts ;* shouldn't be called, but if they are, then we'll know it. ;*************************************************************************** ext_int0: pin_change: tim0_ovf: ee_rdy: ana_comp: ;*************************************************************************** ;* ;* oscillator output test function. A not-quite symetrical square wave. ;* ;* For the tested chip, the correct OSCCAL value is $40 ;* ;* OSCCAL=0/uncal: 149.83 --> RC osc = 1048.8 = -12.6% ;* OSCCAL=40: 172.43 1207 = + 1.0% ;* OSCCAL=80: 202.86 1420 = +18.3% ;* OSCCAL=FF: 315.80 2210.6 = +84.2% ;* ;*************************************************************************** osctest: sbi DDRB,TxD ;set direction ot2: cbi PORTB,TxD ;send a '0' 2 cycles ; nop ; 1 cycle - this would make 50/50 nop ; 1 cycle sbi PORTB,TxD ;send a '1' 2 cycles rjmp ot2 ; 2 cycles ;*************************************************************************** ;* ;* ipod putchar ;* ;* This subroutine transmits the byte stored in the "TXbyte" register ;* Rate is 9600 baud (=125 cycles/bit @ 1.2MHz) ;* ;* input: TXbyte ;* registers: bitcnt, TXbyte, temp ;* stack: one level (UART_delay) ;* ;*************************************************************************** iputchar: ldi bitcnt,11 ;1+8+2 stopbits iputchar0: com TXbyte ;invert everything (so stop bits will be 1's) sec ;start bit ; cycle count if carry set clr ; --- --- iputchar1: brcc iputchar2 ;If carry set 1 2 cbi PORTB,ipodTx ; send a '0' 2 rjmp iputchar3 ;else 2 iputchar2: sbi PORTB,ipodTx ; send a '1' 2 nop ; 1 iputchar3: rcall UART_delay ;One bit delay total - 2*58 cycles rcall UART_delay ; (b=17) is 9600 baud exactly. lsr TXbyte ;Get next bit 1 1 dec bitcnt ;If not all bit sent 1 1 brne iputchar1 ; send next 2 2 ret ;*************************************************************************** ;* ;* iPod output routines - ipod_wake & ipod_packet ;* ;* Format: output normally low ;* high for 45 mSec ;* | output message @ 8N2, 9600 baud, lsb first ;* loop| low for 26 mSec ;* ;* VOL+ 0xFF 0xFD 0xF2 ;* VOL- 0xFF 0xFD 0xF3 ;* SKIP>> 0xFF 0xFD 0xF4 ;* < UARTdelay) ;* ;*************************************************************************** ipod_wake: sbi PORTB,ipodTx ; send a '1' ldi temp2,69 ; (775 + ?) * 69 = 53475 ~= 44.5 msec ldi temp, 0 ipod_wake2: rcall UART_delay1 ; 256 * 3 + 7 = 775 clocks dec temp2 brne ipod_wake2 ret ;*************************************************************************** ipod_packet: ldi TXbyte, 0x00 ; stop bits (inverted) ldi bitcnt,4 ; send 4 stop bits rcall iputchar2 ; alternate entry doesn't have start bit ldi TXbyte, 0xFF rcall iputchar ldi TXbyte, 0xFD rcall iputchar mov TXbyte, TXipod ldi bitcnt,12 ; 1+8+2 stopbits + 1 extra stop bit rcall iputchar0 cbi PORTB,ipodTx ; bring back down to 0 ldi temp2,40 ; (775 + ?) * 40 = 31000 ~= 25.8 msec ldi temp, 0 ipod_packet2: rcall UART_delay1 ; 256 * 3 + 7 = 775 clocks dec temp2 brne ipod_packet2 ret ;*************************************************************************** ;* ;* UART_delay ;* ;* This delay subroutine generates the required delay between the bits when ;* transmitting and receiving bytes. The total execution time is set by the ;* constant "b": ;* ;* 3·b + 7 cycles (including rcall and ret) ;* ;* At 1.2MHz, 17 cycles is just about right for 9600 baud. ;* ;* High registers used: temp ;* ;*************************************************************************** ;3 cycles (rcall) UART_delay: ldi temp,17 ;1 cycle UART_delay1: dec temp ;1 cycle brne UART_delay1 ;2/1 cycles ret ;4 cycles