4 * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
5 * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
6 * This file is part of DevLib - See devlib/README for information.
11 * \author Bernardo Innocenti <bernie@develer.com>
13 * \brief AVR UART and SPI I/O driver
18 * Revision 1.5 2004/06/27 15:25:40 aleph
19 * Add missing callbacks for SPI;
20 * Change UNUSED() macro to new version with two args;
21 * Use TX line filling only on the correct KBUS serial port;
22 * Fix nasty IRQ disabling bug in recv complete hander for port 1.
24 * Revision 1.4 2004/06/03 11:27:09 bernie
25 * Add dual-license information.
27 * Revision 1.3 2004/06/02 21:35:24 aleph
28 * Serial enhancements: interruptible receive handler and 8 bit serial status for AVR; remove volatile attribute to FIFOBuffer, useless for new fifobuf routens
30 * Revision 1.2 2004/05/23 18:21:53 bernie
31 * Trim CVS logs and cleanup header info.
40 #include <mware/fifobuf.h>
42 extern struct Serial ser_handles[SER_CNT];
46 struct SerialHardware hw;
47 struct Serial* serial;
51 /* Hardware handshake */
54 #define IS_CTS_ON true
55 #define IS_CTS_OFF false
58 /* SPI port and pin configuration */
59 #define SPI_PORT PORTB
61 #define SPI_SCK_BIT PORTB1
62 #define SPI_MOSI_BIT PORTB2
63 #define SPI_MISO_BIT PORTB3
66 #ifdef __AVR_ATmega103__
67 /* Macro for ATmega103 compatibility */
79 /* Transmission fill byte */
80 #define SER_FILL_BYTE 0xAA
83 static void uart0_enabletxirq(UNUSED(struct SerialHardware *, ctx))
85 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
86 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
88 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
92 static void uart0_init(struct SerialHardware *_hw, struct Serial *ser)
94 struct AvrSerial *hw = (struct AvrSerial *)_hw;
97 /* Set TX port as input with pull-up enabled to avoid
98 * noise on the remote RX when TX is disabled */
100 DISABLE_IRQSAVE(flags);
103 ENABLE_IRQRESTORE(flags);
105 /* TODO: explain why TX is disabled whenever possible */
106 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
108 * Set multiprocessor mode and 9 bit data frame.
109 * The receiver keep MPCM bit always on. When useful data
110 * is trasmitted the ninth bit is set. Receiver consider the
111 * frame as address info and receive it.
112 * When useless fill bytes are sent the ninth bit is cleared
113 * and the receiver will ignore them, avoiding useless triggering
117 UCSR0B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
119 UCSR0B = BV(RXCIE) | BV(RXEN);
125 static void uart0_cleanup(UNUSED(struct SerialHardware *, ctx))
130 static void uart0_setbaudrate(UNUSED(struct SerialHardware *, ctx), unsigned long rate)
132 // Compute baud-rate period
133 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
135 #ifndef __AVR_ATmega103__
136 UBRR0H = (period) >> 8;
142 #ifndef __AVR_ATmega103__
144 static void uart1_enabletxirq(UNUSED(struct SerialHardware *, ctx))
146 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
147 UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
149 UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
153 static void uart1_init(struct SerialHardware *_hw, struct Serial *ser)
155 struct AvrSerial *hw = (struct AvrSerial *)_hw;
158 /* Set TX port as input with pull-up enabled to avoid
159 * noise on the remote RX when TX is disabled */
161 DISABLE_IRQSAVE(flags);
164 ENABLE_IRQRESTORE(flags);
166 /* TODO: explain why TX is disabled whenever possible */
167 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
168 /*! * See comment in uart0_init() */
170 UCSR1B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
172 UCSR1B = BV(RXCIE) | BV(RXEN);
178 static void uart1_cleanup(UNUSED(struct SerialHardware *, ctx))
183 static void uart1_setbaudrate(UNUSED(struct SerialHardware *, ctx), unsigned long rate)
185 // Compute baud-rate period
186 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
188 UBRR1H = (period) >> 8;
192 static void uart0_setparity(UNUSED(struct SerialHardware *, ctx), int parity)
194 UCSR0C |= (parity) << UPM0;
197 static void uart1_setparity(UNUSED(struct SerialHardware *, ctx), int parity)
199 UCSR1C |= (parity) << UPM0;
202 #endif /* !__AVR_ATmega103__ */
205 static void spi_init(struct SerialHardware *_hw, struct Serial *ser)
207 struct AvrSerial *hw = (struct AvrSerial *)_hw;
210 /* MOSI and SCK out, MISO in */
211 SPI_DDR |= BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT);
212 SPI_DDR &= ~BV(SPI_MISO_BIT);
213 /* Enable SPI, IRQ on, Master, CPU_CLOCK/16 */
214 SPCR = BV(SPE) | BV(SPIE) | BV(MSTR) | BV(SPR0);
217 static void spi_cleanup(UNUSED(struct SerialHardware *, ctx))
220 /* Set all pins as inputs */
221 SPI_DDR &= ~(BV(SPI_MISO_BIT) | BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT));
224 static void spi_setbaudrate(UNUSED(struct SerialHardware *, ctx), UNUSED(unsigned long, rate))
229 static void spi_setparity(UNUSED(struct SerialHardware *, ctx), UNUSED(int, parity))
236 #if defined(CONFIG_SER_HW_HANDSHAKE)
238 //! This interrupt is triggered when the CTS line goes high
241 // Re-enable UDR empty interrupt and TX, then disable CTS interrupt
242 UCR = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
243 cbi(EIMSK, EIMSKB_CTS);
246 #endif // CONFIG_SER_HW_HANDSHAKE
250 * Serial 0 TX interrupt handler
252 #ifdef __AVR_ATmega103__
253 SIGNAL(SIG_UART_DATA)
255 SIGNAL(SIG_UART0_DATA)
258 if (fifo_isempty(&ser_handles[SER_UART0].txfifo))
260 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
262 * To avoid audio interference: always transmit useless char.
263 * Send the byte with the ninth bit cleared, the receiver in MCPM mode
267 UDR0 = SER_FILL_BYTE;
269 /* Disable UDR empty interrupt and transmitter */
270 UCR = BV(RXCIE) | BV(RXEN);
273 #if defined(CONFIG_SER_HWHANDSHAKE)
276 // disable rx interrupt and tx, enable CTS interrupt
277 UCR = BV(RXCIE) | BV(RXEN);
278 sbi(EIFR, EIMSKB_CTS);
279 sbi(EIMSK, EIMSKB_CTS);
281 #endif // CONFIG_SER_HWHANDSHAKE
284 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
285 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
288 UDR = fifo_pop(&ser_handles[SER_UART0].txfifo);
293 * Serial 1 TX interrupt handler
295 #ifndef __AVR_ATmega103__
296 SIGNAL(SIG_UART1_DATA)
298 if (fifo_isempty(&ser_handles[SER_UART1].txfifo))
300 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
302 * To avoid audio interference: always transmit useless char.
303 * Send the byte with the ninth bit cleared, the receiver in MCPM mode
307 UDR1 = SER_FILL_BYTE;
309 /* Disable UDR empty interrupt and transmitter */
310 UCSR1B = BV(RXCIE) | BV(RXEN);
313 #if defined(CONFIG_SER_HWHANDSHAKE)
316 // disable rx interrupt and tx, enable CTS interrupt
317 UCSR1B = BV(RXCIE) | BV(RXEN);
318 sbi(EIFR, EIMSKB_CTS);
319 sbi(EIMSK, EIMSKB_CTS);
321 #endif // CONFIG_SER_HWHANDSHAKE
324 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
325 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
328 UDR1 = fifo_pop(&ser_handles[SER_UART1].txfifo);
331 #endif /* !__AVR_ATmega103__ */
335 * Serial 0 RX complete interrupt handler.
337 * This handler is interruptible.
338 * Interrupt are reenabled as soon as recv complete interrupt is
339 * disabled. Using INTERRUPT() is troublesome when the serial
340 * is heavily loaded, because and interrupt could be retriggered
341 * when executing the handler prologue before RXCIE is disabled.
343 #ifdef __AVR_ATmega103__
344 SIGNAL(SIG_UART_RECV)
346 SIGNAL(SIG_UART0_RECV)
349 /* Disable Recv complete IRQ */
353 /* Should be read before UDR */
354 ser_handles[SER_UART0].status |= USR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
356 /* To clear the RXC flag we must _always_ read the UDR even when we're
357 * not going to accept the incoming data, otherwise a new interrupt
358 * will occur once the handler terminates.
362 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
363 ser_handles[SER_UART0].status |= SERRF_RXFIFOOVERRUN;
366 fifo_push(&ser_handles[SER_UART0].rxfifo, c);
367 #if defined(CONFIG_SER_HW_HANDSHAKE)
368 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
372 /* Reenable receive complete int */
377 * Serial 1 RX complete interrupt handler.
379 * This handler is interruptible.
380 * Interrupt are reenabled as soon as recv complete interrupt is
381 * disabled. Using INTERRUPT() is troublesome when the serial
382 * is heavily loaded, because and interrupt could be retriggered
383 * when executing the handler prologue before RXCIE is disabled.
385 #ifndef __AVR_ATmega103__
386 SIGNAL(SIG_UART1_RECV)
388 /* Disable Recv complete IRQ */
389 UCSR1B &= ~BV(RXCIE);
392 /* Should be read before UDR */
393 ser_handles[SER_UART1].status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
395 /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
396 * not going to accept the incoming data
400 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
401 ser_handles[SER_UART1].status |= SERRF_RXFIFOOVERRUN;
404 fifo_push(&ser_handles[SER_UART1].rxfifo, c);
405 #if defined(CONFIG_SER_HW_HANDSHAKE)
406 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
410 /* Reenable receive complete int */
413 #endif /* !__AVR_ATmega103__ */
417 * SPI Flag: true if we are transmitting/receiving with the SPI.
419 * This kludge is necessary because the SPI sends and receives bytes
420 * at the same time and the SPI IRQ is unique for send/receive.
421 * The only way to start transmission is to write data in SPDR (this
422 * is done by ser_spi_starttx()). We do this *only* if a transfer is
423 * not already started.
425 static volatile bool spi_sending = false;
427 static void spi_starttx(UNUSED(struct SerialHardware *, ctx))
431 DISABLE_IRQSAVE(flags);
433 /* Send data only if the SPI is not already transmitting */
434 if (!spi_sending && !fifo_isempty(&ser_handles[SER_SPI].txfifo))
436 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
440 ENABLE_IRQRESTORE(flags);
444 * SPI interrupt handler
448 /* Read incoming byte. */
449 if (!fifo_isfull(&ser_handles[SER_SPI].rxfifo))
450 fifo_push(&ser_handles[SER_SPI].rxfifo, SPDR);
454 ser_handles[SER_SPI].status |= SERRF_RXFIFOOVERRUN;
458 if (!fifo_isempty(&ser_handles[SER_SPI].txfifo))
459 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
467 #pragma vector = UART_TXC_vect
468 __interrupt void UART_TXC_interrupt(void)
472 UCSRB = RXCIE | RXEN | TXEN; //Abilito l'Interrupt in ricezione e RX e TX
477 static const struct SerialHardwareVT UART0_VT =
480 .cleanup = uart0_cleanup,
481 .setbaudrate = uart0_setbaudrate,
482 .setparity = uart0_setparity,
483 .enabletxirq = uart0_enabletxirq,
486 static const struct SerialHardwareVT UART1_VT =
489 .cleanup = uart1_cleanup,
490 .setbaudrate = uart1_setbaudrate,
491 .setparity = uart1_setparity,
492 .enabletxirq = uart1_enabletxirq,
495 static const struct SerialHardwareVT SPI_VT =
498 .cleanup = spi_cleanup,
499 .setbaudrate = spi_setbaudrate,
500 .setparity = spi_setparity,
501 .enabletxirq = spi_starttx,
504 static struct AvrSerial UARTDescs[SER_CNT] =
507 .hw = { .table = &UART0_VT },
511 .hw = { .table = &UART1_VT },
515 .hw = { .table = &SPI_VT },
519 struct SerialHardware* ser_hw_getdesc(int unit)
521 ASSERT(unit < SER_CNT);
522 return &UARTDescs[unit].hw;