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"
80 # define RX_ISR USART0_RX_vect
84 # define RX_ISR USART_RXC_vect
87 #ifdef USART0_UDRE_vect
88 # define TX_ISR USART0_UDRE_vect
91 #ifdef USART_UDRE_vect
92 # define TX_ISR USART_UDRE_vect
97 #define UART0_CBB_RX_OFFSET 0
98 #define UART0_CBB_TX_OFFSET 10
100 #define CTX_BASE_SIZE (2*(CBB_SIZE))
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
110 # define UART0_CTX_SIZE (3+0+CTX_BASE_SIZE)
111 # define UART0_HOOK_OFFSET 20
112 # define UART0_HOOKR_OFFSET 22
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
120 # define UART0_CTX_SIZE (0+0+CTX_BASE_SIZE)
125 .global uart0_rxbuffer
127 .fill UART0_RXBUFFER_SIZE, 1, 0
128 .global uart0_txbuffer
130 .fill UART0_TXBUFFER_SIZE, 1, 0
133 .fill UART0_CTX_SIZE, 1, 0
134 /******************************************************************************/
135 /* Baudrate calculation */
140 #define BAUD UART0_BAUD_RATE
141 #include "setbaud_asm.inc"
144 /******************************************************************************/
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);
150 * uart0_ctx.hook = NULL;
151 * uart0_ctx.hook_running = 0;
153 * #if UART0_SWFLOWCTRL
154 * uart0_ctx.txon = 1;
155 * uart0_ctx.rxon = 1;
157 * #define BAUD UART0_BAUD_RATE
158 * #include <util/setbaud.h>
159 * UBRR0H = UBRRH_VALUE;
160 * UBRR0L = UBRRL_VALUE;
162 * UCSR0A |= _BV(U2X0);
164 * UCSR0A &= ~_BV(U2X0);
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 * /
174 ldi r24, UART0_RXBUFFER_SIZE
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
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
189 ldi r30, lo8(uart0_ctx)
190 ldi r31, hi8(uart0_ctx)
192 std Z+UART0_TXON_OFFSET, r24
193 std Z+UART0_RXON_OFFSET, r24
196 std Z+UART0_HOOK_OFFSET, r1
197 std Z+UART0_HOOK_OFFSET+1, r1
198 std Z+UART0_HOOKR_OFFSET, r1
205 SET_BIT_IO UCSR0A, U2X0, r24
207 CLEAR_BIT_IO UCSR0A, U2X0, r24
209 ldi r24, (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1)
211 ldi r24, _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0)
216 /******************************************************************************/
218 * ISR(USART0_UDRE_vect){
220 * x = circularbytebuffer_get_fifo(&(uart0_ctx.txb));
222 * / * the transmit buffer is empty, disable interrupt * /
223 * UCSR0B &= (uint8_t)~_BV(UDRIE0);
226 * #if UART0_SWFLOWCTRL
227 * while(!uart0_ctx.txon)
239 in r21, _SFR_IO_ADDR(SREG)
240 CLEAR_BIT_IO UCSR0B, UDRIE0, r22
245 ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
246 ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
247 rcall circularbytebuffer_get_fifo
250 CLEAR_BIT_IO UCSR0B, UDRIE0, r24
254 ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
255 ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
262 SET_BIT_IO UCSR0B, UDRIE0, r22
264 ori r21, 0x80 /* set I bit */
265 out _SFR_IO_ADDR(SREG), r21
271 /******************************************************************************/
273 * void uart0_putc (uint16_t c){
274 * #if UART0_SWFLOWCTRL
275 * while(!uart0_ctx.txon)
278 * while(circularbytebuffer_cnt(&(uart0_ctx.txb))==UART0_TXBUFFER_SIZE)
281 * circularbytebuffer_append((uint8_t)c, &(uart0_ctx.txb));
283 * UCSR0B |= (uint8_t)_BV(UDRIE0);
292 ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
293 ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
299 ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
300 ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
304 rcall circularbytebuffer_cnt
306 cpi r24, UART0_TXBUFFER_SIZE
312 rcall circularbytebuffer_append
313 SET_BIT_IO UCSR0B, UDRIE0, r24
316 /******************************************************************************/
318 * ISR(USART0_RX_vect){
321 * #if UART0_SWFLOWCTRL
323 * uart0_ctx.txon = 1;
327 * uart0_ctx.txon = 0;
332 * if((!uart0_ctx.hook_running) && uart0_ctx.hook){
333 * uart0_ctx.hook_running=1;
337 * }while((c=circularbytebuffer_get_fifo(&(uart0_ctx.rxb)))!=0xffff);
338 * uart0_ctx.hook_running=0;
342 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))==UART0_RXBUFFER_SIZE)
344 * circularbytebuffer_append(c, &(uart0_ctx.rxb));
345 * #if UART0_SWFLOWCTRL
346 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))>UART0_THRESH_HIGH && uart0_ctx.rxon){
347 * uart0_ctx.rxon = 0;
348 * circularbytebuffer_push(XOFF_VALUE, &(uart0_ctx.txb));
349 * UCSR0B |= (uint8_t)_BV(UDRIE0);
351 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))<UART0_THRESH_LOW && !uart0_ctx.rxon){
352 * uart0_ctx.rxon = 1;
353 * circularbytebuffer_push(XON_VALUE, &(uart0_ctx.txb));
354 * UCSR0B |= (uint8_t)_BV(UDRIE0);
364 in r16, _SFR_IO_ADDR(SREG)
368 ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET)
369 ldi r27, hi8(uart0_ctx+UART0_TXON_OFFSET)
379 /* now the "sending" part*/
380 ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
381 ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
382 rcall circularbytebuffer_cnt
383 ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET)
384 ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET)
387 breq 15f/* branch if rxon inactive -> we had send an XOFF earlier */
388 /* ok, we did not have send an XOFF, should we? */
389 cpi r24, UART0_THRESH_HIGH
390 brlo 90f /* ok, nothing critical, go on */
393 ; sbi _SFR_IO_ADDR(PORTD), 5
396 cpi r24, UART0_THRESH_LOW
397 brsh 90f /* nothing has changed */
398 /* if we get here, we had send an XOFF and are now below threshold */
399 /* so we sen an XON */
401 cbi _SFR_IO_ADDR(PORTD), 5
404 ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
405 ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
406 rcall circularbytebuffer_push
407 SET_BIT_IO UCSR0B, UDRIE0, r24
410 #endif /* UART0_SWFLOWCTRL */
413 ldi r30, lo8(uart0_ctx)
414 ldi r31, hi8(uart0_ctx)
415 ldd r22, Z+UART0_HOOKR_OFFSET
418 ldd r26, Z+UART0_HOOK_OFFSET
419 ldd r27, Z+UART0_HOOK_OFFSET+1
426 /* now we can run the hook */
431 rcall circularbytebuffer_get_fifo
435 st -Y, r24 /* write 0 to uart0_hook_running */
437 #endif /* UART0_HOOK */
439 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
440 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
442 ; sbi _SFR_IO_ADDR(PORTD), 6
443 rcall circularbytebuffer_append
445 out _SFR_IO_ADDR(SREG), r16
450 /******************************************************************************/
452 * uint16_t uart0_getc(void){
454 * while(circularbytebuffer_cnt(&(uart0_ctx.rxb))==0)
457 * ret = circularbytebuffer_get_fifo(&(uart0_ctx.rxb));
464 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
465 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
468 rcall circularbytebuffer_cnt
473 rcall circularbytebuffer_get_fifo
477 /******************************************************************************/
479 * uint8_t uart0_dataavail(void){
480 * return circularbytebuffer_cnt(&(uart0_ctx.rxb));
483 .global uart0_dataavail
485 ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
486 ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
487 rjmp circularbytebuffer_cnt
489 /******************************************************************************/
492 * void uart0_sethook(void(*fpt)(uint8_t)){
493 * uart0_ctx.hook = fpt;
496 .global uart0_sethook
498 ldi r26, lo8(uart0_ctx+UART0_HOOK_OFFSET)
499 ldi r27, hi8(uart0_ctx+UART0_HOOK_OFFSET)
508 ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
509 ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
510 rcall circularbytebuffer_cnt