/* uart_i-asm.S */ /* This file is part of the AVR-uart_i. Copyright (C) 2009 Daniel Otte (daniel.otte@rub.de) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * \file uart_i-asm.S * \email daniel.otte@rub.de * \author Daniel Otte * \date 2009-07-24 * \license GPLv3 or later * \ingroup uart_i * \brief implementation of interrupt based uart */ #include #include "config.h" #include "avr-asm-macros.S" #define XON_VALUE 0x11 #define XOFF_VALUE 0x13 #ifdef UDR # define OLD_UART # ifdef UDR0 # error "can not decide which registernames to use, UDR and UDR0 are defined" # endif #endif #ifdef OLD_UART # define UCSR0A UCSRA # define UCSR0B UCSRB # define UCSR0C UCSRC # define UBRR0H UBRRH # define UBRR0L UBRRL # define UDR0 UDR # define TXEN0 TXEN # define RXEN0 RXEN # define UDRE0 UDRE # define RXC0 RXC # define TXB80 TXB8 # define RXB80 RXB8 #endif #define CBB_SIZE 10 #define UART0_CBB_RX_OFFSET 0 #define UART0_CBB_TX_OFFSET 10 #define CTX_BASE_SIZE (2*(CBB_SIZE)) #if UART0_HOOK # if UART0_SWFLOWCTRL # define UART0_CTX_SIZE (3+2+CTX_BASE_SIZE) # define UART0_HOOK_OFFSET 20 # define UART0_HOOKR_OFFSET 22 # define UART0_TXON_OFFSET 23 # define UART0_RXON_OFFSET 24 # else # define UART0_CTX_SIZE (3+0+CTX_BASE_SIZE) # define UART0_HOOK_OFFSET 20 # define UART0_HOOKR_OFFSET 22 # endif #else # if UART0_SWFLOWCTRL # define UART0_CTX_SIZE (0+2+CTX_BASE_SIZE) # define UART0_TXON_OFFSET 20 # define UART0_RXON_OFFSET 21 # else # define UART0_CTX_SIZE (0+0+CTX_BASE_SIZE) # endif #endif .section .bss .global uart0_rxbuffer uart0_rxbuffer: .fill UART0_RXBUFFER_SIZE, 1, 0 .global uart0_txbuffer uart0_txbuffer: .fill UART0_TXBUFFER_SIZE, 1, 0 .global uart0_ctx uart0_ctx: .fill UART0_CTX_SIZE, 1, 0 /******************************************************************************/ /* Baudrate calculation */ #ifdef BAUD #undef BAUD #endif #define BAUD UART0_BAUD_RATE #include "setbaud_asm.inc" .section .text /******************************************************************************/ /* * void uart0_init(void){ * circularbytebuffer_init2(UART0_RXBUFFER_SIZE, &(uart0_ctx.rxb), uart0_rxbuffer); * circularbytebuffer_init2(UART0_TXBUFFER_SIZE, &(uart0_ctx.txb), uart0_txbuffer); * #if UART0_HOOK * uart0_ctx.hook = NULL; * uart0_ctx.hook_running = 0; * #endif * #if UART0_SWFLOWCTRL * uart0_ctx.txon = 1; * uart0_ctx.rxon = 1; * #endif * #define BAUD UART0_BAUD_RATE * #include * UBRR0H = UBRRH_VALUE; * UBRR0L = UBRRL_VALUE; * #if USE_2X * UCSR0A |= _BV(U2X0); * #else * UCSR0A &= ~_BV(U2X0); * #endif * UCSR0C = (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1); * UCSR0B = _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0) ; / * enable TX and RX and interrupts * / * sei(); * } * */ .global uart0_init uart0_init: ldi r24, UART0_RXBUFFER_SIZE clr r25 ldi r22, lo8(uart0_ctx+UART0_CBB_RX_OFFSET) ldi r23, hi8(uart0_ctx+UART0_CBB_RX_OFFSET) ldi r24, UART0_RXBUFFER_SIZE ldi r20, lo8(uart0_rxbuffer) ldi r21, hi8(uart0_rxbuffer) rcall circularbytebuffer_init2 ldi r24, UART0_TXBUFFER_SIZE clr r25 ldi r22, lo8(uart0_ctx+UART0_CBB_TX_OFFSET) ldi r23, hi8(uart0_ctx+UART0_CBB_TX_OFFSET) ldi r24, UART0_TXBUFFER_SIZE ldi r20, lo8(uart0_txbuffer) ldi r21, hi8(uart0_txbuffer) rcall circularbytebuffer_init2 #if UART0_SWFLOWCTRL ldi r30, lo8(uart0_ctx) ldi r31, hi8(uart0_ctx) ldi r24, 1 std Z+UART0_TXON_OFFSET, r24 std Z+UART0_RXON_OFFSET, r24 #endif ldi r24, UBRRH_VALUE STORE_IO UBRR0H, r24 ldi r24, UBRRL_VALUE STORE_IO UBRR0L, r24 #if USE_2X SET_BIT_IO UCSR0A, U2X0, r24 #else CLEAR_BIT_IO UCSR0A, U2X0, r24 /* UCSR0A */ #endif ldi r24, (UART0_PARATY<<4)|(UART0_STOPBITS<<3)|((UART0_DATABITS&3)<<1) STORE_IO UCSR0C, r24 ldi r24, _BV(RXCIE0) | _BV(UDRIE0) | _BV(RXEN0) | _BV(TXEN0) STORE_IO UCSR0B, r24 sei ret /******************************************************************************/ /* * ISR(USART0_UDRE_vect){ * uint16_t x; * x = circularbytebuffer_get_fifo(&(uart0_ctx.txb)); * if(x==0xffff){ * / * the transmit buffer is empty, disable interrupt * / * UCSR0B &= (uint8_t)~_BV(UDRIE0); * return; * } * #if UART0_SWFLOWCTRL * while(!uart0_ctx.txon) * ; * #endif * UDR0 = x; * } */ .global USART0_UDRE_vect USART0_UDRE_vect: push_range 21, 26 push_range 30, 31 in r21, _SFR_IO_ADDR(SREG) ldi r24, lo8(uart0_ctx+UART0_CBB_TX_OFFSET) ldi r25, hi8(uart0_ctx+UART0_CBB_TX_OFFSET) rcall circularbytebuffer_get_fifo cpi r25, 0xff brne 20f CLEAR_BIT_IO UCSR0B, UDRIE0, r24 rjmp 99f 20: #if UART0_SWFLOWCTRL ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET) ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET) 30: ld r22, Z tst r22 breq 30b #endif STORE_IO UDR0, r24 99: out _SFR_IO_ADDR(SREG), r21 pop_range 30, 31 pop_range 21, 26 reti /******************************************************************************/ /* * void uart0_putc (uint16_t c){ * #if UART0_SWFLOWCTRL * while(!uart0_ctx.txon) * ; * #endif * while(circularbytebuffer_cnt(&(uart0_ctx.txb))==UART0_TXBUFFER_SIZE) * ; * cli(); * circularbytebuffer_append((uint8_t)c, &(uart0_ctx.txb)); * sei(); * UCSR0B |= (uint8_t)_BV(UDRIE0); * } * * param c: r24:r25 */ .global uart0_putc uart0_putc: mov r18, r24 #if UART0_SWFLOWCTRL ldi r30, lo8(uart0_ctx+UART0_TXON_OFFSET) ldi r31, hi8(uart0_ctx+UART0_TXON_OFFSET) 10: ld r22, Z tst r22 breq 10b #endif ldi r26, lo8(uart0_ctx+UART0_CBB_TX_OFFSET) ldi r27, hi8(uart0_ctx+UART0_CBB_TX_OFFSET) 20: movw r24, r26 rcall circularbytebuffer_cnt cpi r24, UART0_TXBUFFER_SIZE breq 20b movw r22, r26 mov r24, r18 clr r25 cli rcall circularbytebuffer_append sei SET_BIT_IO UCSR0B, UDRIE0, r24 ret /******************************************************************************/ /* * ISR(USART0_RX_vect){ * uint16_t c; * c = UDR0; * #if UART0_SWFLOWCTRL * if(c==XON_VALUE){ * uart0_ctx.txon = 1; * return; * } * if(c==XOFF_VALUE){ * uart0_ctx.txon = 0; * return; * } * #endif * #if UART0_HOOK * if((!uart0_ctx.hook_running) && uart0_ctx.hook){ * uart0_ctx.hook_running=1; * sei(); * do{ * uart0_ctx.hook(c); * }while((c=circularbytebuffer_get_fifo(&(uart0_ctx.rxb)))!=0xffff); * uart0_ctx.hook_running=0; * return; * } * #endif * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))==UART0_RXBUFFER_SIZE) * return; * circularbytebuffer_append(c, &(uart0_ctx.rxb)); * #if UART0_SWFLOWCTRL * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))>UART0_THRESH_HIGH && uart0_ctx.rxon){ * uart0_ctx.rxon = 0; * circularbytebuffer_push(XOFF_VALUE, &(uart0_ctx.txb)); * UCSR0B |= (uint8_t)_BV(UDRIE0); * } * if(circularbytebuffer_cnt(&(uart0_ctx.rxb))