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
200 SET_BIT_IO UCSR0A, U2X0, r24
202 CLEAR_BIT_IO UCSR0A, U2X0, r24
204 ldi r24, (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1)
206 ldi r24, _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0)
211 /******************************************************************************/
213 * ISR(USART0_UDRE_vect){
215 * x = circularbytebuffer_get_fifo(&(uart0_ctx.txb));
217 * / * the transmit buffer is empty, disable interrupt * /
218 * UCSR0B &= (uint8_t)~_BV(UDRIE0);
221 * #if UART0_SWFLOWCTRL
222 * while(!uart0_ctx.txon)
234 in r21, _SFR_IO_ADDR(SREG)
235 CLEAR_BIT_IO UCSR0B, UDRIE0, r22
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
245 CLEAR_BIT_IO UCSR0B, UDRIE0, r24
249 ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
250 ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
257 SET_BIT_IO UCSR0B, UDRIE0, r22
259 ori r21, 0x80 /* set I bit */
260 out _SFR_IO_ADDR(SREG), r21
266 /******************************************************************************/
268 * void uart0_putc (uint16_t c){
269 * #if UART0_SWFLOWCTRL
270 * while(!uart0_ctx.txon)
273 * while(circularbytebuffer_cnt(&(uart0_ctx.txb))==UART0_TXBUFFER_SIZE)
276 * circularbytebuffer_append((uint8_t)c, &(uart0_ctx.txb));
278 * UCSR0B |= (uint8_t)_BV(UDRIE0);
287 ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
288 ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
294 ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
295 ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
302 rcall circularbytebuffer_cnt
304 cpi r24, UART0_TXBUFFER_SIZE
310 rcall circularbytebuffer_append
312 SET_BIT_IO UCSR0B, UDRIE0, r24
315 /******************************************************************************/
317 * ISR(USART0_RX_vect){
320 * #if UART0_SWFLOWCTRL
322 * uart0_ctx.txon = 1;
326 * uart0_ctx.txon = 0;
331 * if((!uart0_ctx.hook_running) && uart0_ctx.hook){
332 * uart0_ctx.hook_running=1;
336 * }while((c=circularbytebuffer_get_fifo(&(uart0_ctx.rxb)))!=0xffff);
337 * uart0_ctx.hook_running=0;
341 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))==UART0_RXBUFFER_SIZE)
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);
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);
363 in r16, _SFR_IO_ADDR(SREG)
367 ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET)
368 ldi r27, hi8(uart0_ctx+UART0_TXON_OFFSET)
380 #endif /* UART0_SWFLOWCTRL */
383 ldi r30, lo8(uart0_ctx)
384 ldi r31, hi8(uart0_ctx)
385 ldd r22, Z+UART0_HOOKR_OFFSET
388 ldd r26, Z+UART0_HOOK_OFFSET
389 ldd r27, Z+UART0_HOOK_OFFSET+1
396 /* now we can run the hook */
401 rcall circularbytebuffer_get_fifo
405 st -Y, r24 /* write 0 to uart0_hook_running */
407 #endif /* UART0_HOOK */
409 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
410 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
412 rcall circularbytebuffer_append
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)
424 cpi r24, UART0_THRESH_HIGH+1
428 rcall circularbytebuffer_push
429 SET_BIT_IO UCSR0B, UDRIE0, r24
432 cpi r24, UART0_THRESH_LOW
436 rcall circularbytebuffer_push
437 SET_BIT_IO UCSR0B, UDRIE0, r24
438 #endif /* UART0_SWFLOWCTRL */
440 out _SFR_IO_ADDR(SREG), r16
445 /******************************************************************************/
447 * uint16_t uart0_getc(void){
449 * while(circularbytebuffer_cnt(&(uart0_ctx.rxb))==0)
452 * ret = circularbytebuffer_get_fifo(&(uart0_ctx.rxb));
459 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
460 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
463 rcall circularbytebuffer_cnt
468 rcall circularbytebuffer_get_fifo
472 /******************************************************************************/
474 * uint8_t uart0_dataavail(void){
475 * return circularbytebuffer_cnt(&(uart0_ctx.rxb));
478 .global 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
484 /******************************************************************************/
487 * void uart0_sethook(void(*fpt)(uint8_t)){
488 * uart0_ctx.hook = fpt;
491 .global uart0_sethook
493 ldi r26, lo8(uart0_ctx+UART0_HOOK_OFFSET)
494 ldi r27, hi8(uart0_ctx+UART0_HOOK_OFFSET)