4 * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
5 * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
11 * \author Bernardo Innocenti <bernie@develer.com>
13 * \brief AVR UART and SPI I/O driver
18 * Revision 1.3 2004/06/02 21:35:24 aleph
19 * Serial enhancements: interruptible receive handler and 8 bit serial status for AVR; remove volatile attribute to FIFOBuffer, useless for new fifobuf routens
21 * Revision 1.2 2004/05/23 18:21:53 bernie
22 * Trim CVS logs and cleanup header info.
31 #include <mware/fifobuf.h>
33 extern struct Serial ser_handles[SER_CNT];
37 struct SerialHardware hw;
38 struct Serial* serial;
42 /* Hardware handshake */
45 #define IS_CTS_ON true
46 #define IS_CTS_OFF false
49 /* SPI port and pin configuration */
50 #define SPI_PORT PORTB
52 #define SPI_SCK_BIT PORTB1
53 #define SPI_MOSI_BIT PORTB2
54 #define SPI_MISO_BIT PORTB3
57 #ifdef __AVR_ATmega103__
58 /* Macro for ATmega103 compatibility */
70 /* Transmission fill byte */
71 #define SER_FILL_BYTE 0xAA
74 static void uart0_enabletxirq(UNUSED(struct SerialHardware *ctx))
76 #ifdef CONFIG_SER_TXFILL
77 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
79 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
83 static void uart0_init(struct SerialHardware *_hw, struct Serial *ser)
85 struct AvrSerial *hw = (struct AvrSerial *)_hw;
88 /* Set TX port as input with pull-up enabled to avoid
89 * noise on the remote RX when TX is disabled */
91 DISABLE_IRQSAVE(flags);
94 ENABLE_IRQRESTORE(flags);
96 /* TODO: explain why TX is disabled whenever possible */
97 #ifdef CONFIG_SER_TXFILL
99 * Set multiprocessor mode and 9 bit data frame.
100 * The receiver keep MPCM bit always on. When useful data
101 * is trasmitted the ninth bit is set. Receiver consider the
102 * frame as address info and receive it.
103 * When useless fill bytes are sent the ninth bit is cleared
104 * and the receiver will ignore them, avoiding useless triggering
108 UCSR0B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
110 UCSR0B = BV(RXCIE) | BV(RXEN);
116 static void uart0_cleanup(UNUSED(struct SerialHardware *ctx))
121 static void uart0_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
123 // Compute baud-rate period
124 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
126 #ifndef __AVR_ATmega103__
127 UBRR0H = (period) >> 8;
133 #ifndef __AVR_ATmega103__
135 static void uart1_enabletxirq(UNUSED(struct SerialHardware *ctx))
137 UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
140 static void uart1_init(struct SerialHardware *_hw, struct Serial *ser)
142 struct AvrSerial *hw = (struct AvrSerial *)_hw;
145 /* Set TX port as input with pull-up enabled to avoid
146 * noise on the remote RX when TX is disabled */
148 DISABLE_IRQSAVE(flags);
151 ENABLE_IRQRESTORE(flags);
153 /* TODO: explain why TX is disabled whenever possible */
154 UCSR1B = BV(RXCIE) | BV(RXEN);
159 static void uart1_cleanup(UNUSED(struct SerialHardware *ctx))
164 static void uart1_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
166 // Compute baud-rate period
167 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
169 UBRR1H = (period) >> 8;
173 static void uart0_setparity(UNUSED(struct SerialHardware *ctx), int parity)
175 UCSR0C |= (parity) << UPM0;
178 static void uart1_setparity(UNUSED(struct SerialHardware *ctx), int parity)
180 UCSR1C |= (parity) << UPM0;
183 #endif /* !__AVR_ATmega103__ */
186 static void spi_init(struct SerialHardware *_hw, struct Serial *ser)
188 struct AvrSerial *hw = (struct AvrSerial *)_hw;
191 /* MOSI and SCK out, MISO in */
192 SPI_DDR |= BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT);
193 SPI_DDR &= ~BV(SPI_MISO_BIT);
194 /* Enable SPI, IRQ on, Master, CPU_CLOCK/16 */
195 SPCR = BV(SPE) | BV(SPIE) | BV(MSTR) | BV(SPR0);
198 static void spi_cleanup(UNUSED(struct SerialHardware *ctx))
201 /* Set all pins as inputs */
202 SPI_DDR &= ~(BV(SPI_MISO_BIT) | BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT));
207 #if defined(CONFIG_SER_HW_HANDSHAKE)
209 //! This interrupt is triggered when the CTS line goes high
212 // Re-enable UDR empty interrupt and TX, then disable CTS interrupt
213 UCR = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
214 cbi(EIMSK, EIMSKB_CTS);
217 #endif // CONFIG_SER_HW_HANDSHAKE
221 * Serial 0 TX interrupt handler
223 #ifdef __AVR_ATmega103__
224 SIGNAL(SIG_UART_DATA)
226 SIGNAL(SIG_UART0_DATA)
229 if (fifo_isempty(&ser_handles[SER_UART0].txfifo))
231 #ifdef CONFIG_SER_TXFILL
233 * To avoid audio interference: always transmit useless char.
234 * Send the byte with the ninth bit cleared, the receiver in MCPM mode
238 UDR0 = SER_FILL_BYTE;
240 /* Disable UDR empty interrupt and transmitter */
241 UCR = BV(RXCIE) | BV(RXEN);
244 #if defined(CONFIG_SER_HWHANDSHAKE)
247 // disable rx interrupt and tx, enable CTS interrupt
248 UCR = BV(RXCIE) | BV(RXEN);
249 sbi(EIFR, EIMSKB_CTS);
250 sbi(EIMSK, EIMSKB_CTS);
252 #endif // CONFIG_SER_HWHANDSHAKE
255 #ifdef CONFIG_SER_TXFILL
256 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
259 UDR = fifo_pop(&ser_handles[SER_UART0].txfifo);
264 * Serial 1 TX interrupt handler
266 #ifndef __AVR_ATmega103__
267 SIGNAL(SIG_UART1_DATA)
269 if (fifo_isempty(&ser_handles[SER_UART1].txfifo))
271 /* Disable UDR empty interrupt and transmitter */
272 UCSR1B = BV(RXCIE) | BV(RXEN);
274 #if defined(CONFIG_SER_HWHANDSHAKE)
277 // disable rx interrupt and tx, enable CTS interrupt
278 UCSR1B = BV(RXCIE) | BV(RXEN);
279 sbi(EIFR, EIMSKB_CTS);
280 sbi(EIMSK, EIMSKB_CTS);
282 #endif // CONFIG_SER_HWHANDSHAKE
284 UDR1 = fifo_pop(&ser_handles[SER_UART1].txfifo);
286 #endif /* !__AVR_ATmega103__ */
290 * Serial 0 RX complete interrupt handler.
292 * This handler is interruptible.
293 * Interrupt are reenabled as soon as recv complete interrupt is
294 * disabled. Using INTERRUPT() is troublesome when the serial
295 * is heavily loaded, because and interrupt could be retriggered
296 * when executing the handler prologue before RXCIE is disabled.
298 #ifdef __AVR_ATmega103__
299 SIGNAL(SIG_UART_RECV)
301 SIGNAL(SIG_UART0_RECV)
304 /* Disable Recv complete IRQ */
308 /* Should be read before UDR */
309 ser_handles[SER_UART0].status |= USR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
311 /* To clear the RXC flag we must _always_ read the UDR even when we're
312 * not going to accept the incoming data, otherwise a new interrupt
313 * will occur once the handler terminates.
317 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
318 ser_handles[SER_UART0].status |= SERRF_RXFIFOOVERRUN;
321 fifo_push(&ser_handles[SER_UART0].rxfifo, c);
322 #if defined(CONFIG_SER_HW_HANDSHAKE)
323 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
327 /* Reenable receive complete int */
332 * Serial 1 RX complete interrupt handler.
334 * This handler is interruptible.
335 * Interrupt are reenabled as soon as recv complete interrupt is
336 * disabled. Using INTERRUPT() is troublesome when the serial
337 * is heavily loaded, because and interrupt could be retriggered
338 * when executing the handler prologue before RXCIE is disabled.
340 #ifndef __AVR_ATmega103__
341 SIGNAL(SIG_UART1_RECV)
343 /* Disable Recv complete IRQ */
344 UCSR0B &= ~BV(RXCIE);
347 /* Should be read before UDR */
348 ser_handles[SER_UART1].status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
350 /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
351 * not going to accept the incoming data
355 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
356 ser_handles[SER_UART1].status |= SERRF_RXFIFOOVERRUN;
359 fifo_push(&ser_handles[SER_UART1].rxfifo, c);
360 #if defined(CONFIG_SER_HW_HANDSHAKE)
361 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
365 /* Reenable receive complete int */
368 #endif /* !__AVR_ATmega103__ */
372 * SPI Flag: true if we are transmitting/receiving with the SPI.
374 * This kludge is necessary because the SPI sends and receives bytes
375 * at the same time and the SPI IRQ is unique for send/receive.
376 * The only way to start transmission is to write data in SPDR (this
377 * is done by ser_spi_starttx()). We do this *only* if a transfer is
378 * not already started.
380 static volatile bool spi_sending = false;
382 static void spi_starttx(UNUSED(struct SerialHardware *ctx))
386 DISABLE_IRQSAVE(flags);
388 /* Send data only if the SPI is not already transmitting */
389 if (!spi_sending && !fifo_isempty(&ser_handles[SER_SPI].txfifo))
391 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
395 ENABLE_IRQRESTORE(flags);
399 * SPI interrupt handler
403 /* Read incoming byte. */
404 if (!fifo_isfull(&ser_handles[SER_SPI].rxfifo))
405 fifo_push(&ser_handles[SER_SPI].rxfifo, SPDR);
409 ser_handles[SER_SPI].status |= SERRF_RXFIFOOVERRUN;
413 if (!fifo_isempty(&ser_handles[SER_SPI].txfifo))
414 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
422 #pragma vector = UART_TXC_vect
423 __interrupt void UART_TXC_interrupt(void)
427 UCSRB = RXCIE | RXEN | TXEN; //Abilito l'Interrupt in ricezione e RX e TX
432 static const struct SerialHardwareVT UART0_VT =
435 .cleanup = uart0_cleanup,
436 .setbaudrate = uart0_setbaudrate,
437 .setparity = uart0_setparity,
438 .enabletxirq = uart0_enabletxirq,
441 static const struct SerialHardwareVT UART1_VT =
444 .cleanup = uart1_cleanup,
445 .setbaudrate = uart1_setbaudrate,
446 .setparity = uart1_setparity,
447 .enabletxirq = uart1_enabletxirq,
450 static const struct SerialHardwareVT SPI_VT =
453 .cleanup = spi_cleanup,
454 .enabletxirq = spi_starttx,
457 static struct AvrSerial UARTDescs[SER_CNT] =
460 .hw = { .table = &UART0_VT },
464 .hw = { .table = &UART1_VT },
468 .hw = { .table = &SPI_VT },
472 struct SerialHardware* ser_hw_getdesc(int unit)
474 ASSERT(unit < SER_CNT);
475 return &UARTDescs[unit].hw;