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"
33 #define XON_VALUE 0x11
34 #define XOFF_VALUE 0x13
39 # error "can not decide which registernames to use, UDR and UDR0 are defined"
60 #define UART0_CBB_RX_OFFSET 0
61 #define UART0_CBB_TX_OFFSET 10
63 #define CTX_BASE_SIZE (2*(CBB_SIZE))
67 # define UART0_CTX_SIZE (3+2+CTX_BASE_SIZE)
68 # define UART0_HOOK_OFFSET 20
69 # define UART0_HOOKR_OFFSET 22
70 # define UART0_TXON_OFFSET 23
71 # define UART0_RXON_OFFSET 24
73 # define UART0_CTX_SIZE (3+0+CTX_BASE_SIZE)
74 # define UART0_HOOK_OFFSET 20
75 # define UART0_HOOKR_OFFSET 22
79 # define UART0_CTX_SIZE (0+2+CTX_BASE_SIZE)
80 # define UART0_TXON_OFFSET 20
81 # define UART0_RXON_OFFSET 21
83 # define UART0_CTX_SIZE (0+0+CTX_BASE_SIZE)
88 .global uart0_rxbuffer
90 .fill UART0_RXBUFFER_SIZE, 1, 0
91 .global uart0_txbuffer
93 .fill UART0_TXBUFFER_SIZE, 1, 0
96 .fill UART0_CTX_SIZE, 1, 0
97 /******************************************************************************/
98 /* Baudrate calculation */
103 #define BAUD UART0_BAUD_RATE
104 #include "setbaud_asm.inc"
107 /******************************************************************************/
109 * void uart0_init(void){
110 * circularbytebuffer_init2(UART0_RXBUFFER_SIZE, &(uart0_ctx.rxb), uart0_rxbuffer);
111 * circularbytebuffer_init2(UART0_TXBUFFER_SIZE, &(uart0_ctx.txb), uart0_txbuffer);
113 * uart0_ctx.hook = NULL;
114 * uart0_ctx.hook_running = 0;
116 * #if UART0_SWFLOWCTRL
117 * uart0_ctx.txon = 1;
118 * uart0_ctx.rxon = 1;
120 * #define BAUD UART0_BAUD_RATE
121 * #include <util/setbaud.h>
122 * UBRR0H = UBRRH_VALUE;
123 * UBRR0L = UBRRL_VALUE;
125 * UCSR0A |= _BV(U2X0);
127 * UCSR0A &= ~_BV(U2X0);
129 * UCSR0C = (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1);
130 * UCSR0B = _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0) ; / * enable TX and RX and interrupts * /
137 ldi r24, UART0_RXBUFFER_SIZE
139 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
140 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
141 ldi r24, UART0_RXBUFFER_SIZE
142 ldi r20, lo8(uart0_rxbuffer)
143 ldi r21, hi8(uart0_rxbuffer)
144 rcall circularbytebuffer_init2
145 ldi r24, UART0_TXBUFFER_SIZE
147 ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
148 ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
149 ldi r24, UART0_TXBUFFER_SIZE
150 ldi r20, lo8(uart0_txbuffer)
151 ldi r21, hi8(uart0_txbuffer)
152 rcall circularbytebuffer_init2
154 ldi r30, lo8(uart0_ctx)
155 ldi r31, hi8(uart0_ctx)
157 std Z+UART0_TXON_OFFSET, r24
158 std Z+UART0_RXON_OFFSET, r24
165 SET_BIT_IO UCSR0A, U2X0, r24
167 CLEAR_BIT_IO UCSR0A, U2X0, r24
170 ldi r24, (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1)
172 ldi r24, _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0)
177 /******************************************************************************/
179 * ISR(USART0_UDRE_vect){
181 * x = circularbytebuffer_get_fifo(&(uart0_ctx.txb));
183 * / * the transmit buffer is empty, disable interrupt * /
184 * UCSR0B &= (uint8_t)~_BV(UDRIE0);
187 * #if UART0_SWFLOWCTRL
188 * while(!uart0_ctx.txon)
195 .global USART0_UDRE_vect
199 in r21, _SFR_IO_ADDR(SREG)
200 ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
201 ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
202 rcall circularbytebuffer_get_fifo
205 CLEAR_BIT_IO UCSR0B, UDRIE0, r24
209 ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
210 ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
218 out _SFR_IO_ADDR(SREG), r21
223 /******************************************************************************/
225 * void uart0_putc (uint16_t c){
226 * #if UART0_SWFLOWCTRL
227 * while(!uart0_ctx.txon)
230 * while(circularbytebuffer_cnt(&(uart0_ctx.txb))==UART0_TXBUFFER_SIZE)
233 * circularbytebuffer_append((uint8_t)c, &(uart0_ctx.txb));
235 * UCSR0B |= (uint8_t)_BV(UDRIE0);
244 ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET)
245 ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET)
251 ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
252 ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
255 rcall circularbytebuffer_cnt
256 cpi r24, UART0_TXBUFFER_SIZE
262 rcall circularbytebuffer_append
264 SET_BIT_IO UCSR0B, UDRIE0, r24
267 /******************************************************************************/
269 * ISR(USART0_RX_vect){
272 * #if UART0_SWFLOWCTRL
274 * uart0_ctx.txon = 1;
278 * uart0_ctx.txon = 0;
283 * if((!uart0_ctx.hook_running) && uart0_ctx.hook){
284 * uart0_ctx.hook_running=1;
288 * }while((c=circularbytebuffer_get_fifo(&(uart0_ctx.rxb)))!=0xffff);
289 * uart0_ctx.hook_running=0;
293 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))==UART0_RXBUFFER_SIZE)
295 * circularbytebuffer_append(c, &(uart0_ctx.rxb));
296 * #if UART0_SWFLOWCTRL
297 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))>UART0_THRESH_HIGH && uart0_ctx.rxon){
298 * uart0_ctx.rxon = 0;
299 * circularbytebuffer_push(XOFF_VALUE, &(uart0_ctx.txb));
300 * UCSR0B |= (uint8_t)_BV(UDRIE0);
302 * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))<UART0_THRESH_LOW && !uart0_ctx.rxon){
303 * uart0_ctx.rxon = 1;
304 * circularbytebuffer_push(XON_VALUE, &(uart0_ctx.txb));
305 * UCSR0B |= (uint8_t)_BV(UDRIE0);
311 .global USART0_RX_vect
314 in r21, _SFR_IO_ADDR(SREG)
317 ldi r26, lo8(uart0_ctx+UART0_TXON_OFFSET)
318 ldi r27, hi8(uart0_ctx+UART0_TXON_OFFSET)
330 #endif /* UART0_SWFLOWCTRL */
333 ldi r30, lo8(uart0_ctx)
334 ldi r31, hi8(uart0_ctx)
335 ldd r22, Z+UART0_HOOKR_OFFSET
338 ldd r26, Z+UART0_HOOK_OFFSET
339 ldd r27, Z+UART0_HOOK_OFFSET+1
346 /* now we can run the hook */
351 rcall circularbytebuffer_get_fifo
355 st -Y, r24 /* write 0 to uart0_hook_running */
357 #endif /* UART0_HOOK */
359 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
360 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
362 rcall circularbytebuffer_append
364 ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
365 ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
366 rcall circularbytebuffer_cnt
367 ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET)
368 ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET)
369 ldi r30, lo8(uart0_ctx+UART0_RXON_OFFSET)
370 ldi r31, hi8(uart0_ctx+UART0_RXON_OFFSET)
374 cpi r24, UART0_THRESH_HIGH+1
378 rcall circularbytebuffer_push
379 SET_BIT_IO UCSR0B, UDRIE0, r24
382 cpi r24, UART0_THRESH_LOW
386 rcall circularbytebuffer_push
387 SET_BIT_IO UCSR0B, UDRIE0, r24
388 #endif /* UART0_SWFLOWCTRL */
390 out _SFR_IO_ADDR(SREG), r21
394 /******************************************************************************/
396 * uint16_t uart0_getc(void){
398 * while(circularbytebuffer_cnt(&(uart0_ctx.rxb))==0)
401 * ret = circularbytebuffer_get_fifo(&(uart0_ctx.rxb));
408 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
409 ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
412 rcall circularbytebuffer_cnt
417 rcall circularbytebuffer_get_fifo
420 /******************************************************************************/
422 * uint8_t uart0_dataavail(void){
423 * return circularbytebuffer_cnt(&(uart0_ctx.rxb));
426 .global uart0_dataavail
428 ldi r24, lo8(uart0_ctx+UART0_CBB_RX_OFFSET)
429 ldi r25, hi8(uart0_ctx+UART0_CBB_RX_OFFSET)
430 rjmp circularbytebuffer_cnt
432 /******************************************************************************/
435 * void uart0_sethook(void(*fpt)(uint8_t)){
436 * uart0_ctx.hook = fpt;
439 .global uart0_sethook
441 ldi r26, lo8(uart0_ctx+UART0_HOOK_OFFSET)
442 ldi r27, hi8(uart0_ctx+UART0_HOOK_OFFSET)