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.4 2004/06/03 11:27:09 bernie
19 * Add dual-license information.
21 * Revision 1.3 2004/06/02 21:35:24 aleph
22 * Serial enhancements: interruptible receive handler and 8 bit serial status for AVR; remove volatile attribute to FIFOBuffer, useless for new fifobuf routens
24 * Revision 1.2 2004/05/23 18:21:53 bernie
25 * Trim CVS logs and cleanup header info.
34 #include <mware/fifobuf.h>
36 extern struct Serial ser_handles[SER_CNT];
40 struct SerialHardware hw;
41 struct Serial* serial;
45 /* Hardware handshake */
48 #define IS_CTS_ON true
49 #define IS_CTS_OFF false
52 /* SPI port and pin configuration */
53 #define SPI_PORT PORTB
55 #define SPI_SCK_BIT PORTB1
56 #define SPI_MOSI_BIT PORTB2
57 #define SPI_MISO_BIT PORTB3
60 #ifdef __AVR_ATmega103__
61 /* Macro for ATmega103 compatibility */
73 /* Transmission fill byte */
74 #define SER_FILL_BYTE 0xAA
77 static void uart0_enabletxirq(UNUSED(struct SerialHardware *ctx))
79 #ifdef CONFIG_SER_TXFILL
80 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
82 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
86 static void uart0_init(struct SerialHardware *_hw, struct Serial *ser)
88 struct AvrSerial *hw = (struct AvrSerial *)_hw;
91 /* Set TX port as input with pull-up enabled to avoid
92 * noise on the remote RX when TX is disabled */
94 DISABLE_IRQSAVE(flags);
97 ENABLE_IRQRESTORE(flags);
99 /* TODO: explain why TX is disabled whenever possible */
100 #ifdef CONFIG_SER_TXFILL
102 * Set multiprocessor mode and 9 bit data frame.
103 * The receiver keep MPCM bit always on. When useful data
104 * is trasmitted the ninth bit is set. Receiver consider the
105 * frame as address info and receive it.
106 * When useless fill bytes are sent the ninth bit is cleared
107 * and the receiver will ignore them, avoiding useless triggering
111 UCSR0B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
113 UCSR0B = BV(RXCIE) | BV(RXEN);
119 static void uart0_cleanup(UNUSED(struct SerialHardware *ctx))
124 static void uart0_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
126 // Compute baud-rate period
127 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
129 #ifndef __AVR_ATmega103__
130 UBRR0H = (period) >> 8;
136 #ifndef __AVR_ATmega103__
138 static void uart1_enabletxirq(UNUSED(struct SerialHardware *ctx))
140 UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
143 static void uart1_init(struct SerialHardware *_hw, struct Serial *ser)
145 struct AvrSerial *hw = (struct AvrSerial *)_hw;
148 /* Set TX port as input with pull-up enabled to avoid
149 * noise on the remote RX when TX is disabled */
151 DISABLE_IRQSAVE(flags);
154 ENABLE_IRQRESTORE(flags);
156 /* TODO: explain why TX is disabled whenever possible */
157 UCSR1B = BV(RXCIE) | BV(RXEN);
162 static void uart1_cleanup(UNUSED(struct SerialHardware *ctx))
167 static void uart1_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
169 // Compute baud-rate period
170 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
172 UBRR1H = (period) >> 8;
176 static void uart0_setparity(UNUSED(struct SerialHardware *ctx), int parity)
178 UCSR0C |= (parity) << UPM0;
181 static void uart1_setparity(UNUSED(struct SerialHardware *ctx), int parity)
183 UCSR1C |= (parity) << UPM0;
186 #endif /* !__AVR_ATmega103__ */
189 static void spi_init(struct SerialHardware *_hw, struct Serial *ser)
191 struct AvrSerial *hw = (struct AvrSerial *)_hw;
194 /* MOSI and SCK out, MISO in */
195 SPI_DDR |= BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT);
196 SPI_DDR &= ~BV(SPI_MISO_BIT);
197 /* Enable SPI, IRQ on, Master, CPU_CLOCK/16 */
198 SPCR = BV(SPE) | BV(SPIE) | BV(MSTR) | BV(SPR0);
201 static void spi_cleanup(UNUSED(struct SerialHardware *ctx))
204 /* Set all pins as inputs */
205 SPI_DDR &= ~(BV(SPI_MISO_BIT) | BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT));
210 #if defined(CONFIG_SER_HW_HANDSHAKE)
212 //! This interrupt is triggered when the CTS line goes high
215 // Re-enable UDR empty interrupt and TX, then disable CTS interrupt
216 UCR = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
217 cbi(EIMSK, EIMSKB_CTS);
220 #endif // CONFIG_SER_HW_HANDSHAKE
224 * Serial 0 TX interrupt handler
226 #ifdef __AVR_ATmega103__
227 SIGNAL(SIG_UART_DATA)
229 SIGNAL(SIG_UART0_DATA)
232 if (fifo_isempty(&ser_handles[SER_UART0].txfifo))
234 #ifdef CONFIG_SER_TXFILL
236 * To avoid audio interference: always transmit useless char.
237 * Send the byte with the ninth bit cleared, the receiver in MCPM mode
241 UDR0 = SER_FILL_BYTE;
243 /* Disable UDR empty interrupt and transmitter */
244 UCR = BV(RXCIE) | BV(RXEN);
247 #if defined(CONFIG_SER_HWHANDSHAKE)
250 // disable rx interrupt and tx, enable CTS interrupt
251 UCR = BV(RXCIE) | BV(RXEN);
252 sbi(EIFR, EIMSKB_CTS);
253 sbi(EIMSK, EIMSKB_CTS);
255 #endif // CONFIG_SER_HWHANDSHAKE
258 #ifdef CONFIG_SER_TXFILL
259 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
262 UDR = fifo_pop(&ser_handles[SER_UART0].txfifo);
267 * Serial 1 TX interrupt handler
269 #ifndef __AVR_ATmega103__
270 SIGNAL(SIG_UART1_DATA)
272 if (fifo_isempty(&ser_handles[SER_UART1].txfifo))
274 /* Disable UDR empty interrupt and transmitter */
275 UCSR1B = BV(RXCIE) | BV(RXEN);
277 #if defined(CONFIG_SER_HWHANDSHAKE)
280 // disable rx interrupt and tx, enable CTS interrupt
281 UCSR1B = BV(RXCIE) | BV(RXEN);
282 sbi(EIFR, EIMSKB_CTS);
283 sbi(EIMSK, EIMSKB_CTS);
285 #endif // CONFIG_SER_HWHANDSHAKE
287 UDR1 = fifo_pop(&ser_handles[SER_UART1].txfifo);
289 #endif /* !__AVR_ATmega103__ */
293 * Serial 0 RX complete interrupt handler.
295 * This handler is interruptible.
296 * Interrupt are reenabled as soon as recv complete interrupt is
297 * disabled. Using INTERRUPT() is troublesome when the serial
298 * is heavily loaded, because and interrupt could be retriggered
299 * when executing the handler prologue before RXCIE is disabled.
301 #ifdef __AVR_ATmega103__
302 SIGNAL(SIG_UART_RECV)
304 SIGNAL(SIG_UART0_RECV)
307 /* Disable Recv complete IRQ */
311 /* Should be read before UDR */
312 ser_handles[SER_UART0].status |= USR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
314 /* To clear the RXC flag we must _always_ read the UDR even when we're
315 * not going to accept the incoming data, otherwise a new interrupt
316 * will occur once the handler terminates.
320 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
321 ser_handles[SER_UART0].status |= SERRF_RXFIFOOVERRUN;
324 fifo_push(&ser_handles[SER_UART0].rxfifo, c);
325 #if defined(CONFIG_SER_HW_HANDSHAKE)
326 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
330 /* Reenable receive complete int */
335 * Serial 1 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 #ifndef __AVR_ATmega103__
344 SIGNAL(SIG_UART1_RECV)
346 /* Disable Recv complete IRQ */
347 UCSR0B &= ~BV(RXCIE);
350 /* Should be read before UDR */
351 ser_handles[SER_UART1].status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
353 /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
354 * not going to accept the incoming data
358 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
359 ser_handles[SER_UART1].status |= SERRF_RXFIFOOVERRUN;
362 fifo_push(&ser_handles[SER_UART1].rxfifo, c);
363 #if defined(CONFIG_SER_HW_HANDSHAKE)
364 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
368 /* Reenable receive complete int */
371 #endif /* !__AVR_ATmega103__ */
375 * SPI Flag: true if we are transmitting/receiving with the SPI.
377 * This kludge is necessary because the SPI sends and receives bytes
378 * at the same time and the SPI IRQ is unique for send/receive.
379 * The only way to start transmission is to write data in SPDR (this
380 * is done by ser_spi_starttx()). We do this *only* if a transfer is
381 * not already started.
383 static volatile bool spi_sending = false;
385 static void spi_starttx(UNUSED(struct SerialHardware *ctx))
389 DISABLE_IRQSAVE(flags);
391 /* Send data only if the SPI is not already transmitting */
392 if (!spi_sending && !fifo_isempty(&ser_handles[SER_SPI].txfifo))
394 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
398 ENABLE_IRQRESTORE(flags);
402 * SPI interrupt handler
406 /* Read incoming byte. */
407 if (!fifo_isfull(&ser_handles[SER_SPI].rxfifo))
408 fifo_push(&ser_handles[SER_SPI].rxfifo, SPDR);
412 ser_handles[SER_SPI].status |= SERRF_RXFIFOOVERRUN;
416 if (!fifo_isempty(&ser_handles[SER_SPI].txfifo))
417 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
425 #pragma vector = UART_TXC_vect
426 __interrupt void UART_TXC_interrupt(void)
430 UCSRB = RXCIE | RXEN | TXEN; //Abilito l'Interrupt in ricezione e RX e TX
435 static const struct SerialHardwareVT UART0_VT =
438 .cleanup = uart0_cleanup,
439 .setbaudrate = uart0_setbaudrate,
440 .setparity = uart0_setparity,
441 .enabletxirq = uart0_enabletxirq,
444 static const struct SerialHardwareVT UART1_VT =
447 .cleanup = uart1_cleanup,
448 .setbaudrate = uart1_setbaudrate,
449 .setparity = uart1_setparity,
450 .enabletxirq = uart1_enabletxirq,
453 static const struct SerialHardwareVT SPI_VT =
456 .cleanup = spi_cleanup,
457 .enabletxirq = spi_starttx,
460 static struct AvrSerial UARTDescs[SER_CNT] =
463 .hw = { .table = &UART0_VT },
467 .hw = { .table = &UART1_VT },
471 .hw = { .table = &SPI_VT },
475 struct SerialHardware* ser_hw_getdesc(int unit)
477 ASSERT(unit < SER_CNT);
478 return &UARTDescs[unit].hw;