]> cloudbase.mooo.com Git - avrcpm.git/blob - avr/sw-uart.asm
df25d094d94b4b75b9ea08c1edd0bb9b9c247622
[avrcpm.git] / avr / sw-uart.asm
1 ; Serial interface using the ATmega8/88 USART.
2 ; This is part of the Z80-CP/M emulator written by Sprite_tm.
3 ;
4 ; Copyright (C) 2010 Leo C.
5 ;
6 ; This file is part of avrcpm.
7 ;
8 ; avrcpm is free software: you can redistribute it and/or modify it
9 ; under the terms of the GNU General Public License as published by
10 ; the Free Software Foundation, either version 3 of the License, or
11 ; (at your option) any later version.
12 ;
13 ; avrcpm is distributed in the hope that it will be useful,
14 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ; GNU General Public License for more details.
17 ;
18 ; You should have received a copy of the GNU General Public License
19 ; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
20 ;
21 ; $Id$
22 ;
23
24 #define SSER_BIT_TC (F_CPU+BAUD/2) / BAUD
25
26 #define RXBUFMASK RXBUFSIZE-1
27 #define TXBUFMASK TXBUFSIZE-1
28
29 .dseg
30
31 srx_state:
32 .byte 1
33 srx_char_to:
34 .byte 1
35 srx_dr:
36 .byte 1
37 ;srx_lastedge:
38 ; .byte 2
39 stx_bitcount:
40 .byte 1
41 stx_dr:
42 .byte 1
43 rxcount:
44 .byte 1
45 rxidx_w:
46 .byte 1
47 rxidx_r:
48 .byte 1
49 txcount:
50 .byte 1
51 txidx_w:
52 .byte 1
53 txidx_r:
54 .byte 1
55 rxfifo:
56 .byte RXBUFSIZE
57 txfifo:
58 .byte TXBUFSIZE
59
60
61 .cseg
62
63 ; Init
64 uart_init:
65
66 ; - Init clock/timer system and serial port
67
68 ; Init timer 1 as
69 ; - Soft UART TX (OC1A/OCR1A).
70 ; - Soft UART RX (ICP1/ICR1).
71 ; - 1ms System timer is already configured at this point.
72
73 ldi temp,(1<<COM1A1)|(1<<COM1A0) ;OC1A high on compare match (UART TX)
74 outm8 TCCR1A,temp
75
76 ldi temp,(1<<ICF1) ;clear pending int
77 out TIFR1,temp
78 inm8 temp,TIMSK1
79 ori temp,(1<<ICIE1) ;Enable input capture int. (UART RX)
80 outm8 TIMSK1,temp
81 ret
82
83 ;------------------------------------------------------------------
84
85 .cseg
86
87 ; Timer/Counter1 Input Capture interrupt
88
89 INTERRUPT ICP1addr
90
91 push temp
92 in temp,sreg
93 push temp
94 push zh
95 push zl
96 inm8 zl,ICR1L
97 inm8 zh,ICR1H
98 push temp2
99 ldi temp2,(1<<ICES1)
100 inm8 temp,TCCR1B
101 eor temp,temp2 ;toggle edge
102 outm8 TCCR1B,temp
103 ldi temp,(1<<ICF1) ;clear pending int
104 out TIFR1,temp
105
106 #if 0
107 lds temp,srx_state
108 subi temp,-'0'
109 rcall uartputc
110 lds temp,srx_dr
111 rcall printhex
112 #endif
113 lds temp,srx_state
114 cpi temp,0
115 brne srxi_S1
116
117 ; State 0: Wait for start bit
118
119 ; sts srx_lastedge,zl ;save beginning of start bit
120 ; sts srx_lastedge+1,zh
121 movw srx_lastedgel,zl
122 sts srx_dr,_0
123 ldi temp,1
124 sts srx_state,temp
125 ldi temp,2
126 sts srx_char_to,temp
127 sbis P_RXD-2,RXD ;RXD still low?
128 rjmp srxi_end2
129 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
130 outm8 TCCR1B,zl
131 ldi zh,(1<<ICF1) ;clear pending int
132 out TIFR1,zh
133 sts srx_state,_0
134 sts srx_char_to,_0
135 rjmp srxi_end2
136
137 srxi_S1:
138 cpi temp,1
139 brne srxi_S2
140
141 ; State 1: Check start bit (and collect 0-bits)
142
143 ; lds temp,srx_lastedge
144 ; lds temp2,srx_lastedge+1
145 ; sts srx_lastedge,zl
146 ; sts srx_lastedge+1,zh
147
148 movw temp,srx_lastedgel
149 movw srx_lastedgel,zl
150
151 sub zl,temp
152 sbc zh,temp2
153 subi zl,low ((SSER_BIT_TC+1)/2)
154 sbci zh,high((SSER_BIT_TC+1)/2)
155 brcs srxi_sberr
156
157 ; mov temp,zh
158 ; rcall printhex
159 ; mov temp,zl
160 ; rcall printhex
161
162 ldi temp,0x80
163 srxi_1l:
164 subi zl,low(SSER_BIT_TC)
165 sbci zh,high(SSER_BIT_TC)
166 brcs srxi_1be
167 lsr temp
168 brcc srxi_1l
169
170 subi zl,low(SSER_BIT_TC) ; stop bit?
171 sbci zh,high(SSER_BIT_TC)
172 brcc srxi_1fe
173 rjmp srxi_complete0 ; ok, x00 (^@) received
174 srxi_1fe:
175 sts srx_char_to,_0 ; no stop bit --> framing error --> break
176 sts srx_state,_0
177 sbr intstat,(1<<i_break) ;
178 sts rxcount,_0 ;clear rx buffer
179 sts rxidx_w,_0
180 sts rxidx_r,_0
181
182 rjmp srxi_end2
183
184 srxi_1be:
185 sts srx_dr,temp
186 ldi temp,2
187 sts srx_state,temp
188 rjmp srxi_end2
189
190 srxi_sberr:
191 ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
192 outm8 TCCR1B,temp
193 ldi temp,(1<<ICF1) ;clear pending int
194 out TIFR1,temp
195 sts srx_state,_0 ;next state
196 #if 1
197 ldi temp,'?'
198 rcall uartputc
199 subi zl,low (-(SSER_BIT_TC+1)/2)
200 sbci zh,high(-(SSER_BIT_TC+1)/2)
201 mov temp,zh
202 rcall printhex
203 mov temp,zl
204 rcall printhex
205 #endif
206 rjmp srxi_end2
207
208 srxi_S2:
209 cpi temp,2
210 brne srxi_S3
211
212 ; State 2: collect 1-bits
213
214 ; lds temp,srx_lastedge
215 ; lds temp2,srx_lastedge+1
216 ; sts srx_lastedge,zl
217 ; sts srx_lastedge+1,zh
218
219 movw temp,srx_lastedgel
220 movw srx_lastedgel,zl
221
222 sub zl,temp
223 sbc zh,temp2
224 subi zl,low ((SSER_BIT_TC+1)/2)
225 sbci zh,high((SSER_BIT_TC+1)/2)
226
227 lds temp,srx_dr
228 srxi_2l:
229 sec ;one more 1 bit
230 ror temp
231 brcs srxi_complete1 ;8 bits recieved
232 subi zl,low(SSER_BIT_TC)
233 sbci zh,high(SSER_BIT_TC)
234 brcc srxi_2l
235
236 sts srx_dr,temp
237 ldi temp,3
238 sts srx_state,temp
239 rjmp srxi_end2
240
241 srxi_complete1:
242 ldi temp2,1 ;We are in start bit now.
243 sts srx_state,temp2
244 ldi temp2,2
245 sts srx_char_to,temp2
246 rjmp srxi_complete
247
248 srxi_S3:
249 cpi temp,3
250 brne srxi_S4
251
252 ; State 3: collect 0-bits
253
254 ; lds temp,srx_lastedge
255 ; lds temp2,srx_lastedge+1
256 ; sts srx_lastedge,zl
257 ; sts srx_lastedge+1,zh
258
259 movw temp,srx_lastedgel
260 movw srx_lastedgel,zl
261
262 sub zl,temp
263 sbc zh,temp2
264 subi zl,low ((SSER_BIT_TC+1)/2)
265 sbci zh,high((SSER_BIT_TC+1)/2)
266
267 lds temp,srx_dr
268 srxi_3l:
269 ;one more 0 bit
270 lsr temp
271 brcs srxi_complete0 ;8 bits recieved
272 subi zl,low(SSER_BIT_TC)
273 sbci zh,high(SSER_BIT_TC)
274 brcc srxi_3l
275
276 sts srx_dr,temp
277 ldi temp,2
278 sts srx_state,temp
279 rjmp srxi_end2
280
281 srxi_S4:
282 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
283 outm8 TCCR1B,zl
284 ldi zl,(1<<ICF1) ;clear pending int
285 sts srx_state,_0 ;next state
286 rjmp srxi_end2
287
288 srxi_complete0:
289 sts srx_char_to,_0 ;clear timeout
290 sts srx_state,_0 ;next state
291 srxi_complete:
292 #if 0
293 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
294 outm8 TCCR1B,zl
295 ldi zl,(1<<ICF1) ;clear pending int
296 out TIFR1,zl
297 #endif
298
299 ; Save received character in a circular buffer. Do nothing if buffer overflows.
300
301 lds zh,rxcount ;if rxcount < RXBUFSIZE
302 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
303 brsh srxi_ov ;
304 inc zh ;
305 sts rxcount,zh ; rxcount++
306
307 ldi zl,low(rxfifo) ;
308 lds zh,rxidx_w ;
309 add zl,zh ;
310 inc zh ;
311 andi zh,RXBUFMASK ;
312 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
313 ldi zh,high(rxfifo) ;
314 brcc PC+2 ;
315 inc zh ;
316 st z,temp ; rxfifo[rxidx_w] = char
317 srxi_ov: ;endif
318
319 srxi_end2:
320 pop temp2
321 srxi_end:
322 pop zl
323 pop zh
324 pop temp
325 out sreg,temp
326 pop temp
327 reti
328
329
330 ;----------------------------------------------------------------------
331
332 .cseg
333
334 ; Timer/Counter1 Compare Match A interrupt
335
336 INTERRUPT OC1Aaddr
337
338 push temp
339 in temp,sreg
340 push temp
341 push zh
342
343 inm8 temp,OCR1AL
344 inm8 zh,OCR1AH
345 subi temp,low(-SSER_BIT_TC)
346 sbci zh,high(-SSER_BIT_TC)
347 outm8 OCR1AH,zh
348 outm8 OCR1AL,temp
349 lds temp,stx_bitcount
350 tst temp
351 breq stxi_nxtchar
352
353 dec temp
354 sts stx_bitcount,temp
355 ldi zh,9 ;Start bit?
356 cp temp,zh
357 ldi zh,(1<<COM1A1)
358 breq stxi_0
359 lds temp,stx_dr
360 sbrs temp,0
361 ldi zh,(1<<COM1A1)|(1<<COM1A0)
362 lsr temp
363 sts stx_dr,temp
364 stxi_0:
365 outm8 TCCR1A,zh
366 pop zh
367 pop temp
368 out sreg,temp
369 pop temp
370 reti
371
372 ; more characters?
373 stxi_nxtchar:
374 lds temp,txcount ;if txcount != 0
375 tst temp ;
376 breq stxi_dis
377 ; get next char
378 push zl
379 dec temp ;
380 sts txcount,temp ; --txcount
381 ldi zl,low(txfifo) ;
382 ldi zh,high(txfifo) ;
383 lds temp,txidx_r ;
384 add zl,temp ;
385 brcc PC+2 ;
386 inc zh ;
387 inc temp ;
388 andi temp,TXBUFMASK ;
389 sts txidx_r,temp ;
390 ld temp,z
391 com temp
392 sts stx_dr,temp
393 ldi temp,10
394 sts stx_bitcount,temp
395 pop zl
396 pop zh
397 pop temp
398 out sreg,temp
399 pop temp
400 reti
401
402 ; disable transmitter
403 stxi_dis:
404 ldi temp,(1<<COM1A1)|(1<<COM1A0)
405 outm8 TCCR1A,temp
406 inm8 temp,TIMSK1
407 andi temp,~(1<<OCIE1A)
408 outm8 TIMSK1,temp
409 pop zh
410 pop temp
411 out sreg,temp
412 pop temp
413 reti
414 ;------------------------------------------------------------------
415
416 srx_to:
417 #if 0
418 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
419 outm8 TCCR1B,zl
420 ldi zl,(1<<ICF1) ;clear pending int
421 out TIFR1,zl
422 #endif
423 sts srx_state,_0 ;next state
424 push temp
425
426 #if 0
427 ldi temp,'|'
428 rcall uartputc
429 #endif
430 lds temp,srx_dr ;only 0 if timeout after leading edge of start bit.
431 tst temp ; --> break
432 brne srxto_store
433 sbr intstat,(1<<i_break)
434 sts rxcount,_0 ;clear rx buffer
435 sts rxidx_w,_0
436 sts rxidx_r,_0
437 rjmp srxto_ov
438
439 srxto_store:
440 mov zl,temp
441 com zl
442 andi zl,0x80
443 srxto_l:
444 lsr temp
445 or temp,zl
446 brcc srxto_l
447
448 ; Save received character in a circular buffer. Do nothing if buffer overflows.
449
450 lds zh,rxcount ;if rxcount < RXBUFSIZE
451 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
452 brsh srxto_ov ;
453 inc zh ;
454 sts rxcount,zh ; rxcount++
455
456 ldi zl,low(rxfifo) ;
457 lds zh,rxidx_w ;
458 add zl,zh ;
459 inc zh ;
460 andi zh,RXBUFMASK ;
461 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
462 ldi zh,high(rxfifo) ;
463 brcc PC+2 ;
464 inc zh ;
465 st z,temp ; rxfifo[rxidx_w] = char
466 srxto_ov: ;endif
467
468 pop temp
469 ret
470
471
472 ;Fetches a char from the buffer to temp. If none available, waits till one is.
473
474 uartgetc:
475 push zh
476 push zl
477 push temp2
478 ugetc_w:
479 lds temp,rxcount ;Number of characters in buffer
480 tst temp
481 breq ugetc_w ;Wait for char
482
483 ldi zl,low(rxfifo)
484 ldi zh,high(rxfifo)
485 lds temp2,rxidx_r
486 add zl,temp2
487 adc zh,_0
488 inc temp2
489 andi temp2,RXBUFMASK
490 cli
491 lds temp,rxcount
492 subi temp,1
493 brcc ugetc_fin
494 sei
495 rjmp ugetc_w
496
497 ugetc_fin:
498 sts rxcount,temp
499 sts rxidx_r,temp2
500 sei
501 ld temp,z ;don't forget to get the char
502 pop temp2
503 pop zl
504 pop zh
505 ret
506
507 ;Sends a char from temp to the soft uart.
508
509 uartputc:
510 push zh
511 push zl
512 in zl,sreg
513 push zl
514 push temp
515 sputc_l:
516 lds temp,txcount ;do {
517 cpi temp,TXBUFSIZE ;
518 brsh sputc_l ;} while (txcount >= TXBUFSIZE)
519
520 ldi zl,low(txfifo) ;
521 ldi zh,high(txfifo) ;
522 lds temp,txidx_w ;
523 add zl,temp ;
524 adc zh,_0 ;
525 inc temp ;
526 andi temp,TXBUFMASK ;
527 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
528 pop temp ;
529 st z,temp ; txfifo[txidx_w] = char
530 cli
531 lds zh,txcount
532 inc zh
533 sts txcount,zh
534 dec zh
535 brne sputc_e
536 ; Enable transmitter
537 inm8 zh,TIMSK1
538 ori zh,(1<<OCIE1A)
539 outm8 TIMSK1,zh
540 sputc_e:
541 pop zl
542 out sreg,zl
543 pop zl
544 pop zh
545 ret
546
547
548 ; Wait, till tx buffer is empty.
549
550 uart_wait_empty:
551 push temp
552 uwe_loop:
553 lds temp,txcount
554 tst temp
555 brne uwe_loop
556 pop temp
557 ret
558
559
560 ; vim:set ts=8 noet nowrap
561