/*************************************************************************** * * * 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 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*************************************************************************** * INCLUDES ***************************************************************************/ #include #include #include #include #include "usart.h" /*************************************************************************** * DEFINITIONS ***************************************************************************/ /* check for receive/transmit buffer size */ #if (USART_RBUF_SIZE >= 0xFF | USART_TBUF_SIZE >= 0xFF) #error "USART: buffers too big (max = 256 bytes)" #endif #if (USART_RBUF_SIZE & USART_RMASK) #error "USART: RX buffer size is not power of 2" #endif #if (USART_TBUF_SIZE & USART_TMASK) #error "USART: TX buffer size is not power of 2" #endif /* transmission buffers */ static volatile BYTE rx_buff[USART_RBUF_SIZE]; static volatile BYTE tx_buff[USART_TBUF_SIZE]; /* buffer indexes */ static volatile UINT8 rx_head, rx_tail; static volatile UINT8 tx_head, tx_tail; /* usart status */ static volatile e_usartstatus_t usartstatus; #ifdef USART_USE_TIMER /* timeout counter for read timeout */ volatile UINT16 usart_timeout = 0; #endif /* USART_USE_TIMER */ /* incoming byte interrupt handler */ ISR (USART_INT_RX) { #ifdef USART_USE_STATUS /* set status of received byte */ if (USART_UCSRA & BV(FE)) sbi(usartstatus, RX_STAT_FE); if (USART_UCSRA & BV(DOR)) sbi(usartstatus, RX_STAT_DOR); /* Atmegas have different name of this flag */ #ifdef UPE if (USART_UCSRA & BV(UPE)) sbi(usartstatus, RX_STAT_PE); #else if (USART_UCSRA & BV(PE)) sbi(usartstatus, RX_STAT_PE); #endif /* UPE */ #endif /* USART_USE_STATUS */ /* discard last byte in buffer if buffer overflow occured */ if (usartstatus & RX_OVR) rx_tail = (rx_tail + 1) & USART_RMASK; /* insert byte to ring buffer */ rx_buff[rx_head] = USART_UDR; rx_head = (rx_head + 1) & USART_RMASK; /* indicate buffer overflow */ if (rx_head == rx_tail) sbi(usartstatus, RX_STAT_OVR); } /* outgoing byte interrupt handler */ ISR (USART_INT_UDRE) { if ((tx_tail != tx_head) || (usartstatus & TX_FULL)) { USART_UDR = tx_buff[tx_tail]; tx_tail = (tx_tail + 1) & USART_TMASK; cbi(usartstatus, TX_STAT_FULL); } else cbi(USART_UCSRB, USART_UDRIE); } /*************************************************************************** * FUNCTIONS ***************************************************************************/ /* ----------------------------------------------------------------------- */ BOOL usartReceiveBufferOverflow() { return (TO_BOOL((usartstatus & RX_OVR))); } #ifndef USART_USE_TIMER /* ----------------------------------------------------------------------- */ BOOL usartRead(BYTE *str, const UINT16 count) { #ifdef USART_USE_STATUS static BOOL b_byte_read_ok; #endif /* USART_USE_STATUS */ for (UINT16 i = 0; i < count; ++i) { /* if any timeout is present, wait for incomming byte */ while (!usartUnreadBytes()); #ifdef USART_USE_STATUS *str = usartReadByte(&b_byte_read_ok); #endif /* USART_USE_STATUS */ ++str; #ifdef USART_USE_STATUS if (!b_byte_read_ok) return (false); #endif /* USART_USE_STATUS */ } return (true); } #else /* ----------------------------------------------------------------------- */ BOOL usartRead(BYTE *str, const UINT16 count, const UINT16 timeout) { #ifdef USART_USE_STATUS static BOOL b_byte_read_ok; #endif /* USART_USE_STATUS */ for (UINT16 i = 0; i < count; ++i) { usart_timeout = 0; /* if any timeout is present, wait for incomming byte */ while (!usartUnreadBytes() && timeout) { if (usart_timeout == timeout) return (false); } #ifdef USART_USE_STATUS *str = usartReadByte(&b_byte_read_ok); #endif /* USART_USE_STATUS */ ++str; #ifdef USART_USE_STATUS if (!b_byte_read_ok) return (false); #endif /* USART_USE_STATUS */ } return (true); } #endif /* USART_USE_TIMER */ /* ----------------------------------------------------------------------- */ #ifdef USART_USE_STATUS BYTE usartReadByte(BOOL *ok) #else BYTE usartReadByte() #endif /* USART_USE_STATUS */ { static BYTE b; if (usartUnreadBytes()) { b = rx_buff[rx_tail]; rx_tail = (rx_tail + 1) & USART_RMASK; cbi(usartstatus, RX_STAT_OVR); #ifdef USART_USE_STATUS if (ok) { if (usartstatus & (RX_FE | RX_PE | RX_DOR)) { *ok = false; /* clear error flags */ cbi(usartstatus, RX_STAT_FE); cbi(usartstatus, RX_STAT_PE); cbi(usartstatus, RX_STAT_DOR); } else *ok = true; } return (b); } else { if (ok) *ok = false; return (0); } #else } return (b); #endif /* USART_USE_STATUS */ } /* ----------------------------------------------------------------------- */ UINT8 usartUnreadBytes() { if (usartstatus & RX_OVR) return (USART_RBUF_SIZE); if (rx_head > rx_tail) return (rx_head - rx_tail); if (rx_head < rx_tail) return (USART_RBUF_SIZE - (rx_tail - rx_head)); return (0); } /* ----------------------------------------------------------------------- */ void initUsart(const UINT16 baudrate, const BOOL double_speed, const BOOL two_stop_bits, const UINT8 parity) { UINT16 usart_const; UINT8 ucsrc; float f_usart_const; rx_head = 0; rx_tail = 0; tx_head = 0; tx_tail = 0; usartstatus = 0; /* set speed */ if (double_speed) { /* compute USART clock and round to nearest value */ f_usart_const = (float)(USART_F_CPU) / (float)(8); f_usart_const /= (float)(baudrate); f_usart_const -= 1; usart_const = (UINT16)(lrint(f_usart_const)); USART_UCSRA = BV(UDRE) | BV(U2X); } else { /* compute USART clock and round to nearest value */ f_usart_const = (float)(USART_F_CPU) / (float)(16); f_usart_const /= (float)(baudrate); f_usart_const -= 1; usart_const = (UINT16)(lrint(f_usart_const)); USART_UCSRA = BV(UDRE); } USART_UBRRH = (UINT8)(usart_const >> 8); USART_UBRRL = (UINT8)usart_const; /* set rx and tx enabled, allow interrupt on new byte received */ USART_UCSRB = BV(RXEN) | BV(TXEN) | BV(RXCIE); /* set frame format: asynchronous, 8bit data */ ucsrc = BV(UCSZ0) | BV(UCSZ1); /* set frame format: 2 stop bits */ if (two_stop_bits) ucsrc |= BV(USBS); /* set frame format: parity */ if (parity == USART_PARITY_EVEN) ucsrc |= BV(UPM1); else if (parity == USART_PARITY_ODD) ucsrc |= BV(UPM0) | BV(UPM1); /* URSEL for access to UCSRC insetad of UBRRH */ #ifdef URSEL ucsrc |= BV(URSEL); #endif /* URSEL */ USART_UCSRC = ucsrc; } /* ----------------------------------------------------------------------- */ void usartFlush() { rx_tail = rx_head; cbi(usartstatus, RX_STAT_OVR); } /* ----------------------------------------------------------------------- */ void usartSend(BYTE *str, const UINT16 length) { static UINT16 real_length; /* compute max length of data to send */ if (!length) real_length = USART_SEND_MAX_LENGTH; else real_length = (length > USART_SEND_MAX_LENGTH)?(USART_SEND_MAX_LENGTH):(length); /* start sending data */ for (UINT16 i = 0; i < real_length; ++i) { usartSendByte(*str); ++str; } } /* ----------------------------------------------------------------------- */ void usartSendByte(const BYTE b) { /* wait for free space in buffer */ while (usartstatus & TX_FULL); /* insert byte to transmit buffer */ tx_buff[tx_head] = b; tx_head = (tx_head + 1) & USART_TMASK; if (tx_head == tx_tail) sbi(usartstatus, TX_STAT_FULL); sbi(USART_UCSRB, USART_UDRIE); } /* ----------------------------------------------------------------------- */ void usartSendString(BYTE *str, const UINT16 length) { static UINT16 real_length; /* compute max length of data to send */ if (!length) real_length = USART_SEND_MAX_LENGTH; else real_length = (length > USART_SEND_MAX_LENGTH)?(USART_SEND_MAX_LENGTH):(length); /* start sending data */ for (UINT16 i = 0; (i < real_length) && *str; ++i) { usartSendByte(*str); ++str; } } /* ----------------------------------------------------------------------- */ void usartSendString_P(const BYTE *str) { BYTE c; while ((c = pgm_read_byte(str))) { usartSendByte(c); ++str; } } /* END */