]> cloudbase.mooo.com Git - avrcpm.git/blob - avrcpm/avr/sw-uart.asm
36d814cf57ea62b0c303079527dd4a4325255c62
[avrcpm.git] / avrcpm / 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 srxint:
87 .org ICP1addr ; Timer/Counter1 Input Capture
88 rjmp srxint ; Soft UART: RX
89
90 .org srxint
91
92 push temp
93 in temp,sreg
94 push temp
95 push zh
96 push zl
97 inm8 zl,ICR1L
98 inm8 zh,ICR1H
99 push temp2
100 ldi temp2,(1<<ICES1)
101 inm8 temp,TCCR1B
102 eor temp,temp2 ;toggle edge
103 outm8 TCCR1B,temp
104 ldi temp,(1<<ICF1) ;clear pending int
105 out TIFR1,temp
106
107 #if 0
108 lds temp,srx_state
109 subi temp,-'0'
110 rcall uartputc
111 lds temp,srx_dr
112 rcall printhex
113 #endif
114 lds temp,srx_state
115 cpi temp,0
116 brne srxi_S1
117
118 ; State 0: Wait for start bit
119
120 ; sts srx_lastedge,zl ;save beginning of start bit
121 ; sts srx_lastedge+1,zh
122 movw srx_lastedgel,zl
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 rjmp srxi_complete
170 srxi_1be:
171 sts srx_dr,temp
172 ldi temp,2
173 sts srx_state,temp
174 rjmp srxi_end2
175
176 srxi_sberr:
177 ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
178 outm8 TCCR1B,temp
179 ldi temp,(1<<ICF1) ;clear pending int
180 out TIFR1,temp
181 sts srx_state,_0 ;next state
182 #if 1
183 ldi temp,'?'
184 rcall uartputc
185 subi zl,low (-(SSER_BIT_TC+1)/2)
186 sbci zh,high(-(SSER_BIT_TC+1)/2)
187 mov temp,zh
188 rcall printhex
189 mov temp,zl
190 rcall printhex
191 #endif
192 rjmp srxi_end2
193
194 srxi_S2:
195 cpi temp,2
196 brne srxi_S3
197
198 ; State 2: collect 1-bits
199
200 ; lds temp,srx_lastedge
201 ; lds temp2,srx_lastedge+1
202 ; sts srx_lastedge,zl
203 ; sts srx_lastedge+1,zh
204
205 movw temp,srx_lastedgel
206 movw srx_lastedgel,zl
207
208 sub zl,temp
209 sbc zh,temp2
210 subi zl,low ((SSER_BIT_TC+1)/2)
211 sbci zh,high((SSER_BIT_TC+1)/2)
212
213 lds temp,srx_dr
214 srxi_2l:
215 sec ;one more 1 bit
216 ror temp
217 brcs srxi_complete1 ;8 bits recieved
218 subi zl,low(SSER_BIT_TC)
219 sbci zh,high(SSER_BIT_TC)
220 brcc srxi_2l
221
222 sts srx_dr,temp
223 ldi temp,3
224 sts srx_state,temp
225 rjmp srxi_end2
226
227 srxi_complete1:
228 ldi temp2,1 ;We are in start bit now.
229 sts srx_state,temp2
230 ldi temp2,2
231 sts srx_char_to,temp2
232 rjmp srxi_complete
233
234 srxi_S3:
235 cpi temp,3
236 brne srxi_S4
237
238 ; State 3: collect 0-bits
239
240 ; lds temp,srx_lastedge
241 ; lds temp2,srx_lastedge+1
242 ; sts srx_lastedge,zl
243 ; sts srx_lastedge+1,zh
244
245 movw temp,srx_lastedgel
246 movw srx_lastedgel,zl
247
248 sub zl,temp
249 sbc zh,temp2
250 subi zl,low ((SSER_BIT_TC+1)/2)
251 sbci zh,high((SSER_BIT_TC+1)/2)
252
253 lds temp,srx_dr
254 srxi_3l:
255 ;one more 0 bit
256 lsr temp
257 brcs srxi_complete0 ;8 bits recieved
258 subi zl,low(SSER_BIT_TC)
259 sbci zh,high(SSER_BIT_TC)
260 brcc srxi_3l
261
262 sts srx_dr,temp
263 ldi temp,2
264 sts srx_state,temp
265 rjmp srxi_end2
266
267 srxi_S4:
268 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
269 outm8 TCCR1B,zl
270 ldi zl,(1<<ICF1) ;clear pending int
271 sts srx_state,_0 ;next state
272 rjmp srxi_end2
273
274 srxi_complete0:
275 sts srx_char_to,_0 ;clear timeout
276 sts srx_state,_0 ;next state
277 srxi_complete:
278 #if 0
279 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
280 outm8 TCCR1B,zl
281 ldi zl,(1<<ICF1) ;clear pending int
282 out TIFR1,zl
283 #endif
284
285 ; Save received character in a circular buffer. Do nothing if buffer overflows.
286
287 lds zh,rxcount ;if rxcount < RXBUFSIZE
288 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
289 brsh srxi_ov ;
290 inc zh ;
291 sts rxcount,zh ; rxcount++
292
293 ldi zl,low(rxfifo) ;
294 lds zh,rxidx_w ;
295 add zl,zh ;
296 inc zh ;
297 andi zh,RXBUFMASK ;
298 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
299 ldi zh,high(rxfifo) ;
300 brcc PC+2 ;
301 inc zh ;
302 st z,temp ; rxfifo[rxidx_w] = char
303 srxi_ov: ;endif
304
305 srxi_end2:
306 pop temp2
307 srxi_end:
308 pop zl
309 pop zh
310 pop temp
311 out sreg,temp
312 pop temp
313 reti
314
315
316 ;----------------------------------------------------------------------
317
318 .cseg
319 stxint:
320 .org OC1Aaddr ; Timer/Counter1 Compare Match A
321 rjmp stxint ; Soft UART: TX
322
323 .org stxint
324
325 push temp
326 in temp,sreg
327 push temp
328 push zh
329
330 inm8 temp,OCR1AL
331 inm8 zh,OCR1AH
332 subi temp,low(-SSER_BIT_TC)
333 sbci zh,high(-SSER_BIT_TC)
334 outm8 OCR1AH,zh
335 outm8 OCR1AL,temp
336 lds temp,stx_bitcount
337 tst temp
338 breq stxi_nxtchar
339
340 dec temp
341 sts stx_bitcount,temp
342 ldi zh,9 ;Start bit?
343 cp temp,zh
344 ldi zh,(1<<COM1A1)
345 breq stxi_0
346 lds temp,stx_dr
347 sbrs temp,0
348 ldi zh,(1<<COM1A1)|(1<<COM1A0)
349 lsr temp
350 sts stx_dr,temp
351 stxi_0:
352 outm8 TCCR1A,zh
353 pop zh
354 pop temp
355 out sreg,temp
356 pop temp
357 reti
358
359 ; more characters?
360 stxi_nxtchar:
361 lds temp,txcount ;if txcount != 0
362 tst temp ;
363 breq stxi_dis
364 ; get next char
365 push zl
366 dec temp ;
367 sts txcount,temp ; --txcount
368 ldi zl,low(txfifo) ;
369 ldi zh,high(txfifo) ;
370 lds temp,txidx_r ;
371 add zl,temp ;
372 brcc PC+2 ;
373 inc zh ;
374 inc temp ;
375 andi temp,TXBUFMASK ;
376 sts txidx_r,temp ;
377 ld temp,z
378 com temp
379 sts stx_dr,temp
380 ldi temp,10
381 sts stx_bitcount,temp
382 pop zl
383 pop zh
384 pop temp
385 out sreg,temp
386 pop temp
387 reti
388
389 ; disable transmitter
390 stxi_dis:
391 ldi temp,(1<<COM1A1)|(1<<COM1A0)
392 outm8 TCCR1A,temp
393 inm8 temp,TIMSK1
394 andi temp,~(1<<OCIE1A)
395 outm8 TIMSK1,temp
396 pop zh
397 pop temp
398 out sreg,temp
399 pop temp
400 reti
401 ;------------------------------------------------------------------
402
403 srx_to:
404 #if 0
405 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
406 outm8 TCCR1B,zl
407 ldi zl,(1<<ICF1) ;clear pending int
408 out TIFR1,zl
409 #endif
410 push temp
411
412 #if 0
413 ldi temp,'|'
414 rcall uartputc
415 #endif
416 lds temp,srx_dr
417 mov zl,temp
418 com zl
419 andi zl,0x80
420 srxto_l:
421 lsr temp
422 or temp,zl
423 brcc srxto_l
424
425 ; Save received character in a circular buffer. Do nothing if buffer overflows.
426
427 lds zh,rxcount ;if rxcount < RXBUFSIZE
428 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
429 brsh srxto_ov ;
430 inc zh ;
431 sts rxcount,zh ; rxcount++
432
433 ldi zl,low(rxfifo) ;
434 lds zh,rxidx_w ;
435 add zl,zh ;
436 inc zh ;
437 andi zh,RXBUFMASK ;
438 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
439 ldi zh,high(rxfifo) ;
440 brcc PC+2 ;
441 inc zh ;
442 st z,temp ; rxfifo[rxidx_w] = char
443 srxto_ov: ;endif
444 sts srx_state,_0 ;next state
445
446 pop temp
447 ret
448
449
450 ;Fetches a char from the buffer to temp. If none available, waits till one is.
451
452 uartgetc:
453 lds temp,rxcount ;Number of characters in buffer
454 tst temp
455 breq uartgetc ;Wait for char
456
457 push zh
458 push zl
459 ldi zl,low(rxfifo)
460 ldi zh,high(rxfifo)
461 lds temp,rxidx_r
462 add zl,temp
463 brcc PC+2
464 inc zh
465 inc temp
466 andi temp,RXBUFMASK
467 sts rxidx_r,temp
468 cli
469 lds temp,rxcount
470 dec temp
471 sts rxcount,temp
472 sei
473 ld temp,z ;don't forget to get the char
474 pop zl
475 pop zh
476 ret
477
478 ;Sends a char from temp to the soft uart.
479
480 uartputc:
481 push zh
482 push zl
483 in zl,sreg
484 push zl
485 push temp
486 sputc_l:
487 lds temp,txcount ;do {
488 cpi temp,TXBUFSIZE ;
489 brsh sputc_l ;} while (txcount >= TXBUFSIZE)
490
491 ldi zl,low(txfifo) ;
492 ldi zh,high(txfifo) ;
493 lds temp,txidx_w ;
494 add zl,temp ;
495 brcc PC+2 ;
496 inc zh ;
497 inc temp ;
498 andi temp,TXBUFMASK ;
499 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
500 pop temp ;
501 st z,temp ; txfifo[txidx_w] = char
502 cli
503 lds zh,txcount
504 inc zh
505 sts txcount,zh
506 dec zh
507 brne sputc_e
508 ; Enable transmitter
509 inm8 zh,TIMSK1
510 ori zh,(1<<OCIE1A)
511 outm8 TIMSK1,zh
512 sputc_e:
513 pop zl
514 out sreg,zl
515 pop zl
516 pop zh
517 ret
518
519
520 ; Wait, till tx buffer is empty.
521
522 uart_wait_empty:
523 push temp
524 uwe_loop:
525 lds temp,txcount
526 tst temp
527 brne uwe_loop
528 pop temp
529 ret
530
531
532 ; vim:set ts=8 noet nowrap
533