/*#*
*#* $Log$
- *#* Revision 1.11 2004/08/25 14:12:08 rasky
- *#* Aggiornato il comment block dei log RCS
+ *#* Revision 1.15 2004/09/14 21:05:36 bernie
+ *#* Use debug.h instead of kdebug.h; Use new AVR pin names; Spelling fixes.
+ *#*
+ *#* Revision 1.14 2004/09/06 21:50:00 bernie
+ *#* Spelling fixes.
+ *#*
+ *#* Revision 1.13 2004/09/06 21:40:50 bernie
+ *#* Move buffer handling in chip-specific driver.
+ *#*
+ *#* Revision 1.12 2004/08/29 22:06:10 bernie
+ *#* Fix a bug in the (unused) RTS/CTS code; Clarify documentation.
*#*
*#* Revision 1.10 2004/08/10 06:30:41 bernie
*#* Major redesign of serial bus policy handling.
#include "ser.h"
#include "ser_p.h"
-#include "kdebug.h"
#include "config.h"
-#include "hw.h"
+#include "hw.h" /* Required for bus macros overrides */
+
+#include <debug.h>
#include <drv/timer.h>
#include <mware/fifobuf.h>
/*!
- * \def CONFIG_SER_STROBE
- *
- * This is a debug facility that can be used to
- * monitor SER interrupt activity on an external pin.
- *
- * To use strobes, redefine the macros SER_STROBE_ON,
- * SER_STROBE_OFF and SER_STROBE_INIT and set
- * CONFIG_SER_STROBE to 1.
- */
-#ifndef CONFIG_SER_STROBE
- #define SER_STROBE_ON do {/*nop*/} while(0)
- #define SER_STROBE_OFF do {/*nop*/} while(0)
- #define SER_STROBE_INIT do {/*nop*/} while(0)
-#endif
-
-
-/*!
- * \name Overridable serial hooks
+ * \name Overridable serial bus hooks
*
* These can be redefined in hw.h to implement
* special bus policies such as half-duplex, 485, etc.
/* SPI port and pin configuration */
#define SPI_PORT PORTB
#define SPI_DDR DDRB
-#define SPI_SCK_BIT PORTB1
-#define SPI_MOSI_BIT PORTB2
-#define SPI_MISO_BIT PORTB3
+#define SPI_SCK_BIT PB1
+#define SPI_MOSI_BIT PB2
+#define SPI_MISO_BIT PB3
/* USART registers definitions */
#if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
#endif
+/*!
+ * \def CONFIG_SER_STROBE
+ *
+ * This is a debug facility that can be used to
+ * monitor SER interrupt activity on an external pin.
+ *
+ * To use strobes, redefine the macros SER_STROBE_ON,
+ * SER_STROBE_OFF and SER_STROBE_INIT and set
+ * CONFIG_SER_STROBE to 1.
+ */
+#if !defined(CONFIG_SER_STROBE) || !CONFIG_SER_STROBE
+ #define SER_STROBE_ON do {/*nop*/} while(0)
+ #define SER_STROBE_OFF do {/*nop*/} while(0)
+ #define SER_STROBE_INIT do {/*nop*/} while(0)
+#endif
+
+
/* From the high-level serial driver */
extern struct Serial ser_handles[SER_CNT];
+/* TX and RX buffers */
+static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
+static unsigned char uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
+#if AVR_HAS_UART1
+ static unsigned char uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
+ static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
+#endif
+static unsigned char spi_txbuffer[CONFIG_SPI_TXBUFSIZE];
+static unsigned char spi_rxbuffer[CONFIG_SPI_RXBUFSIZE];
+
+
/*!
* Internal hardware state structure
*
- * \a sending var is true if we are transmitting.
- * SPI note: this flag is necessary because the SPI sends and receives bytes
- * at the same time and the SPI IRQ is unique for send/receive.
- * The only way to start transmission is to write data in SPDR (this
- * is done by spi_starttx()). We do this *only* if a transfer is
- * not already started.
+ * The \a sending variable is true while the transmission
+ * interrupt is retriggering itself.
*
* For the USARTs the \a sending flag is useful for taking specific
* actions before sending a burst of data, at the start of a trasmission
* but not before every char sent.
+ *
+ * For the SPI, this flag is necessary because the SPI sends and receives
+ * bytes at the same time and the SPI IRQ is unique for send/receive.
+ * The only way to start transmission is to write data in SPDR (this
+ * is done by spi_starttx()). We do this *only* if a transfer is
+ * not already started.
*/
struct AvrSerial
{
volatile bool sending;
};
+
/*
* These are to trick GCC into *not* using
* absolute addressing mode when accessing
#endif
UBRR0L = (period);
- DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
+ //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
}
static void uart0_setparity(UNUSED(struct SerialHardware *, _hw), int parity)
UBRR1H = (period) >> 8;
UBRR1L = (period);
- DB(kprintf("uart1_setbaudrate(rate=%ld): period=%d\n", rate, period);)
+ //DB(kprintf("uart1_setbaudrate(rate=%ld): period=%d\n", rate, period);)
}
static void uart1_setparity(UNUSED(struct SerialHardware *, _hw), int parity)
static struct AvrSerial UARTDescs[SER_CNT] =
{
{
- .hw = { .table = &UART0_VT },
+ .hw = {
+ .table = &UART0_VT,
+ .txbuffer = uart0_txbuffer,
+ .rxbuffer = uart0_rxbuffer,
+ .txbuffer_size = CONFIG_UART0_TXBUFSIZE,
+ .rxbuffer_size = CONFIG_UART0_RXBUFSIZE,
+ },
.sending = false,
},
#if AVR_HAS_UART1
{
- .hw = { .table = &UART1_VT },
+ .hw = {
+ .table = &UART1_VT,
+ .txbuffer = uart1_txbuffer,
+ .rxbuffer = uart1_rxbuffer,
+ .txbuffer_size = CONFIG_UART1_TXBUFSIZE,
+ .rxbuffer_size = CONFIG_UART1_RXBUFSIZE,
+ },
.sending = false,
},
#endif
{
- .hw = { .table = &SPI_VT },
+ .hw = {
+ .table = &SPI_VT,
+ .txbuffer = spi_txbuffer,
+ .rxbuffer = spi_rxbuffer,
+ .txbuffer_size = CONFIG_SPI_TXBUFSIZE,
+ .rxbuffer_size = CONFIG_SPI_RXBUFSIZE,
+ },
.sending = false,
}
};
{
// Disable rx interrupt and tx, enable CTS interrupt
// UNTESTED
- UCSR0B = BV(RXCIE) | BV(RXEN);
+ UCSR0B = BV(RXCIE) | BV(RXEN) | BV(TXEN);
sbi(EIFR, EIMSKB_CTS);
sbi(EIMSK, EIMSKB_CTS);
}
{
// Disable rx interrupt and tx, enable CTS interrupt
// UNTESTED
- UCSR1B = BV(RXCIE) | BV(RXEN);
+ UCSR1B = BV(RXCIE) | BV(RXEN) | BV(TXEN);
sbi(EIFR, EIMSKB_CTS);
sbi(EIMSK, EIMSKB_CTS);
}
* disabled. Using INTERRUPT() is troublesome when the serial
* is heavily loaded, because an interrupt could be retriggered
* when executing the handler prologue before RXCIE is disabled.
+ *
+ * \note The code that re-enables interrupts is commented out
+ * because in some nasty cases the interrupt is retriggered.
+ * This is probably due to the RXC flag being set before
+ * RXCIE is cleared. Unfortunately the RXC flag is read-only
+ * and can't be cleared by code.
*/
SIGNAL(SIG_UART0_RECV)
{
SER_STROBE_ON;
/* Disable Recv complete IRQ */
- UCSR0B &= ~BV(RXCIE);
- ENABLE_INTS;
+ //UCSR0B &= ~BV(RXCIE);
+ //ENABLE_INTS;
/* Should be read before UDR */
ser_uart0->status |= UCSR0A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
}
/* Reenable receive complete int */
- UCSR0B |= BV(RXCIE);
+ //DISABLE_INTS;
+ //UCSR0B |= BV(RXCIE);
SER_STROBE_OFF;
}
* disabled. Using INTERRUPT() is troublesome when the serial
* is heavily loaded, because an interrupt could be retriggered
* when executing the handler prologue before RXCIE is disabled.
+ *
+ * \see SIGNAL(SIG_UART0_RECV)
*/
SIGNAL(SIG_UART1_RECV)
{
SER_STROBE_ON;
/* Disable Recv complete IRQ */
- UCSR1B &= ~BV(RXCIE);
- ENABLE_INTS;
+ //UCSR1B &= ~BV(RXCIE);
+ //ENABLE_INTS;
/* Should be read before UDR */
ser_uart1->status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
*/
char c = UDR1;
struct FIFOBuffer * const rxfifo = &ser_uart1->rxfifo;
+ //ASSERT_VALID_FIFO(rxfifo);
- if (fifo_isfull(rxfifo))
+ if (UNLIKELY(fifo_isfull(rxfifo)))
ser_uart1->status |= SERRF_RXFIFOOVERRUN;
else
{
RTS_OFF;
#endif
}
- /* Reenable receive complete int */
- UCSR1B |= BV(RXCIE);
+ /* Re-enable receive complete int */
+ //UCSR1B |= BV(RXCIE);
SER_STROBE_OFF;
}