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