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)
187 ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
189 ldi temp,(1<<ICF1) ;clear pending int
191 sts srx_state,_0 ;next state
195 subi zl,low (-(SSER_BIT_TC+1)/2)
196 sbci zh,high(-(SSER_BIT_TC+1)/2)
208 ; State 2: collect 1-bits
210 ; lds temp,srx_lastedge
211 ; lds temp2,srx_lastedge+1
212 ; sts srx_lastedge,zl
213 ; sts srx_lastedge+1,zh
215 movw temp,srx_lastedgel
216 movw srx_lastedgel,zl
220 subi zl,low ((SSER_BIT_TC+1)/2)
221 sbci zh,high((SSER_BIT_TC+1)/2)
227 brcs srxi_complete1 ;8 bits recieved
228 subi zl,low(SSER_BIT_TC)
229 sbci zh,high(SSER_BIT_TC)
238 ldi temp2,1 ;We are in start bit now.
241 sts srx_char_to,temp2
248 ; State 3: collect 0-bits
250 ; lds temp,srx_lastedge
251 ; lds temp2,srx_lastedge+1
252 ; sts srx_lastedge,zl
253 ; sts srx_lastedge+1,zh
255 movw temp,srx_lastedgel
256 movw srx_lastedgel,zl
260 subi zl,low ((SSER_BIT_TC+1)/2)
261 sbci zh,high((SSER_BIT_TC+1)/2)
267 brcs srxi_complete0 ;8 bits recieved
268 subi zl,low(SSER_BIT_TC)
269 sbci zh,high(SSER_BIT_TC)
278 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
280 ldi zl,(1<<ICF1) ;clear pending int
281 sts srx_state,_0 ;next state
285 sts srx_char_to,_0 ;clear timeout
286 sts srx_state,_0 ;next state
289 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
291 ldi zl,(1<<ICF1) ;clear pending int
295 ; Save received character in a circular buffer. Do nothing if buffer overflows.
297 lds zh,rxcount ;if rxcount < RXBUFSIZE
298 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
301 sts rxcount,zh ; rxcount++
308 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
309 ldi zh,high(rxfifo) ;
312 st z,temp ; rxfifo[rxidx_w] = char
326 ;----------------------------------------------------------------------
330 ; Timer/Counter1 Compare Match A interrupt
341 subi temp,low(-SSER_BIT_TC)
342 sbci zh,high(-SSER_BIT_TC)
345 lds temp,stx_bitcount
350 sts stx_bitcount,temp
357 ldi zh,(1<<COM1A1)|(1<<COM1A0)
370 lds temp,txcount ;if txcount != 0
376 sts txcount,temp ; --txcount
378 ldi zh,high(txfifo) ;
384 andi temp,TXBUFMASK ;
390 sts stx_bitcount,temp
398 ; disable transmitter
400 ldi temp,(1<<COM1A1)|(1<<COM1A0)
403 andi temp,~(1<<OCIE1A)
410 ;------------------------------------------------------------------
414 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
416 ldi zl,(1<<ICF1) ;clear pending int
419 sts srx_state,_0 ;next state
426 lds temp,srx_dr ;only 0 if timeout after leading edge of start bit.
429 sbr intstat,(1<<i_break)
441 ; Save received character in a circular buffer. Do nothing if buffer overflows.
443 lds zh,rxcount ;if rxcount < RXBUFSIZE
444 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
447 sts rxcount,zh ; rxcount++
454 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
455 ldi zh,high(rxfifo) ;
458 st z,temp ; rxfifo[rxidx_w] = char
465 ;Fetches a char from the buffer to temp. If none available, waits till one is.
468 lds temp,rxcount ;Number of characters in buffer
470 breq uartgetc ;Wait for char
488 ld temp,z ;don't forget to get the char
493 ;Sends a char from temp to the soft uart.
502 lds temp,txcount ;do {
504 brsh sputc_l ;} while (txcount >= TXBUFSIZE)
507 ldi zh,high(txfifo) ;
513 andi temp,TXBUFMASK ;
514 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
516 st z,temp ; txfifo[txidx_w] = char
535 ; Wait, till tx buffer is empty.
547 ; vim:set ts=8 noet nowrap