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
127 sbis P_RXD-2,RXD ;RXD still low?
129 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
131 ldi zh,(1<<ICF1) ;clear pending int
141 ; State 1: Check start bit (and collect 0-bits)
143 ; lds temp,srx_lastedge
144 ; lds temp2,srx_lastedge+1
145 ; sts srx_lastedge,zl
146 ; sts srx_lastedge+1,zh
148 movw temp,srx_lastedgel
149 movw srx_lastedgel,zl
153 subi zl,low ((SSER_BIT_TC+1)/2)
154 sbci zh,high((SSER_BIT_TC+1)/2)
164 subi zl,low(SSER_BIT_TC)
165 sbci zh,high(SSER_BIT_TC)
170 subi zl,low(SSER_BIT_TC) ; stop bit?
171 sbci zh,high(SSER_BIT_TC)
173 rjmp srxi_complete0 ; ok, x00 (^@) received
175 sts srx_char_to,_0 ; no stop bit --> framing error --> break
177 sbr intstat,(1<<i_break) ;
178 sts rxcount,_0 ;clear rx buffer
191 ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
193 ldi temp,(1<<ICF1) ;clear pending int
195 sts srx_state,_0 ;next state
199 subi zl,low (-(SSER_BIT_TC+1)/2)
200 sbci zh,high(-(SSER_BIT_TC+1)/2)
212 ; State 2: collect 1-bits
214 ; lds temp,srx_lastedge
215 ; lds temp2,srx_lastedge+1
216 ; sts srx_lastedge,zl
217 ; sts srx_lastedge+1,zh
219 movw temp,srx_lastedgel
220 movw srx_lastedgel,zl
224 subi zl,low ((SSER_BIT_TC+1)/2)
225 sbci zh,high((SSER_BIT_TC+1)/2)
231 brcs srxi_complete1 ;8 bits recieved
232 subi zl,low(SSER_BIT_TC)
233 sbci zh,high(SSER_BIT_TC)
242 ldi temp2,1 ;We are in start bit now.
245 sts srx_char_to,temp2
252 ; State 3: collect 0-bits
254 ; lds temp,srx_lastedge
255 ; lds temp2,srx_lastedge+1
256 ; sts srx_lastedge,zl
257 ; sts srx_lastedge+1,zh
259 movw temp,srx_lastedgel
260 movw srx_lastedgel,zl
264 subi zl,low ((SSER_BIT_TC+1)/2)
265 sbci zh,high((SSER_BIT_TC+1)/2)
271 brcs srxi_complete0 ;8 bits recieved
272 subi zl,low(SSER_BIT_TC)
273 sbci zh,high(SSER_BIT_TC)
282 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
284 ldi zl,(1<<ICF1) ;clear pending int
285 sts srx_state,_0 ;next state
289 sts srx_char_to,_0 ;clear timeout
290 sts srx_state,_0 ;next state
293 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
295 ldi zl,(1<<ICF1) ;clear pending int
299 ; Save received character in a circular buffer. Do nothing if buffer overflows.
301 lds zh,rxcount ;if rxcount < RXBUFSIZE
302 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
305 sts rxcount,zh ; rxcount++
312 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
313 ldi zh,high(rxfifo) ;
316 st z,temp ; rxfifo[rxidx_w] = char
330 ;----------------------------------------------------------------------
334 ; Timer/Counter1 Compare Match A interrupt
345 subi temp,low(-SSER_BIT_TC)
346 sbci zh,high(-SSER_BIT_TC)
349 lds temp,stx_bitcount
354 sts stx_bitcount,temp
361 ldi zh,(1<<COM1A1)|(1<<COM1A0)
374 lds temp,txcount ;if txcount != 0
380 sts txcount,temp ; --txcount
382 ldi zh,high(txfifo) ;
388 andi temp,TXBUFMASK ;
394 sts stx_bitcount,temp
402 ; disable transmitter
404 ldi temp,(1<<COM1A1)|(1<<COM1A0)
407 andi temp,~(1<<OCIE1A)
414 ;------------------------------------------------------------------
418 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
420 ldi zl,(1<<ICF1) ;clear pending int
423 sts srx_state,_0 ;next state
430 lds temp,srx_dr ;only 0 if timeout after leading edge of start bit.
433 sbr intstat,(1<<i_break)
434 sts rxcount,_0 ;clear rx buffer
448 ; Save received character in a circular buffer. Do nothing if buffer overflows.
450 lds zh,rxcount ;if rxcount < RXBUFSIZE
451 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
454 sts rxcount,zh ; rxcount++
461 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
462 ldi zh,high(rxfifo) ;
465 st z,temp ; rxfifo[rxidx_w] = char
472 ;Fetches a char from the buffer to temp. If none available, waits till one is.
479 lds temp,rxcount ;Number of characters in buffer
481 breq ugetc_w ;Wait for char
501 ld temp,z ;don't forget to get the char
507 ;Sends a char from temp to the soft uart.
516 lds temp,txcount ;do {
518 brsh sputc_l ;} while (txcount >= TXBUFSIZE)
521 ldi zh,high(txfifo) ;
526 andi temp,TXBUFMASK ;
527 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
529 st z,temp ; txfifo[txidx_w] = char
548 ; Wait, till tx buffer is empty.
560 ; vim:set ts=8 noet nowrap