]> git.cryptolib.org Git - avr-crypto-lib.git/blob - test_src/uart_i-asm.S
big bug fixed, still some problems with flow control
[avr-crypto-lib.git] / test_src / uart_i-asm.S
1 /* uart_i-asm.S */
2 /*
3     This file is part of the AVR-uart_i.
4     Copyright (C) 2009  Daniel Otte (daniel.otte@rub.de)
5
6     This program is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 /**
20  * \file     uart_i-asm.S
21  * \email    daniel.otte@rub.de
22  * \author   Daniel Otte 
23  * \date     2009-07-24
24  * \license  GPLv3 or later
25  * \ingroup  uart_i
26  * \brief    implementation of interrupt based uart
27  */
28
29 #include <avr/io.h>
30 #include "config.h"
31 #include "avr-asm-macros.S"
32 #include "uart_defs.h"
33
34 #define XON_VALUE  0x11
35 #define XOFF_VALUE 0x13
36
37 #if UART0_I
38
39 #ifndef UART0_PARATY
40 # warning "UART0: using default paraty: 'none'"
41 # define UART0_PARATY UART_PARATY_NONE
42 #endif
43
44 #ifndef UART0_STOPBITS
45 # warning "UART0: using default ammount of stop bits: '1'"
46 # define UART0_STOPBITS UART_STOPBITS_1
47 #endif
48
49 #ifndef UART0_DATABITS
50 # warning "UART0: using default ammount of data bits: '8'"
51 # define UART0_DATABITS UART_DATABITS_8
52 #endif
53
54 #ifdef UDR
55 # define OLD_UART
56 # ifdef UDR0
57 #  error "can not decide which registernames to use, UDR and UDR0 are defined"
58 # endif
59 #endif
60
61 #ifdef OLD_UART
62 # define UCSR0A UCSRA
63 # define UCSR0B UCSRB
64 # define UCSR0C UCSRC
65 # define UBRR0H UBRRH
66 # define UBRR0L UBRRL
67 # define UDR0   UDR
68 # define TXEN0  TXEN
69 # define RXEN0  RXEN
70 # define UDRE0  UDRE
71 # define RXC0   RXC
72 # define TXB80  TXB8
73 # define RXB80  RXB8
74 # define U2X0   U2X
75 # define UDRIE0 UDRIE
76 # define RXCIE0 RXCIE
77 #endif
78
79 #ifdef USART0_RX_vect
80 # define RX_ISR USART0_RX_vect
81 #endif
82
83 #ifdef USART_RXC_vect
84 # define RX_ISR USART_RXC_vect
85 #endif
86
87 #ifdef USART0_UDRE_vect
88 # define TX_ISR USART0_UDRE_vect
89 #endif
90
91 #ifdef USART_UDRE_vect
92 # define TX_ISR USART_UDRE_vect
93 #endif
94
95 #define CBB_SIZE 10
96
97 #define UART0_CBB_RX_OFFSET  0
98 #define UART0_CBB_TX_OFFSET 10
99
100 #define CTX_BASE_SIZE (2*(CBB_SIZE))
101
102 #if UART0_HOOK
103 #  if UART0_SWFLOWCTRL
104 #    define UART0_CTX_SIZE (3+2+CTX_BASE_SIZE)
105 #    define UART0_HOOK_OFFSET  20
106 #    define UART0_HOOKR_OFFSET 22
107 #    define UART0_TXON_OFFSET  23
108 #    define UART0_RXON_OFFSET  24
109 #  else
110 #    define UART0_CTX_SIZE (3+0+CTX_BASE_SIZE)
111 #    define UART0_HOOK_OFFSET  20
112 #    define UART0_HOOKR_OFFSET 22
113 #  endif
114 #else
115 #  if UART0_SWFLOWCTRL
116 #    define UART0_CTX_SIZE (0+2+CTX_BASE_SIZE)
117 #    define UART0_TXON_OFFSET  20
118 #    define UART0_RXON_OFFSET  21
119 #  else
120 #    define UART0_CTX_SIZE (0+0+CTX_BASE_SIZE)
121 #  endif
122 #endif
123
124         .section .bss
125 .global uart0_rxbuffer
126 uart0_rxbuffer:
127         .fill UART0_RXBUFFER_SIZE, 1, 0
128 .global uart0_txbuffer
129 uart0_txbuffer:
130         .fill UART0_TXBUFFER_SIZE, 1, 0
131 .global uart0_ctx
132 uart0_ctx:
133         .fill UART0_CTX_SIZE, 1, 0      
134 /******************************************************************************/        
135 /* Baudrate calculation */
136 #ifdef BAUD
137 #undef BAUD
138 #endif
139
140 #define BAUD UART0_BAUD_RATE
141 #include "setbaud_asm.inc"
142
143         .section .text
144 /******************************************************************************/        
145 /*
146  *      void uart0_init(void){
147  *              circularbytebuffer_init2(UART0_RXBUFFER_SIZE, &(uart0_ctx.rxb), uart0_rxbuffer);
148  *              circularbytebuffer_init2(UART0_TXBUFFER_SIZE, &(uart0_ctx.txb), uart0_txbuffer);
149  *      #if UART0_HOOK
150  *              uart0_ctx.hook = NULL;
151  *              uart0_ctx.hook_running = 0;
152  *      #endif
153  *      #if UART0_SWFLOWCTRL
154  *              uart0_ctx.txon = 1;
155  *              uart0_ctx.rxon = 1;
156  *      #endif
157  *              #define BAUD UART0_BAUD_RATE
158  *              #include <util/setbaud.h>       
159  *              UBRR0H = UBRRH_VALUE;
160  *              UBRR0L = UBRRL_VALUE;
161  *              #if USE_2X
162  *              UCSR0A |= _BV(U2X0);
163  *              #else
164  *              UCSR0A &= ~_BV(U2X0);
165  *              #endif
166  *              UCSR0C = (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1);
167  *              UCSR0B = _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0) ; / * enable TX and RX and interrupts * /
168  *              sei();
169  *      }
170  *
171  */
172 .global uart0_init
173 uart0_init:
174         ldi r24, UART0_RXBUFFER_SIZE
175         clr r25
176         ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
177         ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
178         ldi r20, lo8(uart0_rxbuffer)
179         ldi r21, hi8(uart0_rxbuffer)
180         rcall circularbytebuffer_init2
181         ldi r24, UART0_TXBUFFER_SIZE
182         clr r25
183         ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
184         ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
185         ldi r20, lo8(uart0_txbuffer)
186         ldi r21, hi8(uart0_txbuffer)
187         rcall circularbytebuffer_init2
188 #if UART0_SWFLOWCTRL
189         ldi r30, lo8(uart0_ctx)
190         ldi r31, hi8(uart0_ctx)
191         ldi r24, 1
192         std Z+UART0_TXON_OFFSET, r24
193         std Z+UART0_RXON_OFFSET, r24
194 #endif  
195         ldi r24, UBRRH_VALUE
196         STORE_IO UBRR0H, r24
197         ldi r24, UBRRL_VALUE
198         STORE_IO UBRR0L, r24
199 #if USE_2X
200         SET_BIT_IO UCSR0A, U2X0, r24
201 #else
202         CLEAR_BIT_IO UCSR0A, U2X0, r24
203 #endif
204         ldi r24, (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1)
205         STORE_IO UCSR0C, r24
206         ldi r24, _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0)  
207         STORE_IO UCSR0B, r24
208         sei
209         ret
210         
211 /******************************************************************************/        
212 /*
213  *      ISR(USART0_UDRE_vect){
214  *              uint16_t x;
215  *              x = circularbytebuffer_get_fifo(&(uart0_ctx.txb));
216  *              if(x==0xffff){
217  *                      / * the transmit buffer is empty, disable interrupt * /
218  *                      UCSR0B &= (uint8_t)~_BV(UDRIE0);
219  *                      return;
220  *              }
221  *      #if UART0_SWFLOWCTRL
222  *              while(!uart0_ctx.txon)
223  *                      ;
224  *      #endif          
225  *              UDR0 = x;
226  *      }
227  */ 
228  
229 .global TX_ISR
230 TX_ISR:
231         push r1
232         push r21
233         push r22
234         in r21, _SFR_IO_ADDR(SREG)
235         CLEAR_BIT_IO UCSR0B, UDRIE0, r22
236         sei
237         push_range 23, 27
238         push_range 30, 31
239         clr r1
240         ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
241         ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
242         rcall circularbytebuffer_get_fifo
243         cpi r25, 0xff
244         brne 20f
245         CLEAR_BIT_IO UCSR0B, UDRIE0, r24
246         rjmp 99f
247 20:
248 #if UART0_SWFLOWCTRL
249         ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
250         ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
251 30:
252         ld r22, Z
253         tst r22
254         breq 30b
255 #endif
256         STORE_IO UDR0, r24
257         SET_BIT_IO UCSR0B, UDRIE0, r22
258 99:
259         ori r21, 0x80 /* set I bit */
260         out _SFR_IO_ADDR(SREG), r21
261         pop_range 30, 31
262         pop_range 21, 27
263         pop r1
264         ret
265         
266 /******************************************************************************/
267 /*
268  *      void uart0_putc (uint16_t c){
269  *      #if UART0_SWFLOWCTRL
270  *              while(!uart0_ctx.txon)
271  *                      ;
272  *      #endif  
273  *              while(circularbytebuffer_cnt(&(uart0_ctx.txb))==UART0_TXBUFFER_SIZE)
274  *                      ;
275  *              cli();          
276  *              circularbytebuffer_append((uint8_t)c, &(uart0_ctx.txb));
277  *              sei();
278  *              UCSR0B |= (uint8_t)_BV(UDRIE0);
279  *      }
280  *
281  * param c:  r24:r25
282  */
283 .global uart0_putc
284 uart0_putc:
285         mov r18, r24
286 #if UART0_SWFLOWCTRL
287         ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
288         ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
289 10:
290         ld r22, Z
291         tst r22
292         breq 10b
293 #endif
294         ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
295         ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
296 20:
297 ;       sei
298         movw r24, r26
299 ;       nop
300 ;       nop
301         cli
302         rcall circularbytebuffer_cnt
303         sei
304         cpi r24, UART0_TXBUFFER_SIZE
305         breq 20b
306         movw r22, r26
307         mov r24, r18
308         clr r25
309         cli
310         rcall circularbytebuffer_append
311         sei
312         SET_BIT_IO UCSR0B, UDRIE0, r24
313         ret
314
315 /******************************************************************************/
316 /*
317  *      ISR(USART0_RX_vect){
318  *              uint16_t c;
319  *              c = UDR0;
320  *      #if UART0_SWFLOWCTRL
321  *              if(c==XON_VALUE){
322  *                      uart0_ctx.txon = 1;
323  *                      return;
324  *              }
325  *              if(c==XOFF_VALUE){
326  *                      uart0_ctx.txon = 0;
327  *                      return;
328  *              }
329  *      #endif          
330  *      #if     UART0_HOOK
331  *              if((!uart0_ctx.hook_running) && uart0_ctx.hook){
332  *                      uart0_ctx.hook_running=1;
333  *                      sei();
334  *                      do{
335  *                              uart0_ctx.hook(c);
336  *                      }while((c=circularbytebuffer_get_fifo(&(uart0_ctx.rxb)))!=0xffff);
337  *                      uart0_ctx.hook_running=0;
338  *                      return;
339  *              }
340  *      #endif
341  *              if(circularbytebuffer_cnt(&(uart0_ctx.rxb))==UART0_RXBUFFER_SIZE)
342  *                      return;
343  *              circularbytebuffer_append(c, &(uart0_ctx.rxb));
344  *      #if UART0_SWFLOWCTRL
345  *              if(circularbytebuffer_cnt(&(uart0_ctx.rxb))>UART0_THRESH_HIGH && uart0_ctx.rxon){
346  *                      uart0_ctx.rxon = 0;
347  *                      circularbytebuffer_push(XOFF_VALUE, &(uart0_ctx.txb));
348  *                      UCSR0B |= (uint8_t)_BV(UDRIE0);
349  *              }
350  *              if(circularbytebuffer_cnt(&(uart0_ctx.rxb))<UART0_THRESH_LOW && !uart0_ctx.rxon){
351  *                      uart0_ctx.rxon = 1;
352  *                      circularbytebuffer_push(XON_VALUE, &(uart0_ctx.txb));
353  *                      UCSR0B |= (uint8_t)_BV(UDRIE0);
354  *              }
355  *      #endif          
356  *      }
357  *
358  */
359  .global RX_ISR
360  RX_ISR:
361         push_range 0, 1
362         push_range 16, 31
363         in r16, _SFR_IO_ADDR(SREG)
364         clr r1
365         LOAD_IO r24, UDR0
366 #if UART0_SWFLOWCTRL
367         ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET)
368         ldi r27, hi8(uart0_ctx+UART0_TXON_OFFSET)
369         cpi r24, XON_VALUE
370         brne 10f
371         ldi r24, 1
372         st X, r24
373         rjmp 99f
374 10:     
375         cpi r24, XOFF_VALUE
376         brne 20f
377         clr r24
378         st X, r24
379         rjmp 99f
380 #endif /* UART0_SWFLOWCTRL */   
381 20:     
382 #if UART0_HOOK
383         ldi r30, lo8(uart0_ctx)
384         ldi r31, hi8(uart0_ctx)
385         ldd r22, Z+UART0_HOOKR_OFFSET
386         tst r22
387         brne 50f
388         ldd r26, Z+UART0_HOOK_OFFSET
389         ldd r27, Z+UART0_HOOK_OFFSET+1
390         adiw r26, 0
391         breq 50f
392         movw r28, r26
393         movw r16, r30
394         sei
395 30:
396         /* now we can run the hook */
397         movw r30, r28
398         clr r25
399         icall
400         movw r24, r16
401         rcall circularbytebuffer_get_fifo 
402         cpi r25, 0xff
403         brne 30b
404         clr r24
405         st -Y, r24 /* write 0 to uart0_hook_running */
406         rjmp 99f
407 #endif /* UART0_HOOK */
408 50:
409         ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
410         ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
411         clr r25
412         rcall circularbytebuffer_append
413 #if UART0_SWFLOWCTRL
414         ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
415         ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
416         rcall circularbytebuffer_cnt
417         ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
418         ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
419         ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET)
420         ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET)
421         ld r18, Z
422         tst r18
423         breq 60f
424         cpi r24, UART0_THRESH_HIGH+1
425         brlo 99f
426         clr r25
427         ldi r24, XOFF_VALUE
428         rcall circularbytebuffer_push
429         SET_BIT_IO UCSR0B, UDRIE0, r24
430         rjmp 99f
431 60:
432         cpi r24, UART0_THRESH_LOW
433         brge 99f
434         clr r25
435         ldi r24, XON_VALUE
436         rcall circularbytebuffer_push
437         SET_BIT_IO UCSR0B, UDRIE0, r24
438 #endif /* UART0_SWFLOWCTRL */
439 99:     
440         out _SFR_IO_ADDR(SREG), r16
441         pop_range 16, 31
442         pop_range 0, 1
443         reti
444
445 /******************************************************************************/
446 /*
447  *      uint16_t uart0_getc(void){
448  *              uint8_t ret;
449  *              while(circularbytebuffer_cnt(&(uart0_ctx.rxb))==0)
450  *                      ;
451  *              cli();  
452  *              ret = circularbytebuffer_get_fifo(&(uart0_ctx.rxb));
453  *              sei();
454  *              return  ret;
455  *      }
456  */
457  .global uart0_getc
458  uart0_getc:
459         ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
460         ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
461  10:
462         movw r24, r22
463         rcall circularbytebuffer_cnt
464         tst r24
465         breq 10b
466         movw r24, r22
467         cli
468         rcall circularbytebuffer_get_fifo
469         clr r25
470         reti
471         
472 /******************************************************************************/
473 /*
474  *      uint8_t uart0_dataavail(void){
475  *              return circularbytebuffer_cnt(&(uart0_ctx.rxb));
476  *      }
477  */
478 .global uart0_dataavail
479 uart0_dataavail:
480         ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
481         ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
482         rjmp circularbytebuffer_cnt
483         
484 /******************************************************************************/
485 #if     UART0_HOOK
486 /*
487  *      void uart0_sethook(void(*fpt)(uint8_t)){
488  *              uart0_ctx.hook = fpt;
489  *      }
490  */
491 .global uart0_sethook
492 uart0_sethook:
493         ldi r26, lo8(uart0_ctx+UART0_HOOK_OFFSET)
494         ldi r27, hi8(uart0_ctx+UART0_HOOK_OFFSET)
495         st X+, r24
496         st X+, r25
497         ret
498 #endif
499         
500 #endif /* UART0_I */