1 ; Serial interface using the ATmega8/88 USART.
2 ; This is part of the Z80-CP/M emulator written by Sprite_tm.
4 ; Copyright (C) 2010 Leo C.
6 ; This file is part of avrcpm.
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.
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.
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/>.
24 #define SSER_BIT_TC (F_CPU+BAUD/2) / BAUD
26 #define RXBUFMASK RXBUFSIZE-1
27 #define TXBUFMASK TXBUFSIZE-1
66 ; - Init clock/timer system and serial port
69 ; - Soft UART TX (OC1A/OCR1A).
70 ; - Soft UART RX (ICP1/ICR1).
71 ; - 1ms System timer is already configured at this point.
73 ldi temp,(1<<COM1A1)|(1<<COM1A0) ;OC1A high on compare match (UART TX)
76 ldi temp,(1<<ICF1) ;clear pending int
79 ori temp,(1<<ICIE1) ;Enable input capture int. (UART RX)
83 ;------------------------------------------------------------------
87 ; Timer/Counter1 Input Capture interrupt
101 eor temp,temp2 ;toggle edge
103 ldi temp,(1<<ICF1) ;clear pending int
117 ; State 0: Wait for start bit
119 ; sts srx_lastedge,zl ;save beginning of start bit
120 ; sts srx_lastedge+1,zh
121 movw srx_lastedgel,zl
126 sbis P_RXD-2,RXD ;RXD still low?
128 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
130 ldi zh,(1<<ICF1) ;clear pending int
140 ; State 1: Check start bit (and collect 0-bits)
142 ; lds temp,srx_lastedge
143 ; lds temp2,srx_lastedge+1
144 ; sts srx_lastedge,zl
145 ; sts srx_lastedge+1,zh
147 movw temp,srx_lastedgel
148 movw srx_lastedgel,zl
152 subi zl,low ((SSER_BIT_TC+1)/2)
153 sbci zh,high((SSER_BIT_TC+1)/2)
163 subi zl,low(SSER_BIT_TC)
164 sbci zh,high(SSER_BIT_TC)
176 ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
178 ldi temp,(1<<ICF1) ;clear pending int
180 sts srx_state,_0 ;next state
184 subi zl,low (-(SSER_BIT_TC+1)/2)
185 sbci zh,high(-(SSER_BIT_TC+1)/2)
197 ; State 2: collect 1-bits
199 ; lds temp,srx_lastedge
200 ; lds temp2,srx_lastedge+1
201 ; sts srx_lastedge,zl
202 ; sts srx_lastedge+1,zh
204 movw temp,srx_lastedgel
205 movw srx_lastedgel,zl
209 subi zl,low ((SSER_BIT_TC+1)/2)
210 sbci zh,high((SSER_BIT_TC+1)/2)
216 brcs srxi_complete1 ;8 bits recieved
217 subi zl,low(SSER_BIT_TC)
218 sbci zh,high(SSER_BIT_TC)
227 ldi temp2,1 ;We are in start bit now.
230 sts srx_char_to,temp2
237 ; State 3: collect 0-bits
239 ; lds temp,srx_lastedge
240 ; lds temp2,srx_lastedge+1
241 ; sts srx_lastedge,zl
242 ; sts srx_lastedge+1,zh
244 movw temp,srx_lastedgel
245 movw srx_lastedgel,zl
249 subi zl,low ((SSER_BIT_TC+1)/2)
250 sbci zh,high((SSER_BIT_TC+1)/2)
256 brcs srxi_complete0 ;8 bits recieved
257 subi zl,low(SSER_BIT_TC)
258 sbci zh,high(SSER_BIT_TC)
267 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
269 ldi zl,(1<<ICF1) ;clear pending int
270 sts srx_state,_0 ;next state
274 sts srx_char_to,_0 ;clear timeout
275 sts srx_state,_0 ;next state
278 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
280 ldi zl,(1<<ICF1) ;clear pending int
284 ; Save received character in a circular buffer. Do nothing if buffer overflows.
286 lds zh,rxcount ;if rxcount < RXBUFSIZE
287 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
290 sts rxcount,zh ; rxcount++
297 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
298 ldi zh,high(rxfifo) ;
301 st z,temp ; rxfifo[rxidx_w] = char
315 ;----------------------------------------------------------------------
319 ; Timer/Counter1 Compare Match A interrupt
330 subi temp,low(-SSER_BIT_TC)
331 sbci zh,high(-SSER_BIT_TC)
334 lds temp,stx_bitcount
339 sts stx_bitcount,temp
346 ldi zh,(1<<COM1A1)|(1<<COM1A0)
359 lds temp,txcount ;if txcount != 0
365 sts txcount,temp ; --txcount
367 ldi zh,high(txfifo) ;
373 andi temp,TXBUFMASK ;
379 sts stx_bitcount,temp
387 ; disable transmitter
389 ldi temp,(1<<COM1A1)|(1<<COM1A0)
392 andi temp,~(1<<OCIE1A)
399 ;------------------------------------------------------------------
403 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
405 ldi zl,(1<<ICF1) ;clear pending int
423 ; Save received character in a circular buffer. Do nothing if buffer overflows.
425 lds zh,rxcount ;if rxcount < RXBUFSIZE
426 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
429 sts rxcount,zh ; rxcount++
436 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
437 ldi zh,high(rxfifo) ;
440 st z,temp ; rxfifo[rxidx_w] = char
442 sts srx_state,_0 ;next state
448 ;Fetches a char from the buffer to temp. If none available, waits till one is.
451 lds temp,rxcount ;Number of characters in buffer
453 breq uartgetc ;Wait for char
471 ld temp,z ;don't forget to get the char
476 ;Sends a char from temp to the soft uart.
485 lds temp,txcount ;do {
487 brsh sputc_l ;} while (txcount >= TXBUFSIZE)
490 ldi zh,high(txfifo) ;
496 andi temp,TXBUFMASK ;
497 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
499 st z,temp ; txfifo[txidx_w] = char
518 ; Wait, till tx buffer is empty.
530 ; vim:set ts=8 noet nowrap