; Interactive Disk Spin, ; Copyright (c) 2007, Paul Stoffregen, paul@pjrc.com ; http://www.pjrc.com/disk_spin/ ; This program is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License ; as published by the Free Software Foundation; either version 2 ; of the License, or (at your option) any later version. ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. .include "mega16.asm" ;***************************************************************** ;** ** ;** Memory Allocation ** ;** ** ;***************************************************************** .dseg .org 0x60 prev_period_count: .byte 1 reading_buffer: .byte 64 .equ ramend = 0x60 + 1024 - 1 .equ sta013_data_addr = 0x2000 ;added to code by perl script! ;***************************************************************** ;** ** ;** Pinouts ** ;** ** ;***************************************************************** ;bit r18 (tens) r16 (ones) ;--- --- --- ;port A pinouts .equ thous_g_pin = 0 .equ thous_g_port = porta .equ thous_b_pin = 1 .equ thous_b_port = porta .equ hund_f_pin = 2 .equ hund_f_port = porta .equ hund_e_pin = 3 .equ hund_e_port = porta .equ hund_a_pin = 4 .equ hund_a_port = porta .equ hund_g_pin = 5 .equ hund_g_port = porta .equ hund_c_pin = 6 .equ hund_c_port = porta .equ hund_d_pin = 7 .equ hund_d_port = porta .equ porta_cfg = 0xFF .equ porta_default = 0xFF ;port B pinouts .equ thous_d_pin = 0 .equ thous_d_port = portb .equ thous_e_pin = 1 .equ thous_e_port = portb .equ thous_c_pin = 2 .equ thous_c_port = portb .equ thous_a_pin = 3 .equ thous_a_port = portb .equ thous_f_pin = 4 .equ thous_f_port = portb .equ mosi_pin = 5 .equ one_e_pin = 6 .equ one_e_port = portb .equ sck_pin = 7 .equ portb_cfg = 0xFF .equ portb_default = 0xFF ;port C pinouts .equ one_g_pin = 0 .equ one_g_port = portc .equ one_c_pin = 1 .equ one_c_port = portc .equ one_d_pin = 2 .equ one_d_port = portc .equ ten_d_pin = 3 .equ ten_d_port = portc .equ ten_c_pin = 4 .equ ten_c_port = portc .equ ten_g_pin = 5 .equ ten_g_port = portc .equ ten_b_pin = 6 .equ ten_b_port = portc .equ hund_b_pin = 7 .equ hund_b_port = portc .equ portc_cfg = 0xFF .equ portc_default = 0xFF ;port D pinouts .equ ten_a_pin = 0 .equ ten_a_port = portd .equ txd_pin = 1 .equ ten_f_pin = 2 .equ ten_f_port = portd .equ ten_e_pin = 3 .equ ten_e_port = portd .equ one_f_pin = 4 .equ one_f_port = portd .equ one_a_pin = 5 .equ one_a_port = portd .equ icp_pin = 6 .equ one_b_pin = 7 .equ one_b_port = portd .equ portd_cfg = 0xFF ^ (1<> 8) out sph, r16 ;Initialize all I/O pins (I/O docs start on page 47) ldi r16, porta_default out porta, r16 ldi r16, porta_cfg out ddra, r16 ldi r16, portb_default out portb, r16 ldi r16, portb_cfg out ddrb, r16 ldi r16, portc_default out portc, r16 ldi r16, portc_cfg out ddrc, r16 ldi r16, portd_default out portd, r16 ldi r16, portd_cfg out ddrd, r16 begin_loop: rcall uart_init ;pstr msg_booting rcall wipe_buffer rcall timer1_init rcall timer0_init clr r16 sts prev_period_count, r16 clr r20 clr r21 rcall print main_loop: mov r16, r_timeout ;rcall phex cpi r16, 255 breq timeout rcall get_period_measurement brtc main_loop rcall add_to_reading_buffer mov r16, r_timeout cpi r16, 68 brlo main_wait_to_display main_display: rcall sum_readings rcall get_numerator rcall div32u ;movw r16, r20 ;movw r18, r22 ;rcall phex32 ;rcall space rcall clip_to_9999 ;mov r16, r21 ;rcall phex ;mov r16, r20 ;rcall phex ;rcall space rcall print clr r_timeout rjmp main_loop main_wait_to_display: mov r16, r_timeout cpi r16, 68 brsh main_display rcall get_period_measurement brtc main_wait_to_display rcall add_to_reading_buffer rjmp main_wait_to_display timeout: clr r20 clr r21 rcall print rcall wipe_buffer clr r_timeout rjmp main_loop print: clr r19 print_1000: ldi r22, low(1000) ldi r23, high(1000) rcall print_ssub add r19, r16 rcall get_segments rcall print_thousand push r16 ldi r22, low(100) ldi r23, high(100) rcall print_ssub add r19, r16 rcall get_segments rcall print_hundred push r16 ldi r22, low(10) ldi r23, high(10) rcall print_ssub add r19, r16 rcall get_segments rcall print_ten push r16 mov r16, r20 ldi r19, 1 rcall get_segments rcall print_one mov r19, r16 pop r18 pop r17 pop r16 rcall cout_digit mov r16, r17 rcall cout_digit mov r16, r18 rcall cout_digit mov r16, r19 rcall cout_digit rcall newline ret get_segments: tst r19 breq get_segments_blank ldi Zl, low(segment_table * 2) ldi Zh, high(segment_table * 2) add Zl, r16 adc Zh, r_zero lpm r17, Z ret get_segments_blank: ldi r17, 0xFF ret print_one: sbrs r17, 6 cbi one_a_port, one_a_pin sbrc r17, 6 sbi one_a_port, one_a_pin sbrs r17, 5 cbi one_b_port, one_b_pin sbrc r17, 5 sbi one_b_port, one_b_pin sbrs r17, 4 cbi one_c_port, one_c_pin sbrc r17, 4 sbi one_c_port, one_c_pin sbrs r17, 3 cbi one_d_port, one_d_pin sbrc r17, 3 sbi one_d_port, one_d_pin sbrs r17, 2 cbi one_e_port, one_e_pin sbrc r17, 2 sbi one_e_port, one_e_pin sbrs r17, 1 cbi one_f_port, one_f_pin sbrc r17, 1 sbi one_f_port, one_f_pin sbrs r17, 0 cbi one_g_port, one_g_pin sbrc r17, 0 sbi one_g_port, one_g_pin ret print_ten: sbrs r17, 6 cbi ten_a_port, ten_a_pin sbrc r17, 6 sbi ten_a_port, ten_a_pin sbrs r17, 5 cbi ten_b_port, ten_b_pin sbrc r17, 5 sbi ten_b_port, ten_b_pin sbrs r17, 4 cbi ten_c_port, ten_c_pin sbrc r17, 4 sbi ten_c_port, ten_c_pin sbrs r17, 3 cbi ten_d_port, ten_d_pin sbrc r17, 3 sbi ten_d_port, ten_d_pin sbrs r17, 2 cbi ten_e_port, ten_e_pin sbrc r17, 2 sbi ten_e_port, ten_e_pin sbrs r17, 1 cbi ten_f_port, ten_f_pin sbrc r17, 1 sbi ten_f_port, ten_f_pin sbrs r17, 0 cbi ten_g_port, ten_g_pin sbrc r17, 0 sbi ten_g_port, ten_g_pin ret print_hundred: sbrs r17, 6 cbi hund_a_port, hund_a_pin sbrc r17, 6 sbi hund_a_port, hund_a_pin sbrs r17, 5 cbi hund_b_port, hund_b_pin sbrc r17, 5 sbi hund_b_port, hund_b_pin sbrs r17, 4 cbi hund_c_port, hund_c_pin sbrc r17, 4 sbi hund_c_port, hund_c_pin sbrs r17, 3 cbi hund_d_port, hund_d_pin sbrc r17, 3 sbi hund_d_port, hund_d_pin sbrs r17, 2 cbi hund_e_port, hund_e_pin sbrc r17, 2 sbi hund_e_port, hund_e_pin sbrs r17, 1 cbi hund_f_port, hund_f_pin sbrc r17, 1 sbi hund_f_port, hund_f_pin sbrs r17, 0 cbi hund_g_port, hund_g_pin sbrc r17, 0 sbi hund_g_port, hund_g_pin ret print_thousand: sbrs r17, 6 cbi thous_a_port, thous_a_pin sbrc r17, 6 sbi thous_a_port, thous_a_pin sbrs r17, 5 cbi thous_b_port, thous_b_pin sbrc r17, 5 sbi thous_b_port, thous_b_pin sbrs r17, 4 cbi thous_c_port, thous_c_pin sbrc r17, 4 sbi thous_c_port, thous_c_pin sbrs r17, 3 cbi thous_d_port, thous_d_pin sbrc r17, 3 sbi thous_d_port, thous_d_pin sbrs r17, 2 cbi thous_e_port, thous_e_pin sbrc r17, 2 sbi thous_e_port, thous_e_pin sbrs r17, 1 cbi thous_f_port, thous_f_pin sbrc r17, 1 sbi thous_f_port, thous_f_pin sbrs r17, 0 cbi thous_g_port, thous_g_pin sbrc r17, 0 sbi thous_g_port, thous_g_pin ret print_ssub: clr r16 print_ssub_loop: inc r16 sub r20, r22 sbc r21, r23 brcc print_ssub_loop add r20, r22 adc r21, r23 dec r16 ret clip_to_9999: or r22, r23 brne over_9999 movw r16, r20 subi r16, low(9999) sbci r17, high(9999) brsh over_9999 ret over_9999: ldi r20, low(9999) ldi r21, high(9999) ret ;fetch the numerator, which is (7372800 * r0) get_numerator: ldi Zl, low(numerator_table * 2) ldi Zh, high(numerator_table * 2) dec r0 lsl r0 lsl r0 add Zl, r0 adc Zh, r_zero lpm r20, Z+ lpm r21, Z+ lpm r22, Z+ lpm r23, Z+ ret .equ sum_threshold = (7372800 / 3) ;add together readings so that their cumulative time is ;as long as possible, but not exceeding "sum_threshold" ;so that we get as much averaging as possible but the ;response time is constrained. Of course, if the first ;reading exceeds sum_threshold, we return it anyway. ;otherwise, the result is always less than sum_threshold. sum_readings: ;ldi r16, '-' ;rcall cout clr r0 ;r0 = number we've added ldi Zl, low(reading_buffer) ldi Zh, high(reading_buffer) ld r16, Z+ ;r19/r18/r17/r16 = sum ld r17, Z+ ld r18, Z+ ld r19, Z+ inc r0 sum_readings_loop: ld r20, Z add r20, r16 ldd r21, Z+1 adc r21, r17 ldd r22, Z+2 adc r22, r18 ldd r23, Z+3 adc r23, r19 brcs sum_readings_done subi r20, ((sum_threshold >> 0) & 255) sbci r21, ((sum_threshold >> 8) & 255) sbci r22, ((sum_threshold >> 16) & 255) sbci r23, ((sum_threshold >> 24) & 255) brsh sum_readings_done ld r20, Z+ ld r21, Z+ ld r22, Z+ ld r23, Z+ add r16, r20 adc r17, r21 adc r18, r22 adc r19, r23 inc r0 cpi Zl, low(reading_buffer + 64) brne sum_readings_loop sum_readings_done: sbrs r19, 7 rjmp sum_readings_ok ldi r19, 0x7F ldi r18, 0xFF ldi r17, 0xFF ldi r16, 0xFF sum_readings_ok: ;rcall space ;push r16 ;mov r16, r0 ;rcall phex ;pop r16 ;rcall space ;rcall phex32 ;rcall newline ret ;add the newest measurement to the buffer of 16 most recent add_to_reading_buffer: ldi Zl, low(reading_buffer) ldi Zh, high(reading_buffer) add_to_reading_buffer_loop: ;rcall phex32 ;rcall space ld r20, Z ldd r21, Z+1 ldd r22, Z+2 ldd r23, Z+3 st Z+, r16 st Z+, r17 st Z+, r18 st Z+, r19 movw r16, r20 movw r18, r22 cpi Zl, low(reading_buffer + 64) brne add_to_reading_buffer_loop ;rcall newline ret wipe_buffer: ldi r16, 0x7F ldi Zl, low(reading_buffer) ldi Zh, high(reading_buffer) wipe_buffer_loop: st Z+, r16 cpi Zl, low(reading_buffer + 64) brne wipe_buffer_loop ret phex32: push r16 mov r16, r19 rcall phex mov r16, r18 rcall phex mov r16, r17 rcall phex pop r16 rjmp phex .def var10 = r20 .def var11 = r21 .def var12 = r22 .def var13 = r23 .def var20 = r16 .def var21 = r17 .def var22 = r18 .def var23 = r19 .def lc = r27 .def mod0 = r28 .def mod1 = r29 .def mod2 = r30 .def mod3 = r31 ;-----------------------------------------------------------------------------: ; 32bit/32bit Unsigned Division ; ; Register Variables ; Call: var1[3:0] = dividend (0x00000000..0xffffffff) ; var2[3:0] = divisor (0x00000001..0x7fffffff) ; mod[3:0] = ; lc = (high register must be allocated) ; ; Result:var1[3:0] = var1[3:0] / var2[3:0] ; var2[3:0] = ; mod[3:0] = var1[3:0] % var2[3:0] ; lc = 0 ; ; Size = 26 words ; Clock = 549..677 cycles (+ret) ; Stack = 0 bytes ; From http://elm-chan.org/docs/avrlib/div32.txt div32u: clr mod0 ;initialize variables clr mod1 ; mod = 0; clr mod2 ; lc = 32; clr mod3 ; ldi lc,32 ;/ div32u_loop: ;---- calcurating loop lsl var10 ;var1 = var1 << 1; rol var11 ; rol var12 ; rol var13 ;/ rol mod0 ;mod = mod << 1 + carry; rol mod1 ; rol mod2 ; rol mod3 ;/ cp mod0,var20 ;if (mod => var2) { cpc mod1,var21 ; mod -= var2; var1++; cpc mod2,var22 ; } cpc mod3,var23 ; brcs div32u_next ; inc var10 ; sub mod0,var20 ; sbc mod1,var21 ; sbc mod2,var22 ; sbc mod3,var23 ;/ div32u_next: dec lc ;if (--lc > 0) brne div32u_loop ; continue loop; ret ;***************************************************************** ;** ** ;** Timer 1 - Pulse Width Measurement ** ;** ** ;***************************************************************** ;"normal mode" - page 95 & 106 - WGM13,WGM12,WGM11,WGM10 = 0 timer1_init: clr r_zero clr r_t1_count_2 clr r_t1_count_3 clr r_prev_capture_0 clr r_prev_capture_1 clr r_prev_capture_2 clr r_prev_capture_3 clr r_period_count ldi r16, 0x00 out TCCR1A, r16 ;pg 104 ldi r16, 0x81 out TCCR1B, r16 ;pg 107 clr r16 out TCNT1H, r16 out TCNT1L, r16 ldi r16, 0x24 out TIMSK, r16 sei ret .def r_timeout = r1 .def r_status = r2 .def r_zero = r3 .def r_capture_0 = r4 .def r_capture_1 = r5 .def r_t1_count_2 = r6 .def r_t1_count_3 = r7 .def r_prev_capture_0 = r8 .def r_prev_capture_1 = r9 .def r_prev_capture_2 = r10 .def r_prev_capture_3 = r11 .def r_period_0 = r12 .def r_period_1 = r13 .def r_period_2 = r14 .def r_period_3 = r15 .def r_tmp = r24 .def r_tmp2 = r25 .def r_period_count = r26 t1_overflow_isr: ;4 to a lot... in r_status, sreg ;2 sec ;1 adc r_t1_count_2, r_zero ;1 adc r_t1_count_3, r_zero ;1 out sreg, r_status ;2 reti ;4 t1_capture_isr: ;4-8 (highest priority interrupt) in r_status, sreg ;2 ;first, grab the capture register - input capture, page 90 in r_capture_0, ICR1L ;2 in r_capture_1, ICR1H ;toggle the edge (doubles our resolution, useful for slow speed) in r_tmp, TCCR1B ldi r_tmp2, 0x40 ; toggle edge - page 107 eor r_tmp, r_tmp2 out TCCR1B, r_tmp ;if the capture was 00FF or less, the capture and overflow interrupts ;could have both been pending and we got executed before the overflow. tst r_capture_1 brne t1_capture_2 ;capture was 00FF or less, now check overflow flag. if it's clear, ;then the other interrupt routine already incremented the upper 16 ;bit could (and there's no way it could have been set again since ;the capture was so low and this is the higher priority interrupt). ;if the overflow is set, then we need to increment the count here. in r_tmp, TIFR sbrs r_tmp, TOV1 ;page 110 rjmp t1_capture_2 sec adc r_t1_count_2, r_zero ;increment the upper 16 bit count adc r_t1_count_3, r_zero ldi r16, (1<> 255) out UBRRH, r16 ldi r16, (ubrr_value & 255) out UBRRL, r16 ldi r16, 0 out UCSRA, r16 ldi r16, (1<> 8) & 255),((x1 >> 16) & 255),((x1 >> 24) & 255) .db (x2 & 255),((x2 >> 8) & 255),((x2 >> 16) & 255),((x2 >> 24) & 255) .db (x3 & 255),((x3 >> 8) & 255),((x3 >> 16) & 255),((x3 >> 24) & 255) .db (x4 & 255),((x4 >> 8) & 255),((x4 >> 16) & 255),((x4 >> 24) & 255) .db (x5 & 255),((x5 >> 8) & 255),((x5 >> 16) & 255),((x5 >> 24) & 255) .db (x6 & 255),((x6 >> 8) & 255),((x6 >> 16) & 255),((x6 >> 24) & 255) .db (x7 & 255),((x7 >> 8) & 255),((x7 >> 16) & 255),((x7 >> 24) & 255) .db (x8 & 255),((x8 >> 8) & 255),((x8 >> 16) & 255),((x8 >> 24) & 255) .db (x9 & 255),((x9 >> 8) & 255),((x9 >> 16) & 255),((x9 >> 24) & 255) .db (x10 & 255),((x10 >> 8) & 255),((x10 >> 16) & 255),((x10 >> 24) & 255) .db (x11 & 255),((x11 >> 8) & 255),((x11 >> 16) & 255),((x11 >> 24) & 255) .db (x12 & 255),((x12 >> 8) & 255),((x12 >> 16) & 255),((x12 >> 24) & 255) .db (x13 & 255),((x13 >> 8) & 255),((x13 >> 16) & 255),((x13 >> 24) & 255) .db (x14 & 255),((x14 >> 8) & 255),((x14 >> 16) & 255),((x14 >> 24) & 255) .db (x15 & 255),((x15 >> 8) & 255),((x15 >> 16) & 255),((x15 >> 24) & 255) .db (x16 & 255),((x16 >> 8) & 255),((x16 >> 16) & 255),((x16 >> 24) & 255) segment_table: .db 0x81,0xCF,0x92,0x86,0xCC,0xA4,0xA0,0x8F,0x80,0x84 ;0 .abc def. ;1 ..bc .... ;2 .ab. de.g aaa ;3 .abc d..g f b ;4 ..bc ..fg f b ;5 .a.c d.fg ggg ;6 .a.c defg e c ;7 .abc .... e c ;8 .abc defg ddd ;9 .abc d.fg msg_booting: .db 13,10,"Tach",13,10,0