11 |
11 |
12 .org ADCCaddr |
12 .org ADCCaddr |
13 rjmp ADC_Interrupt |
13 rjmp ADC_Interrupt |
14 |
14 |
15 ;; SPI |
15 ;; SPI |
16 .equ SPI_DDR = DDRB |
16 .include "spi.inc" |
17 .equ SPI_PORT = PORTB |
|
18 .equ SPI_SCK = PORTB5 |
|
19 .equ SPI_MISO = PORTB4 |
|
20 .equ SPI_MOSI = PORTB3 |
|
21 .equ SPI_SS = PORTB2 |
|
22 |
|
23 .equ SPI_FLAGS = GPIOR0 |
|
24 .equ SPI_BUSY = 0 |
|
25 |
|
26 ;; Initialize SPI subsystem for master operation |
|
27 SPI_Init: |
|
28 ; Set modes |
|
29 sbi SPI_DDR, SPI_SCK ; Out |
|
30 sbi SPI_DDR, SPI_MOSI ; Out |
|
31 sbi SPI_DDR, SPI_SS ; Out |
|
32 |
|
33 ; Drive SS high (off) |
|
34 sbi SPI_PORT, SPI_SS |
|
35 |
|
36 ; Set control mode |
|
37 ; Enable interrupt |
|
38 ; Enable SPI |
|
39 ; MSB first |
|
40 ; Master mode |
|
41 ; Polarity/phase: Mode 0 (sample on rising edge) |
|
42 ; Clock rate 1/16 |
|
43 ldi r16, (1 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | (0 << CPOL) | (0 << CPHA) | (0b01 << SPR0) |
|
44 out SPCR, r16 |
|
45 |
|
46 ; Flags |
|
47 clr r0 |
|
48 out SPI_FLAGS, r0 |
|
49 |
|
50 ; Done |
|
51 ret |
|
52 |
|
53 ;; Send byte |
|
54 ;; Input: r16 |
|
55 ;; XXX: should not be busy... |
|
56 SPI_SendRecv: |
|
57 ; Flag |
|
58 sbi SPI_FLAGS, SPI_BUSY |
|
59 |
|
60 ; Enable slave (low) |
|
61 cbi SPI_PORT, SPI_SS |
|
62 |
|
63 ; Write byte (starts SCK) |
|
64 out SPDR, r16 |
|
65 |
|
66 ; Wait for interrupt |
|
67 ; Done |
|
68 ret |
|
69 |
|
70 ;; Wait for byte to be sent |
|
71 SPI_Wait: |
|
72 wait_idle: |
|
73 sbic SPI_FLAGS, SPI_BUSY ; Test for busy flag |
|
74 rjmp wait_idle ; loop |
|
75 |
|
76 ; Done |
|
77 ret |
|
78 |
|
79 ;; Service SPI interrupt |
|
80 SPI_Interrupt: |
|
81 ; Store SREG |
|
82 in r16, SREG |
|
83 |
|
84 ; Drive SS high (off) |
|
85 sbi SPI_PORT, SPI_SS |
|
86 |
|
87 ; Read |
|
88 in r10, SPDR |
|
89 |
|
90 ; Flag |
|
91 cbi SPI_FLAGS, SPI_BUSY |
|
92 |
|
93 ; Done |
|
94 out SREG, r16 |
|
95 reti |
|
96 |
17 |
97 ;; LCD |
18 ;; LCD |
98 .equ LCD_DDR = DDRB |
19 .include "led7seg.inc" |
99 .equ LCD_PORT = PORTB |
|
100 .equ LCD_OE = PORTB1 ; Output Enable (Low) |
|
101 |
|
102 ; Output font for 7-segment display |
|
103 LCD_Font: |
|
104 .db 0b00111111, 0b00000110 ; 0, 1 |
|
105 .db 0b01011011, 0b01001111 ; 2, 3 |
|
106 .db 0b01100110, 0b01101101 ; 4, 5 |
|
107 .db 0b01111101, 0b00000111 ; 6, 7 |
|
108 .db 0b01111111, 0b01100111 ; 8, 9 |
|
109 .db 0b01110111, 0b01111100 ; A, b |
|
110 .db 0b00111001, 0b01011110 ; C, d |
|
111 .db 0b01111001, 0b01110001 ; E, f |
|
112 .db 0b10000000, 0b00000000 ; ., |
|
113 |
|
114 ;.db 0b00111111, ; 0 |
|
115 ; 0b00000110, ; 1 |
|
116 ; 0b01011011, ; 2 |
|
117 ; 0b01001111, ; 3 |
|
118 ; 0b01100110, ; 4 |
|
119 ; 0b01101101, ; 5 |
|
120 ; 0b01111101, ; 6 |
|
121 ; 0b00000111, ; 7 |
|
122 ; 0b01111111, ; 8 |
|
123 ; 0b01100111, ; 9 |
|
124 ; 0b10000000, ; . |
|
125 ; 0b01000000 ; |
|
126 |
|
127 .equ LCD_0 = 0 |
|
128 .equ LCD_1 = 1 |
|
129 .equ LCD_2 = 2 |
|
130 .equ LCD_3 = 3 |
|
131 .equ LCD_4 = 4 |
|
132 .equ LCD_5 = 5 |
|
133 .equ LCD_6 = 6 |
|
134 .equ LCD_7 = 7 |
|
135 .equ LCD_8 = 8 |
|
136 .equ LCD_9 = 9 |
|
137 .equ LCD_A = 10 |
|
138 .equ LCD_B = 11 |
|
139 .equ LCD_C = 12 |
|
140 .equ LCD_D = 13 |
|
141 .equ LCD_E = 14 |
|
142 .equ LCD_F = 15 |
|
143 .equ LCD_DOT = 16 |
|
144 .equ LCD_EMPTY = 17 |
|
145 |
|
146 ;; Initialize LCD to empty, and enable |
|
147 LCD_Init: |
|
148 ; Setup ENable port |
|
149 sbi LCD_PORT, LCD_OE ; Disabled (Low) |
|
150 sbi LCD_DDR, LCD_OE ; Out |
|
151 |
|
152 ; empty |
|
153 ldi r16, 0b11111111 |
|
154 |
|
155 ; Output |
|
156 rcall SPI_SendRecv |
|
157 rcall SPI_Wait |
|
158 |
|
159 ; Enable |
|
160 cbi LCD_PORT, LCD_OE |
|
161 |
|
162 ; Done |
|
163 ret |
|
164 |
|
165 ;; Display a single digit on the display |
|
166 ;; Input: r16 |
|
167 LCD_Show: |
|
168 clr r0, 0 |
|
169 |
|
170 ; Prep address |
|
171 ; base addr for font table |
|
172 ldi ZH, high(2*LCD_Font) |
|
173 ldi ZL, low(2*LCD_Font) |
|
174 |
|
175 ; offset |
|
176 add ZL, r16 |
|
177 adc ZH, r0 |
|
178 |
|
179 ; Load char |
|
180 lpm r16, Z |
|
181 |
|
182 ;; Continue |
|
183 |
|
184 ;; Display a raw segment mask |
|
185 ;; Input: r16 |
|
186 LCD_ShowRaw: |
|
187 ; Invert |
|
188 ; com r16 |
|
189 |
|
190 ; Display |
|
191 rjmp SPI_SendRecv |
|
192 |
20 |
193 ;; ADC |
21 ;; ADC |
194 .equ ADC_DDR = DDRC |
22 .include "adc.inc" |
195 .equ ADC_PORT = PORTC |
|
196 .equ ADC_PIN = PORTC0 |
|
197 |
|
198 ;; Initialize the ADC for starting conversions |
|
199 ADC_Init: |
|
200 ; Setup ADMUX |
|
201 ; Use AVcc as ref |
|
202 ; Left-adjust result (for 8-bit access) |
|
203 ; Select ADC0 |
|
204 ldi r16, (0b01 << REFS0) | (1 << ADLAR) | (0b000 << MUX0) |
|
205 sts ADMUX, r16 |
|
206 |
|
207 ; Setup ADCSRB |
|
208 ; Free-running mode |
|
209 ldi r16, (0b000 << ADTS0) |
|
210 sts ADCSRB, r16 |
|
211 |
23 |
212 ; Setup ADCSRA |
24 ;; Utils |
213 ; Enable |
25 .include "delay.inc" |
214 ; Start right away... |
|
215 ; Auto-trigger |
|
216 ; Enable Interrupt |
|
217 ; Scale 1/128 |
|
218 ldi r16, (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADIE) | (0b111 << ADPS0) |
|
219 sts ADCSRA, r16 |
|
220 |
|
221 ; Disable digital circuit for pin |
|
222 ldi r16, (1 << ADC_PIN) |
|
223 sts DIDR0, r16 |
|
224 |
|
225 ; Debug LED |
|
226 sbi DDRD, PORTD7 |
|
227 sbi PORTD, PORTD7 |
|
228 |
|
229 ; Done |
|
230 ret |
|
231 |
|
232 ADC_Interrupt: |
|
233 ; Off |
|
234 cbi PORTD, PORTD7 |
|
235 |
|
236 ; Done |
|
237 reti |
|
238 |
|
239 ;; Read the current 8-bit ADC sample |
|
240 ; Returns value in r16 |
|
241 ADC_Read8: |
|
242 ; Copy |
|
243 lds r16, ADCH |
|
244 |
|
245 ; Done |
|
246 ret |
|
247 |
|
248 ;; Delay for approx. one second |
|
249 Delay_1s: |
|
250 ; 40 * 64k = 2.6M loops |
|
251 ldi r20, 40 |
|
252 |
|
253 ;; Delay for r20 * 64k cycles |
|
254 VarDelay: |
|
255 ldi r21, 255 |
|
256 |
|
257 ;; Delay for r20 * r21 * 255 cycles |
|
258 ShortDelay: |
|
259 ldi r22, 255 |
|
260 |
|
261 delay: |
|
262 dec r22 |
|
263 brne delay |
|
264 dec r21 |
|
265 brne delay |
|
266 dec r20 |
|
267 brne delay |
|
268 |
|
269 ret |
|
270 |
|
271 |
26 |
272 ;; Count down from 9 |
27 ;; Count down from 9 |
273 ; Returns once we've hit zero |
28 ; Returns once we've hit zero |
274 Main_Countdown: |
29 Main_Countdown: |
275 ; init from F |
30 ; init from F |
276 ldi r24, LCD_F |
31 ldi r24, LED7_F |
277 |
32 |
278 _count_loop: |
33 _count_loop: |
279 ; display |
34 ; display |
280 mov r16, r24 |
35 mov r16, r24 |
281 rcall LCD_Show |
36 rcall LED7_Show |
282 |
37 |
283 ; exit if zero |
38 ; exit if zero |
284 tst r24 |
39 tst r24 |
285 breq _count_end |
40 breq _count_end |
286 |
41 |