3 This file is part of the AVR-uart_i.
4 Copyright (C) 2009 Daniel Otte (daniel.otte@rub.de)
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.
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.
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/>.
21 * \email daniel.otte@rub.de
24 * \license GPLv3 or later
26 * \brief implementation of interrupt based uart
31 #include "avr-asm-macros.S"
32 #include "uart_defs.h"
34 #define XON_VALUE 0x11
35 #define XOFF_VALUE 0x13
40 # warning "UART0: using default paraty: 'none'"
41 # define UART0_PARATY UART_PARATY_NONE
44 #ifndef UART0_STOPBITS
45 # warning "UART0: using default ammount of stop bits: '1'"
46 # define UART0_STOPBITS UART_STOPBITS_1
49 #ifndef UART0_DATABITS
50 # warning "UART0: using default ammount of data bits: '8'"
51 # define UART0_DATABITS UART_DATABITS_8
57 # error "can not decide which registernames to use, UDR and UDR0 are defined"
78 #define UART0_CBB_RX_OFFSET 0
79 #define UART0_CBB_TX_OFFSET 10
81 #define CTX_BASE_SIZE (2*(CBB_SIZE))
85 # define UART0_CTX_SIZE (3+2+CTX_BASE_SIZE)
86 # define UART0_HOOK_OFFSET 20
87 # define UART0_HOOKR_OFFSET 22
88 # define UART0_TXON_OFFSET 23
89 # define UART0_RXON_OFFSET 24
91 # define UART0_CTX_SIZE (3+0+CTX_BASE_SIZE)
92 # define UART0_HOOK_OFFSET 20
93 # define UART0_HOOKR_OFFSET 22
97 # define UART0_CTX_SIZE (0+2+CTX_BASE_SIZE)
98 # define UART0_TXON_OFFSET 20
99 # define UART0_RXON_OFFSET 21
101 # define UART0_CTX_SIZE (0+0+CTX_BASE_SIZE)
106 .global uart0_rxbuffer
108 .fill UART0_RXBUFFER_SIZE, 1, 0
109 .global uart0_txbuffer
111 .fill UART0_TXBUFFER_SIZE, 1, 0
114 .fill UART0_CTX_SIZE, 1, 0
115 /******************************************************************************/
116 /* Baudrate calculation */
121 #define BAUD UART0_BAUD_RATE
122 #include "setbaud_asm.inc"
125 /******************************************************************************/
127 * void uart0_init(void){
128 * circularbytebuffer_init2(UART0_RXBUFFER_SIZE, &(uart0_ctx.rxb), uart0_rxbuffer);
129 * circularbytebuffer_init2(UART0_TXBUFFER_SIZE, &(uart0_ctx.txb), uart0_txbuffer);
131 * uart0_ctx.hook = NULL;
132 * uart0_ctx.hook_running = 0;
134 * #if UART0_SWFLOWCTRL
135 * uart0_ctx.txon = 1;
136 * uart0_ctx.rxon = 1;
138 * #define BAUD UART0_BAUD_RATE
139 * #include <util/setbaud.h>
140 * UBRR0H = UBRRH_VALUE;
141 * UBRR0L = UBRRL_VALUE;
143 * UCSR0A |= _BV(U2X0);
145 * UCSR0A &= ~_BV(U2X0);
147 * UCSR0C = (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1);
148 * UCSR0B = _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0) ; / * enable TX and RX and interrupts * /
155 ldi r24, UART0_RXBUFFER_SIZE
157 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
158 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
159 ldi r24, UART0_RXBUFFER_SIZE
160 ldi r20, lo8(uart0_rxbuffer)
161 ldi r21, hi8(uart0_rxbuffer)
162 rcall circularbytebuffer_init2
163 ldi r24, UART0_TXBUFFER_SIZE
165 ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
166 ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
167 ldi r24, UART0_TXBUFFER_SIZE
168 ldi r20, lo8(uart0_txbuffer)
169 ldi r21, hi8(uart0_txbuffer)
170 rcall circularbytebuffer_init2
172 ldi r30, lo8(uart0_ctx)
173 ldi r31, hi8(uart0_ctx)
175 std Z+UART0_TXON_OFFSET, r24
176 std Z+UART0_RXON_OFFSET, r24
183 SET_BIT_IO UCSR0A, U2X0, r24
185 CLEAR_BIT_IO UCSR0A, U2X0, r24
188 ldi r24, (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1)
190 ldi r24, _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0)
195 /******************************************************************************/
197 * ISR(USART0_UDRE_vect){
199 * x = circularbytebuffer_get_fifo(&(uart0_ctx.txb));
201 * / * the transmit buffer is empty, disable interrupt * /
202 * UCSR0B &= (uint8_t)~_BV(UDRIE0);
205 * #if UART0_SWFLOWCTRL
206 * while(!uart0_ctx.txon)
213 .global USART0_UDRE_vect
217 in r21, _SFR_IO_ADDR(SREG)
218 ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
219 ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
220 rcall circularbytebuffer_get_fifo
223 CLEAR_BIT_IO UCSR0B, UDRIE0, r24
227 ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
228 ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
236 out _SFR_IO_ADDR(SREG), r21
241 /******************************************************************************/
243 * void uart0_putc (uint16_t c){
244 * #if UART0_SWFLOWCTRL
245 * while(!uart0_ctx.txon)
248 * while(circularbytebuffer_cnt(&(uart0_ctx.txb))==UART0_TXBUFFER_SIZE)
251 * circularbytebuffer_append((uint8_t)c, &(uart0_ctx.txb));
253 * UCSR0B |= (uint8_t)_BV(UDRIE0);
262 ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
263 ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
269 ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
270 ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
273 rcall circularbytebuffer_cnt
274 cpi r24, UART0_TXBUFFER_SIZE
280 rcall circularbytebuffer_append
282 SET_BIT_IO UCSR0B, UDRIE0, r24
285 /******************************************************************************/
287 * ISR(USART0_RX_vect){
290 * #if UART0_SWFLOWCTRL
292 * uart0_ctx.txon = 1;
296 * uart0_ctx.txon = 0;
301 * if((!uart0_ctx.hook_running) && uart0_ctx.hook){
302 * uart0_ctx.hook_running=1;
306 * }while((c=circularbytebuffer_get_fifo(&(uart0_ctx.rxb)))!=0xffff);
307 * uart0_ctx.hook_running=0;
311 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))==UART0_RXBUFFER_SIZE)
313 * circularbytebuffer_append(c, &(uart0_ctx.rxb));
314 * #if UART0_SWFLOWCTRL
315 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))>UART0_THRESH_HIGH && uart0_ctx.rxon){
316 * uart0_ctx.rxon = 0;
317 * circularbytebuffer_push(XOFF_VALUE, &(uart0_ctx.txb));
318 * UCSR0B |= (uint8_t)_BV(UDRIE0);
320 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))<UART0_THRESH_LOW && !uart0_ctx.rxon){
321 * uart0_ctx.rxon = 1;
322 * circularbytebuffer_push(XON_VALUE, &(uart0_ctx.txb));
323 * UCSR0B |= (uint8_t)_BV(UDRIE0);
329 .global USART0_RX_vect
333 in r18, _SFR_IO_ADDR(SREG)
336 ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET)
337 ldi r27, hi8(uart0_ctx+UART0_TXON_OFFSET)
349 #endif /* UART0_SWFLOWCTRL */
352 ldi r30, lo8(uart0_ctx)
353 ldi r31, hi8(uart0_ctx)
354 ldd r22, Z+UART0_HOOKR_OFFSET
357 ldd r26, Z+UART0_HOOK_OFFSET
358 ldd r27, Z+UART0_HOOK_OFFSET+1
365 /* now we can run the hook */
370 rcall circularbytebuffer_get_fifo
374 st -Y, r24 /* write 0 to uart0_hook_running */
376 #endif /* UART0_HOOK */
378 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
379 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
381 rcall circularbytebuffer_append
383 ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
384 ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
385 rcall circularbytebuffer_cnt
386 ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
387 ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
388 ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET)
389 ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET)
393 cpi r24, UART0_THRESH_HIGH+1
397 rcall circularbytebuffer_push
398 SET_BIT_IO UCSR0B, UDRIE0, r24
401 cpi r24, UART0_THRESH_LOW
405 rcall circularbytebuffer_push
406 SET_BIT_IO UCSR0B, UDRIE0, r24
407 #endif /* UART0_SWFLOWCTRL */
409 out _SFR_IO_ADDR(SREG), r18
414 /******************************************************************************/
416 * uint16_t uart0_getc(void){
418 * while(circularbytebuffer_cnt(&(uart0_ctx.rxb))==0)
421 * ret = circularbytebuffer_get_fifo(&(uart0_ctx.rxb));
428 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
429 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
432 rcall circularbytebuffer_cnt
437 rcall circularbytebuffer_get_fifo
441 /******************************************************************************/
443 * uint8_t uart0_dataavail(void){
444 * return circularbytebuffer_cnt(&(uart0_ctx.rxb));
447 .global uart0_dataavail
449 ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
450 ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
451 rjmp circularbytebuffer_cnt
453 /******************************************************************************/
456 * void uart0_sethook(void(*fpt)(uint8_t)){
457 * uart0_ctx.hook = fpt;
460 .global uart0_sethook
462 ldi r26, lo8(uart0_ctx+UART0_HOOK_OFFSET)
463 ldi r27, hi8(uart0_ctx+UART0_HOOK_OFFSET)