
;; Tachometer - Copyright 2010 by Michael Kohn
;; Email: mike to mikekohn.net
;;   Web: http://www.mikekohn.net/
;;
;; Count pulses per second from an IR circuit.

;.include "tn2313def.inc"
.device ATtiny2313

; 20MHz clock

; Timer 0: 20,000,000 / 256 = 78,145 interrupts = 1 second
; Timer 1: 16 bit counter, counting pulses on T1

; r0  = 0
; r1  = 1
; r2  = 0 so r2:r1 = 0
; r5  = flag main time is ready
; r13 = temp in interrupt
; r14 = temp in main funct
; r15 = 255
; r16 = r16:r31:r30  counts of the 8 bit interrupt overflow
; r17 = temp
; r18 = temp in funct
; r19 = send_char param
; r20 = read from rs232
; r26 = low byte of pulses per second count
; r27 = high byte of pulses per second count
; r30 = r16:r31:r30  counts of the 8 bit interrupt overflow
; r31 = r16:r31:r30  counts of the 8 bit interrupt overflow
;

; note: CLKSEL 1111
; lowfuse = 0x8f

.cseg

.org 0x000
  rjmp start
  reti
  reti
  reti
  rjmp zomg_timer1_a   ; a timer1 compare interrupt is a problem
  rjmp zomg_timer1     ; if we interrupt on TIMER1, something went wrong
  rjmp timer0_interrupt

start:
  ;; I'm busy.  Don't interrupt me!
  cli

  ;; Set up stack ptr
  ;ldi r17, RAMEND>>8
  ;out SPH, r17
  ldi r17, RAMEND&255
  out SPL, r17

  ;; r0 = 0, r1 = 1, r15 = 255
  clr r0
  clr r1
  inc r1
  clr r2
  clr r15
  dec r15

  clr r30            ; r16:r31:r30 = 0
  clr r31
  clr r16

  ; init variables
  clr r21
  mov r2, r1                   ; clear to send! (cts)

  ;; Set up rs232 baud rate
  ldi r17, ((20000000/(16*9600))-1) >> 8
  out UBRRH, r17
  ldi r17, ((20000000/(16*9600))-1) & 0xff
  out UBRRL, r17

  ;; Set up rs232 options
  ldi r17, (1<<UCSZ0)|(1<<UCSZ1)      ; sets up data as 8N1
  out UCSRC, r17
  ldi r17, (1<<TXEN)|(1<<RXEN)        ; enables send/receive
  out UCSRB, r17
  out UCSRA, r0

  ;; Set up PORTB
  out DDRB, r15
  out PORTB, r0

  ;; Set up TIMER0
  out TCCR0A, r0                 ; normal counting (0xffff is top, count up)
  ldi r17, (1<<CS00)             ; No prescaling
  out TCCR0B, r17

  ;; Set up TIMER1
  ;ldi r17, (299>>8)
  ;out OCR1AH, r17
  ;ldi r17, (299&0xff)            ; compare to 400 clocks (10kHz)
  ;out OCR1AL, r17

  out TCCR1C, r0
  out TCCR1A, r0                 ; normal counting (0xffff is top, count up)
  ldi r17, (1<<CS10)|(1<<CS11)|(1<<CS12)
  out TCCR1B, r17                ; Rising edge of T1 is clock

  ;; Set up interrupts for both timer modules
  ldi r17, (1<<TOIE0)
  out TIMSK, r17                 ; Interrupt on Timer 0 overflow only

  ; Fine, I can be interrupted now
  sei

main:
  in r20, UCSRA         ; poll uart to see if there is a data waiting
  sbrs r20, RXC
  rjmp no_echo          ; if no data, don't echo

  in r19, UDR
  rcall send_char       ; echo for debug

no_echo:
  sbrs r5, 0
  rjmp main

  clr r5

  ;; ZOMG DEBUG
  ;ldi r19, 10
  ;rcall send_char
  ;ldi r19, 13
  ;rcall send_char

  ;mov r19, r27
  ;rcall send_hex
  ;mov r19, r26
  ;rcall send_hex
  ;; ZOMG END

  ldi r19, 0xff
  rcall send_char
  ldi r19, 0xff
  rcall send_char

  mov r19, r27
  rcall send_char
  mov r19, r26
  rcall send_char

  rjmp main             ; do while(1)

; void send_char(r19)  : r14 trashed
send_char:
  in r14, UCSRA       ; check to see if it's okay to send a char
  sbrs r14, UDRE
  rjmp send_char      ; if it's not okay, loop around :)
  out UDR, r19        ; output a char over rs232
  ret

;; TIMER0 8 bit interrupt
timer0_interrupt:
  in r7, SREG

  ;sbi PORTB, 1        ; ZOMG DEBUG

  adiw r30, 1
  brne no_carry
  inc r16
no_carry:
  cpi r30, 0x41
  brne exit_interrupt
  cpi r31, 0x31
  brne exit_interrupt
  cpi r16, 0x01
  brne exit_interrupt
  rjmp read_time

exit_interrupt:
  out SREG, r7
  reti

read_time:
  in r26, TCNT1L
  in r27, TCNT1H
  out TCNT1H, r0
  out TCNT1L, r0
  out TCNT0, r0
  mov r5, r1         ; time flag

  clr r30            ; r16:r31:r30 = 0
  clr r31
  clr r16

  out SREG, r7
  reti

; void send_nibble(r19)  : r14, r18 trashed
send_nibble:
  cpi r19, 10
  brlo hex_nibble_under_10
  subi r19, 10
  ldi r18, 'A'
  add r19, r18
  rcall send_char
  ret
hex_nibble_under_10:
  ldi r18, '0'
  add r19, r18
  rcall send_char
  ret

; void send_hex(r19)  : r13, r14, r18, r24 trashed
send_hex:
  mov r13, r19
  swap r19
  andi r19, 0x0f
  rcall send_nibble
  mov r19, r13
  andi r19, 0x0f
  rcall send_nibble
  ldi r19, ' '
  rcall send_char
  ret

zomg_timer1:
  sbi PORTB, 0
  reti

zomg_timer1_a:
  sbi PORTB, 2
  reti

signature:
.db "Tachometer - Copyright 2010 - Michael Kohn - Version 0.01",0





