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/>.
25 #error "ATmega8 is not supported (yet)! Please update this driver, or buy an ATmega88."
28 #define SSER_BIT_TC (F_CPU+BAUD/2) / BAUD
29 #define SSER_CHAR_TC (10 * 1000 / BAUD) + 2
31 #define RXBUFMASK RXBUFSIZE-1
32 #define TXBUFMASK TXBUFSIZE-1
73 ; - Init clock/timer system and serial port
76 ; - Soft UART TX (OC1A/OCR1A).
77 ; - Soft UART RX (ICP1/ICR1).
78 ; - 1ms System timer is already configured at this point.
81 cbi P_TXD-1,TXD ;TXD pin as input
82 ldi temp,(1<<COM1A1)|(1<<COM1A0) ;OC1A high on compare match (UART TX)
83 ldi temp2,(1<<FOC1A) ;force compare match
86 sbi P_TXD-1,TXD ;TXD pin now output (OC1A)
88 ldi temp,(1<<ICF1) ;clear pending input capture int
91 ori temp,(1<<ICIE1) ;Enable input capture int. (UART RX)
94 ldi temp,SSER_CHAR_TC ;Character TO
95 sts srx_char_time,temp
99 ;------------------------------------------------------------------
103 ; Timer/Counter1 Input Capture interrupt
117 eor temp,temp2 ;toggle edge
119 ldi temp,(1<<ICF1) ;clear pending int
133 ; State 0: Wait for start bit
135 sts srx_lastedge,zl ;save beginning of start bit
136 sts srx_lastedge+1,zh
137 ; movw srx_lastedgel,zl
141 lds temp,srx_char_time
143 sbis P_RXD-2,RXD ;RXD still low?
145 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
147 ldi zh,(1<<ICF1) ;clear pending int
157 ; State 1: Check start bit (and collect 0-bits)
159 lds temp,srx_lastedge
160 lds temp2,srx_lastedge+1
162 sts srx_lastedge+1,zh
164 ; movw temp,srx_lastedgel
165 ; movw srx_lastedgel,zl
169 subi zl,low ((SSER_BIT_TC+1)/2)
170 sbci zh,high((SSER_BIT_TC+1)/2)
180 subi zl,low(SSER_BIT_TC)
181 sbci zh,high(SSER_BIT_TC)
186 subi zl,low(SSER_BIT_TC) ; stop bit?
187 sbci zh,high(SSER_BIT_TC)
189 rjmp srxi_complete0 ; ok, x00 (^@) received
191 sts srx_char_to,_0 ; no stop bit --> framing error --> break
193 sbr intstat,(1<<i_break) ;
194 sts rxcount,_0 ;clear rx buffer
207 ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
209 ldi temp,(1<<ICF1) ;clear pending int
211 sts srx_state,_0 ;next state
215 subi zl,low (-(SSER_BIT_TC+1)/2)
216 sbci zh,high(-(SSER_BIT_TC+1)/2)
228 ; State 2: collect 1-bits
230 lds temp,srx_lastedge
231 lds temp2,srx_lastedge+1
233 sts srx_lastedge+1,zh
235 ; movw temp,srx_lastedgel
236 ; movw srx_lastedgel,zl
240 subi zl,low ((SSER_BIT_TC+1)/2)
241 sbci zh,high((SSER_BIT_TC+1)/2)
247 brcs srxi_complete1 ;8 bits recieved
248 subi zl,low(SSER_BIT_TC)
249 sbci zh,high(SSER_BIT_TC)
258 ldi temp2,1 ;We are in start bit now.
260 lds temp2,srx_char_time
261 sts srx_char_to,temp2
268 ; State 3: collect 0-bits
270 lds temp,srx_lastedge
271 lds temp2,srx_lastedge+1
273 sts srx_lastedge+1,zh
275 ; movw temp,srx_lastedgel
276 ; movw srx_lastedgel,zl
280 subi zl,low ((SSER_BIT_TC+1)/2)
281 sbci zh,high((SSER_BIT_TC+1)/2)
287 brcs srxi_complete0 ;8 bits recieved
288 subi zl,low(SSER_BIT_TC)
289 sbci zh,high(SSER_BIT_TC)
298 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
300 ldi zl,(1<<ICF1) ;clear pending int
301 sts srx_state,_0 ;next state
305 sts srx_char_to,_0 ;clear timeout
306 sts srx_state,_0 ;next state
309 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
311 ldi zl,(1<<ICF1) ;clear pending int
315 ; Save received character in a circular buffer. Do nothing if buffer overflows.
317 lds zh,rxcount ;2 if rxcount < RXBUFSIZE
318 cpi zh,RXBUFSIZE ;1 (room for at least 1 char?)
321 sts rxcount,zh ;2 rxcount++
323 ldi zl,low(rxfifo) ;1
328 sts rxidx_w,zh ;2 rxidx_w = ++rxidx_w % RXBUFSIZE
329 ldi zh,high(rxfifo) ;1
331 st z,temp ;2 rxfifo[rxidx_w] = char
344 ;----------------------------------------------------------------------
348 ; Timer/Counter1 Compare Match A interrupt
359 subi zl,low(-SSER_BIT_TC)
360 sbci zh,high(-SSER_BIT_TC)
368 ; bit counter was 0, more characters?
371 lds zl,txcount ;if txcount != 0
376 sts txcount,zl ; --txcount
379 ldi zh,high(txfifo) ;
384 andi temp,TXBUFMASK ;
390 sts stx_bitcount,temp
396 ; disable transmitter
402 ldi zh,(1<<COM1A1)|(1<<COM1A0)
411 ldi zh,(1<<COM1A1)|(1<<COM1A0)
422 ;------------------------------------------------------------------
426 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
428 ldi zl,(1<<ICF1) ;clear pending int
431 sts srx_state,_0 ;next state
438 lds temp,srx_dr ;only 0 if timeout after leading edge of start bit.
441 sbr intstat,(1<<i_break)
442 sts rxcount,_0 ;clear rx buffer
456 ; Save received character in a circular buffer. Do nothing if buffer overflows.
458 lds zh,rxcount ;if rxcount < RXBUFSIZE
459 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
462 sts rxcount,zh ; rxcount++
469 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
470 ldi zh,high(rxfifo) ;
473 st z,temp ; rxfifo[rxidx_w] = char
480 ;Fetches a char from the buffer to temp. If none available, waits till one is.
487 lds temp,rxcount ;Number of characters in buffer
489 breq ugetc_w ;Wait for char
509 ld temp,z ;don't forget to get the char
515 ;Sends a char from temp to the soft uart.
524 lds temp,txcount ;do {
526 brsh sputc_l ;} while (txcount >= TXBUFSIZE)
529 ldi zh,high(txfifo) ;
534 andi temp,TXBUFMASK ;
535 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
537 st z,temp ; txfifo[txidx_w] = char
567 ; Wait, till tx buffer is empty.
579 ; vim:set ts=8 noet nowrap