Added new XPLAIN serial Bridge project (thanks to John Steggall for the software...
[pub/USBasp.git] / Projects / XPLAINBridge / Lib / SoftUART.S
1 /*
2
3 uart_soft
4
5 copyright John Steggall 2009
6
7 */
8
9
10 /*
11 Copyright 2009 John Steggall (steggall.j@gmail.com)
12
13 Permission to use, copy, modify, and distribute this software
14 and its documentation for any purpose and without fee is hereby
15 granted, provided that the above copyright notice appear in all
16 copies and that both that the copyright notice and this
17 permission notice and warranty disclaimer appear in supporting
18 documentation, and that the name of the author not be used in
19 advertising or publicity pertaining to distribution of the
20 software without specific, written prior permission.
21
22 The author disclaim all warranties with regard to this
23 software, including all implied warranties of merchantability
24 and fitness. In no event shall the author be liable for any
25 special, indirect or consequential damages or any damages
26 whatsoever resulting from loss of use, data or profits, whether
27 in an action of contract, negligence or other tortious action,
28 arising out of or in connection with the use or performance of
29 this software.
30 */
31
32 #include <avr/io.h>
33
34 /* BITLENGTH is the time for a bit cycle worked out at F_CPU / BAUD. Gives a rough but usable figure. Wouldn't like to try
35 * anything faster than 9600! */
36 #define BITLENGTH 833
37
38 #define SFT_TX_EN 7
39
40 #define SF_UART_TX 1
41 #define SF_UART_RX 2
42
43 .section .data
44
45 rxdata:
46 .byte 0
47 txShifter:
48 .byte 0
49 txBitcount:
50 .byte 0
51 rxShifter:
52 .byte 0
53 rxBitcount:
54 .byte 0
55 status:
56 .byte 0
57
58 .section .text
59
60 /*********************************************
61 * External interrupt
62 *
63 * RX pin has gone low.
64 */
65 .global INT0_vect
66
67 INT0_vect:
68 push r16
69 lds r16,SREG
70 push r16
71
72 lds r16,PIND
73 sbrc r16,0 // anti glitch
74 rjmp ignore
75 nop
76 nop
77 nop
78 nop
79 lds r16,PIND
80 sbrc r16,0 // just make sure
81 rjmp ignore
82
83 push r17
84
85 // grab timer value
86 lds r16,TCNT3L
87 lds r17,TCNT3H
88
89 // set trigger for RX timer (will need to add a little more though)
90 sts OCR3CH,r17
91 sts OCR3CL,r16
92
93 pop r17
94
95 // set bitcount to 0
96 ldi r16,0
97 sts rxBitcount,r16
98
99
100 // turn off interrupt, will get annoying.
101 cbi 0x1D,0
102
103 // turn on interrupt on compare match
104 sbi 0x18,OCF3C
105 lds r16,TIMSK3
106 ori r16,(1<<OCIE3C)
107 sts TIMSK3,r16
108
109 ignore:
110 pop r16
111 sts SREG,r16
112 pop r16
113 reti
114
115
116 /*********************************************
117 * interrupt routine, timer compare match.
118 *
119 * TX bit rate timing
120 */
121 .global TIMER3_COMPB_vect
122
123 TIMER3_COMPB_vect:
124 push r16
125 lds r16,SREG
126 push r16
127 push r17
128 push r18
129
130 // check if the last bit was sent
131 lds r17,txBitcount
132 inc r17
133 cpi r17,0x0A
134 sts txBitcount,r17
135 breq lastBitTX
136
137 lds r16,txShifter
138
139 lds r17, PORTD
140
141 sbrs r16,0
142 andi r17,0xFD
143 sbrc r16,0
144 ori r17,0x02
145
146 sts PORTD,r17
147
148 lsr r16
149 ori r16,0x80
150
151 txout:
152 sts txShifter,r16
153 lastBitOut:
154 pop r18
155 pop r17
156 pop r16
157 sts SREG,r16
158 pop r16
159 reti
160
161 // section handles the last bit (stop bit sent/received and sets the flag to say done //
162 lastBitTX:
163 lds r17,status // get status
164 ori r17,SF_UART_TX // set TXC/DRE flag
165 sts status,r17
166
167 lds r16,TIMSK3
168 andi r16,~(1<<OCIE3B)
169 sts TIMSK3,r16
170
171 rjmp lastBitOut // over and out
172
173
174
175 /*********************************************
176 * interrupt routine, timer compare match.
177 *
178 * RX bit rate timing
179 */
180 .global TIMER3_COMPC_vect
181
182 TIMER3_COMPC_vect:
183 push r16
184 lds r16,SREG
185 push r16
186 push r17
187 push r18
188
189 // check if the last bit has been recieved
190 lds r17,rxBitcount
191 inc r17
192 cpi r17,0x0A
193 sts rxBitcount,r17
194 breq lastBitRX
195
196 cpi r17,0x01
197 breq rx1stbit
198
199 ldi r18,3 // set counter to 3
200 ldi r17,0
201
202 // cbi 0x0B,1 // marker
203
204 loopGetBit:
205 lds r16,PIND
206 sbrc r16,0
207 inc r17
208 dec r18
209 nop
210 nop
211 nop
212 nop
213 brne loopGetBit
214
215 // sbi 0x0B,1 // marker
216
217 lds r16,rxShifter
218 lsr r16
219
220 cpi r17,2
221 brlo skipBitSet
222 ori r16,0x80
223 skipBitSet:
224 sts rxShifter,r16
225 rjmp lastBitOut
226
227 lastBitRX:
228 lds r17,status // store status
229 lds r16,PIND // get status of stop bit
230 sbrc r16,0
231 ori r17,0x02 // set flag if stop bit was high
232 sts status,r17
233
234 lds r16,rxShifter // get contents of shifter
235 sbrc r17,1 // check if we just received a valid byte
236 sts rxdata,r16 // if valid rxdata = shifter
237
238 // switch interrupt back on to get another go
239
240 sbi 0x1C,0 // clear interrupt flag
241 sbi 0x1D,0 // enable external interrupt 0 (RX)
242
243 // switch off rx bit timer
244 lds r16,TIMSK3
245 andi r16,~(1<<OCIE3C)
246 sts TIMSK3,r16
247
248 rjmp lastBitOut // loud and clear
249
250 rx1stbit:
251 lds r16,TCNT3L
252 lds r17,TCNT3H
253
254 subi r16,lo8(BITLENGTH / 2)
255 sbci r17,hi8(BITLENGTH / 2)
256 brcc skipOverflow
257
258 subi r16,lo8(0xFFFF - BITLENGTH)
259 sbci r17,hi8(0xFFFF - BITLENGTH)
260
261 skipOverflow:
262 sts OCR3CH,r17
263 sts OCR3CL,r17
264 rjmp lastBitOut
265
266
267 /*********************************************
268 * void SoftUART_Init(void)
269 *
270 * initialises software uart and enables transmit
271 */
272 .global SoftUART_Init
273
274 SoftUART_Init:
275
276 lds r18,PORTD
277 ori r18,0x02
278 sts PORTD,r18
279 lds r18,DDRD
280 ori r18,0x02
281 sts DDRD,r18
282
283 ldi r18,(1<<SFT_TX_EN)|SF_UART_TX
284 sts status,r18
285
286 ldi r18,lo8(BITLENGTH)
287 ldi r19,hi8(BITLENGTH)
288 sts OCR3AH,r19
289 sts OCR3AL,r18
290
291 // Start timer 3
292 ldi r18,0b00001001 // ctc count mode, clock div 1
293 sts TCCR3B,r18
294
295 // Interrupt on low level INT0
296 sbi 0x1C,0
297 sbi 0x1D,0
298
299 ret
300
301
302 /*********************************************
303 * char SoftUART_TxByte(char)
304 *
305 * starts a byte send and returns the byte to be sent
306 */
307 .global SoftUART_TxByte
308
309 SoftUART_TxByte:
310 lds r18,status
311 sbrs r18,SFT_TX_EN
312 rjmp uart_putchar_end
313
314 andi r18,0xFE // clear tx empty flag
315 sts status,r18
316
317 sts txShifter,r24
318
319 ldi r18,0
320 sts txBitcount,r18
321
322 // grab timer value
323
324 lds r18,TCNT3L
325 lds r19,TCNT3H
326
327 // drop down tx line for start bit
328 lds r20, PORTD
329 andi r20,0xFD
330 sts PORTD,r20
331
332 // set trigger for tx timer
333 cli
334 sts OCR3BH,r19
335 sts OCR3BL,r18
336 sei
337
338 // clear interrupt flag and enable tx interrupt
339 sbi 0x18,OCF3B
340 lds r18,TIMSK3
341 ori r18,(1<<OCIE3B)
342 sts TIMSK3,r18
343
344 uart_putchar_end:
345 ret
346
347
348 /*********************************************
349 * char SoftUART_RxByte(void)
350 *
351 * returns the received byte
352 */
353 .global SoftUART_RxByte
354
355 SoftUART_RxByte:
356 lds r24,rxdata
357 lds r18,status
358 andi r18,0xFD
359 sts status,r18
360 ret
361
362
363 /*********************************************
364 * char SoftUART_IsReceived(void)
365 *
366 * checks if there is a byte in the receive buffer
367 */
368 .global SoftUART_IsReceived
369
370 SoftUART_IsReceived:
371 lds r24,status
372 andi r24,SF_UART_RX
373 lsr r24
374 ret
375
376
377 /*********************************************
378 * char SoftUART_IsReady(void)
379 *
380 * Simulates polling UDRE to see if tx buffer is empty and ready
381 *
382 * returns 1 if empty 0 if not
383 */
384 .global SoftUART_IsReady
385
386 SoftUART_IsReady:
387 lds r24,status
388 andi r24,SF_UART_TX
389 ret