]> cloudbase.mooo.com Git - avrcpm.git/blame - avr/sw-uart.asm
SVN --> GIT
[avrcpm.git] / avr / sw-uart.asm
CommitLineData
4bd49b80 1; Serial interface using the ATmega8/88 USART.
9c15f366
L
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
4bd49b80 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
4bd49b80 35
9c15f366
L
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
4bd49b80 70; Init
9c15f366
L
71uart_init:
72
73; - Init clock/timer system and serial port
74
4bd49b80 75; Init timer 1 as
9c15f366
L
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 97 ret
4bd49b80 98
9c15f366
L
99;------------------------------------------------------------------
100
101 .cseg
9c15f366 102
4675c141 103; Timer/Counter1 Input Capture interrupt
4bd49b80 104
4675c141 105 INTERRUPT ICP1addr
4bd49b80 106
9c15f366
L
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
4bd49b80 121
9c15f366
L
122#if 0
123 lds temp,srx_state
124 subi temp,-'0'
125 rcall uartputc
126 lds temp,srx_dr
127 rcall printhex
4bd49b80 128#endif
9c15f366
L
129 lds temp,srx_state
130 cpi temp,0
4bd49b80 131 brne srxi_S1
9c15f366
L
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
4bd49b80 173; mov temp,zh
9c15f366
L
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
4bd49b80 251
9c15f366
L
252 sts srx_dr,temp
253 ldi temp,3
254 sts srx_state,temp
623dd899 255 rjmp srxi_end
4bd49b80 256
9c15f366
L
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
4bd49b80 263
9c15f366
L
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
4bd49b80 291
9c15f366
L
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 303
4bd49b80 304srxi_complete0:
9c15f366
L
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?)
4bd49b80 319 brsh srxi_ov ;1
623dd899
L
320 inc zh ;1
321 sts rxcount,zh ;2 rxcount++
322
4bd49b80 323 ldi zl,low(rxfifo) ;1
623dd899
L
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 348; Timer/Counter1 Compare Match A interrupt
4bd49b80 349
4675c141 350 INTERRUPT OC1Aaddr
4bd49b80 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
4bd49b80 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 ;
4bd49b80 378 ldi zl,low(txfifo) ;
9c15f366
L
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
4bd49b80 455
9c15f366
L
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?)
4bd49b80 460 brsh srxto_ov ;
9c15f366
L
461 inc zh ;
462 sts rxcount,zh ; rxcount++
463
4bd49b80 464 ldi zl,low(rxfifo) ;
9c15f366
L
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
4bd49b80 475
9c15f366
L
476 pop temp
477 ret
4bd49b80
L
478
479
9c15f366
L
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
4bd49b80 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
4bd49b80 515;Sends a char from temp to the soft uart.
9c15f366
L
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
12a27f27 528 cli
4bd49b80 529 ldi zl,low(txfifo) ;
9c15f366
L
530 ldi zh,high(txfifo) ;
531 lds temp,txidx_w ;
532 add zl,temp ;
6efd6291 533 adc zh,_0 ;
9c15f366
L
534 inc temp ;
535 andi temp,TXBUFMASK ;
536 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
537 pop temp ;
538 st z,temp ; txfifo[txidx_w] = char
12a27f27 539; cli
9c15f366
L
540 lds zh,txcount
541 inc zh
542 sts txcount,zh
623dd899 543 cpi zh,1
9c15f366
L
544 brne sputc_e
545; Enable transmitter
546 inm8 zh,TIMSK1
623dd899
L
547 sbrc zh,OCIE1A
548 rjmp sputc_e
9c15f366
L
549 ori zh,(1<<OCIE1A)
550 outm8 TIMSK1,zh
623dd899
L
551
552 inm8 zl,TCNT1L ;
553 inm8 zh,TCNT1H ;
554 adiw zl,30 ;
555 outm8 OCR1AH,zh ;
556 outm8 OCR1AL,zl ;
557 ldi zl,(1<<OCF1A)
558 outm8 TIFR1,zl
559
9c15f366
L
560sputc_e:
561 pop zl
562 out sreg,zl
563 pop zl
564 pop zh
565 ret
566
567
568; Wait, till tx buffer is empty.
569
570uart_wait_empty:
571 push temp
572uwe_loop:
573 lds temp,txcount
574 tst temp
575 brne uwe_loop
576 pop temp
577 ret
578
579
580; vim:set ts=8 noet nowrap