-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.asm
142 lines (113 loc) · 3.87 KB
/
main.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
; Capacity sensor, ATtiny85
; Clock 8mHz
; Antenna - PB3
; Charge electrode - PB2 (connect to the ground ot body)
; PWM output - PB0
.include "tn85def.inc"
.def rMP1 = r16 ; Multi-purpose register 1 = r16
.def rMP2 = r17 ; Multi-purpose register 2 = r17
.def rSUM = r6 ; Register to save sum = r6
.def rCOUNTER = r5 ; Counter register = r5
rjmp init ; Start from init
; ========== INIT ==========
init:
; Reset rSUM to 10 == number of readings
ldi rMP1, 10
mov rCOUNTER, rMP1
; Clear sum register
clr rSUM
cli ; Disable interrupts
sbi DDRB, DDB0 ; Set OC0A as output
sbi DDRB, DDB2 ; Set PB2 as output
; Setup Timer 0
; Fast PWM mode, output A low at cycle start
ldi rMP1, (1<<COM0A1)|(1<<COM0A0)|(1<<WGM01)|(1<<WGM00)
out TCCR0A, rMP1 ; To timer control register A
; Set Timer 0 Prescaler = 1
ldi rMP1, 1<<CS00
out TCCR0B, rMP1 ; To timer control register B
; PWM compare value
ldi rMP1,0 ; Start from 0% intensity
out OCR0A,rMP1 ; To compare match register A
sei ; Enable interrupts
rjmp loop ; To main loop
; ========== LOOP ==========
loop:
; Read antenna capacitance
; Calculate average value reading capacitance several times,
rcall readCap ; Capacitance value saved to rMP1
add rSUM, rMP1 ; rSUM += capValue
brcc repeatReadCap ; If it does not overflows, go to repeatReadCap label (repeat reading)
; If it overflows, set r6 to 255 (max value)
clr rSUM
dec rSUM
rjmp updatePWM ; Skip and go to updatePWM label
repeatReadCap:
dec rCOUNTER ; r5 is counting down the number of readings we've made
brne loop ; If r5 != 0, go to label loop (one more reading)
; Else, update PWM value
updatePWM:
; Reset rSUM to 10 == number of readings
ldi rMP1, 10
mov rCOUNTER, rMP1
lsr rSUM ; Divide sum by two and set volume level
out OCR0A,r6 ; to compare match register A
clr rSUM ; Clear sum value
rjmp loop ; Go to loop begin
; ========== CAPACITANCE READING ==========
.equ chargePin = 2
.equ antennaPin = 3
readCap:
; Setup ADC:
; Vcc as Aref (default)
; Left adjust
; Read from PB3
ldi rMP1, (1<<ADLAR|1<<MUX1|1<<MUX0)
out ADMUX, rMP1
; Start reading capacitance
cbi PORTB, antennaPin ; Ground antenna pin
cbi PORTB, chargePin ; Ground charge pin
ldi rMP1, 0b00011111 ; Prepare value for DDRB
out DDRB, rMP1 ; Set all port as output, load value
rcall wait ; Wait a bit for pin mode changing
cbi DDRB, antennaPin ; Set antenna pin as high-impedance input
rcall wait ; Wait a bit for pin mode changing
cli ; Disable interrupts (timing critical)
sbi PORTB, chargePin ; Set charge pin to high
rcall waitForCharge ; Wait a specific amount of time
rcall readADC ; Start reading
ret ; Return, value saved to rMP1
; ========== WAIT PROCEDURES ===========
; Simple wait for port mode changing
wait:
ldi rMP2, 10 ; Set counter value to 10
waitL:
dec rMP2 ; Decrease counter
brne waitL ; If counter != 0, go to waitL label
ret ; Else return
; Wait for capacitance changing
waitForCharge:
ldi rMP2,8 ; Set counter value to 8 (the value obtained by experiments)
waitForChargeL:
nop
nop
dec rMP2 ; Decrease counter
brne waitForChargeL ; If counter != 0, go to waitForChargeL label
ret ; Else return
; ========== ADC READING ============
readADC:
; Enable ADC
; Begin conversion cycle
; Clear interrupt flag
; Set division factor to 16
ldi rMP1, (1<<ADEN|1<<ADSC|1<<ADIF|1<<ADPS2)
out ADCSRA, rMP1
sei ; Enable interrupts
waitForConversion:
sbis ADCSRA, ADIF ; If conversion finished, skip the next command
rjmp waitForConversion ; Wait for conversion, go to waitForConversion label
in rMP2, ADCL ; Read low ADC byte to rMP2
in rMP1, ADCH ; Read high ADC byte to rMP1
sbrc rMP2, 7 ; If low byte >= 128, skip the next command
inc rMP1 ; Else increase rMP1 value
ret ; Return, capacitance value saved to rMP1