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 .org ICP1addr ; Timer/Counter1 Input Capture
88 rjmp srxint ; Soft UART: RX
102 eor temp,temp2 ;toggle edge
104 ldi temp,(1<<ICF1) ;clear pending int
118 ; State 0: Wait for start bit
120 ; sts srx_lastedge,zl ;save beginning of start bit
121 ; sts srx_lastedge+1,zh
122 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)
177 ldi temp,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
179 ldi temp,(1<<ICF1) ;clear pending int
181 sts srx_state,_0 ;next state
185 subi zl,low (-(SSER_BIT_TC+1)/2)
186 sbci zh,high(-(SSER_BIT_TC+1)/2)
198 ; State 2: collect 1-bits
200 ; lds temp,srx_lastedge
201 ; lds temp2,srx_lastedge+1
202 ; sts srx_lastedge,zl
203 ; sts srx_lastedge+1,zh
205 movw temp,srx_lastedgel
206 movw srx_lastedgel,zl
210 subi zl,low ((SSER_BIT_TC+1)/2)
211 sbci zh,high((SSER_BIT_TC+1)/2)
217 brcs srxi_complete1 ;8 bits recieved
218 subi zl,low(SSER_BIT_TC)
219 sbci zh,high(SSER_BIT_TC)
228 ldi temp2,1 ;We are in start bit now.
231 sts srx_char_to,temp2
238 ; State 3: collect 0-bits
240 ; lds temp,srx_lastedge
241 ; lds temp2,srx_lastedge+1
242 ; sts srx_lastedge,zl
243 ; sts srx_lastedge+1,zh
245 movw temp,srx_lastedgel
246 movw srx_lastedgel,zl
250 subi zl,low ((SSER_BIT_TC+1)/2)
251 sbci zh,high((SSER_BIT_TC+1)/2)
257 brcs srxi_complete0 ;8 bits recieved
258 subi zl,low(SSER_BIT_TC)
259 sbci zh,high(SSER_BIT_TC)
268 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
270 ldi zl,(1<<ICF1) ;clear pending int
271 sts srx_state,_0 ;next state
275 sts srx_char_to,_0 ;clear timeout
276 sts srx_state,_0 ;next state
279 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
281 ldi zl,(1<<ICF1) ;clear pending int
285 ; Save received character in a circular buffer. Do nothing if buffer overflows.
287 lds zh,rxcount ;if rxcount < RXBUFSIZE
288 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
291 sts rxcount,zh ; rxcount++
298 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
299 ldi zh,high(rxfifo) ;
302 st z,temp ; rxfifo[rxidx_w] = char
316 ;----------------------------------------------------------------------
320 .org OC1Aaddr ; Timer/Counter1 Compare Match A
321 rjmp stxint ; Soft UART: TX
332 subi temp,low(-SSER_BIT_TC)
333 sbci zh,high(-SSER_BIT_TC)
336 lds temp,stx_bitcount
341 sts stx_bitcount,temp
348 ldi zh,(1<<COM1A1)|(1<<COM1A0)
361 lds temp,txcount ;if txcount != 0
367 sts txcount,temp ; --txcount
369 ldi zh,high(txfifo) ;
375 andi temp,TXBUFMASK ;
381 sts stx_bitcount,temp
389 ; disable transmitter
391 ldi temp,(1<<COM1A1)|(1<<COM1A0)
394 andi temp,~(1<<OCIE1A)
401 ;------------------------------------------------------------------
405 ldi zl,(1<<ICNC1)|(1<<CS10) ;next edge is falling edge
407 ldi zl,(1<<ICF1) ;clear pending int
425 ; Save received character in a circular buffer. Do nothing if buffer overflows.
427 lds zh,rxcount ;if rxcount < RXBUFSIZE
428 cpi zh,RXBUFSIZE ; (room for at least 1 char?)
431 sts rxcount,zh ; rxcount++
438 sts rxidx_w,zh ; rxidx_w = ++rxidx_w % RXBUFSIZE
439 ldi zh,high(rxfifo) ;
442 st z,temp ; rxfifo[rxidx_w] = char
444 sts srx_state,_0 ;next state
450 ;Fetches a char from the buffer to temp. If none available, waits till one is.
453 lds temp,rxcount ;Number of characters in buffer
455 breq uartgetc ;Wait for char
473 ld temp,z ;don't forget to get the char
478 ;Sends a char from temp to the soft uart.
487 lds temp,txcount ;do {
489 brsh sputc_l ;} while (txcount >= TXBUFSIZE)
492 ldi zh,high(txfifo) ;
498 andi temp,TXBUFMASK ;
499 sts txidx_w,temp ; txidx_w = ++txidx_w % TXBUFSIZE
501 st z,temp ; txfifo[txidx_w] = char
520 ; Wait, till tx buffer is empty.
532 ; vim:set ts=8 noet nowrap