;; Bitbanger - Copyright 2008 by Michael Kohn ;; Email: mike ta mikekohn.net ;; Web: http://www.mikekohn.net/ ;; ;; Bitbanging on a serial port example .include "m8def.inc" ; 4MHz / 1200baud = 3333.333 cycles per bit ; note: CLKSEL 1111 (add 4MHz crystal resonator to schematic) .equ TX_DATA = SRAM_START .equ TX_STATE = SRAM_START+1 ; 0 = idle 1 = go .equ TX_BITS = SRAM_START+2 .equ TX_BUSY = SRAM_START+3 ; 0 = ready 1 = busy .dseg .cseg .org 0x000 rjmp start .org 0x016 rjmp service_bit .org 0x01a rjmp service_bit ;; FIXME - erase this padding.. it's dumb .org 0x020 start: ;; I'm busy. Don't interrupt me! cli ;; clear the memory where servo info is eor r0, r0 ; r0 = constant 0 eor r1, r1 ; r1 = constant 1 inc r1 ldi r17, 4 ldi r27, TX_DATA>>8 ldi r26, TX_DATA&255 memset_serial: st X+, r0 dec r17 brne memset_serial ;; Set up stack ptr ldi r16, RAMEND>>8 out SPH, r16 ldi r16, RAMEND&255 out SPL, r16 ;; Set up PORTB ser r17 ldi r18, 0 out DDRB, r17 ; entire port B is output out PORTB, r17 ; turn off all of port B for fun out DDRC, r17 ; entire port C is output out PORTC, r17 ; turn on all of port C for fun ;; Set up TIMER1 ;lds r17, PRR ;andi r17, 255 ^ (1<>8) ; I think this could be 1 off out OCR1AH, r17 ldi r17, (3333&0xff) ; compare to 639 clocks (800 25MHz pixels) out OCR1AL, r17 ldi r17, (1<>8 ldi r30, (message*2)&255 main: lds r20, TX_BUSY ; poll uart to see if there is a data waiting sbrc r20, 0 rjmp main ; if no data, loop around ; TX_BUSY is false! we can write! lpm r25, Z+ ;ldi r25, 65 cpi r25, 0 breq done sts TX_DATA, r25 sts TX_BUSY, r1 sts TX_STATE, r1 rjmp main done: ; nothing more to do.. LOOP! rjmp done service_bit: ;; debug by toggling the hell out of PORTC (to see on the scope) eor r2, r2 dec r2 eor r26, r2 out PORTC, r26 ;; Check if new data needs to go out lds r18, TX_STATE ; if (TX_STATE==0) goto no_strobe cpi r18, 0 breq no_strobe out PORTB, r0 ; start bit sts TX_STATE, r0 ; unstrobe TX_STATE=0 ldi r18, 8 sts TX_BITS, r18 ; TX_BITS=8 ;sts TX_BUSY, r1 ; TX_BUSY=1 reti no_strobe: lds r18, TX_BUSY ; if (TX_BUSY==1) goto output_bit cpi r18, 1 breq output_bit ; this could be done with a skip instead of branch reti ; nothing to do. leave. output_bit: lds r19, TX_BITS ; if (TX_BITS>0) goto output_more_bits cpi r19, 0 brne output_more_bits out PORTB, r1 ; stop bit sts TX_BUSY, r0 ; done TX_BUSY = 0 reti output_more_bits: lds r18, TX_DATA sbrs r18, 0 out PORTB, r0 sbrc r18, 0 out PORTB, r1 lsr r18 sts TX_DATA, r18 dec r19 sts TX_BITS, r19 reti signature: .db "Atmel Bitbanger - Copyright 2008 - Michael Kohn - Version 0.01" message: .db "I'm now officially in the Bitbanger Club with Oliver Hillmann",0