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.1 2004/05/23 18:10:11 bernie
19 * Import drv/ modules.
21 * Revision 1.30 2004/05/19 17:06:11 bernie
24 * Revision 1.29 2004/05/16 19:16:46 aleph
25 * Serial always transmitting, first try
27 * Revision 1.28 2004/05/14 12:09:00 aleph
28 * Fix TX port pull-ups
30 * Revision 1.27 2004/05/08 13:56:02 aleph
31 * Adapt avr serial driver to new design
33 * Revision 1.25 2004/04/28 13:42:16 aleph
36 * Revision 1.24 2004/04/08 14:17:27 bernie
37 * Change serial to disable TX when not sending data
39 * Revision 1.23 2004/04/03 20:39:41 aleph
42 * Revision 1.22 2004/03/29 17:01:02 aleph
43 * Add function to set serial parity, fix it when ser_open is used
51 #include <mware/fifobuf.h>
53 extern struct Serial ser_handles[SER_CNT];
57 struct SerialHardware hw;
58 struct Serial* serial;
62 /* Hardware handshake */
65 #define IS_CTS_ON true
66 #define IS_CTS_OFF false
69 /* SPI port and pin configuration */
70 #define SPI_PORT PORTB
72 #define SPI_SCK_BIT PORTB1
73 #define SPI_MOSI_BIT PORTB2
74 #define SPI_MISO_BIT PORTB3
77 #ifdef __AVR_ATmega103__
78 /* Macro for ATmega103 compatibility */
90 /* Transmission fill byte */
91 #define SER_FILL_BYTE 0xAA
94 static void uart0_enabletxirq(UNUSED(struct SerialHardware *ctx))
96 #ifdef CONFIG_SER_TXFILL
97 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
99 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
103 static void uart0_init(struct SerialHardware *_hw, struct Serial *ser)
105 struct AvrSerial *hw = (struct AvrSerial *)_hw;
108 /* Set TX port as input with pull-up enabled to avoid
109 * noise on the remote RX when TX is disabled */
111 DISABLE_IRQSAVE(flags);
114 ENABLE_IRQRESTORE(flags);
116 /* TODO: explain why TX is disabled whenever possible */
117 #ifdef CONFIG_SER_TXFILL
119 * Set multiprocessor mode and 9 bit data frame.
120 * The receiver keep MPCM bit always on. When useful data
121 * is trasmitted the ninth bit is set. Receiver consider the
122 * frame as address info and receive it.
123 * When useless fill bytes are sent the ninth bit is cleared
124 * and the receiver will ignore them, avoiding useless triggering
128 UCSR0B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
130 UCSR0B = BV(RXCIE) | BV(RXEN);
136 static void uart0_cleanup(UNUSED(struct SerialHardware *ctx))
141 static void uart0_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
143 // Compute baud-rate period
144 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
146 #ifndef __AVR_ATmega103__
147 UBRR0H = (period) >> 8;
153 #ifndef __AVR_ATmega103__
155 static void uart1_enabletxirq(UNUSED(struct SerialHardware *ctx))
157 UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
160 static void uart1_init(struct SerialHardware *_hw, struct Serial *ser)
162 struct AvrSerial *hw = (struct AvrSerial *)_hw;
165 /* Set TX port as input with pull-up enabled to avoid
166 * noise on the remote RX when TX is disabled */
168 DISABLE_IRQSAVE(flags);
171 ENABLE_IRQRESTORE(flags);
173 /* TODO: explain why TX is disabled whenever possible */
174 UCSR1B = BV(RXCIE) | BV(RXEN);
179 static void uart1_cleanup(UNUSED(struct SerialHardware *ctx))
184 static void uart1_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
186 // Compute baud-rate period
187 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
189 UBRR1H = (period) >> 8;
193 static void uart0_setparity(UNUSED(struct SerialHardware *ctx), int parity)
195 UCSR0C |= (parity) << UPM0;
198 static void uart1_setparity(UNUSED(struct SerialHardware *ctx), int parity)
200 UCSR1C |= (parity) << UPM0;
203 #endif /* !__AVR_ATmega103__ */
206 static void spi_init(struct SerialHardware *_hw, struct Serial *ser)
208 struct AvrSerial *hw = (struct AvrSerial *)_hw;
211 /* MOSI and SCK out, MISO in */
212 SPI_DDR |= BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT);
213 SPI_DDR &= ~BV(SPI_MISO_BIT);
214 /* Enable SPI, IRQ on, Master, CPU_CLOCK/16 */
215 SPCR = BV(SPE) | BV(SPIE) | BV(MSTR) | BV(SPR0);
218 static void spi_cleanup(UNUSED(struct SerialHardware *ctx))
221 /* Set all pins as inputs */
222 SPI_DDR &= ~(BV(SPI_MISO_BIT) | BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT));
227 #if defined(CONFIG_SER_HW_HANDSHAKE)
229 //! This interrupt is triggered when the CTS line goes high
232 // Re-enable UDR empty interrupt and TX, then disable CTS interrupt
233 UCR = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
234 cbi(EIMSK, EIMSKB_CTS);
237 #endif // CONFIG_SER_HW_HANDSHAKE
241 * Serial 0 TX interrupt handler
243 #ifdef __AVR_ATmega103__
244 SIGNAL(SIG_UART_DATA)
246 SIGNAL(SIG_UART0_DATA)
249 if (fifo_isempty(&ser_handles[SER_UART0].txfifo))
251 #ifdef CONFIG_SER_TXFILL
253 * To avoid audio interference: always transmit useless char.
254 * Send the byte with the ninth bit cleared, the receiver in MCPM mode
258 UDR0 = SER_FILL_BYTE;
260 /* Disable UDR empty interrupt and transmitter */
261 UCR = BV(RXCIE) | BV(RXEN);
264 #if defined(CONFIG_SER_HWHANDSHAKE)
267 // disable rx interrupt and tx, enable CTS interrupt
268 UCR = BV(RXCIE) | BV(RXEN);
269 sbi(EIFR, EIMSKB_CTS);
270 sbi(EIMSK, EIMSKB_CTS);
272 #endif // CONFIG_SER_HWHANDSHAKE
275 #ifdef CONFIG_SER_TXFILL
276 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
279 UDR = fifo_pop(&ser_handles[SER_UART0].txfifo);
284 * Serial 1 TX interrupt handler
286 #ifndef __AVR_ATmega103__
287 SIGNAL(SIG_UART1_DATA)
289 if (fifo_isempty(&ser_handles[SER_UART1].txfifo))
291 /* Disable UDR empty interrupt and transmitter */
292 UCSR1B = BV(RXCIE) | BV(RXEN);
294 #if defined(CONFIG_SER_HWHANDSHAKE)
297 // disable rx interrupt and tx, enable CTS interrupt
298 UCSR1B = BV(RXCIE) | BV(RXEN);
299 sbi(EIFR, EIMSKB_CTS);
300 sbi(EIMSK, EIMSKB_CTS);
302 #endif // CONFIG_SER_HWHANDSHAKE
304 UDR1 = fifo_pop(&ser_handles[SER_UART1].txfifo);
306 #endif /* !__AVR_ATmega103__ */
310 * Serial 0 RX complete interrupt handler
312 #ifdef __AVR_ATmega103__
313 SIGNAL(SIG_UART_RECV)
315 SIGNAL(SIG_UART0_RECV)
318 /* Should be read before UDR */
319 ser_handles[SER_UART0].status |= USR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
321 /* To clear the RXC flag we must _always_ read the UDR even when we're
322 * not going to accept the incoming data, otherwise a new interrupt
323 * will occur once the handler terminates.
327 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
328 ser_handles[SER_UART0].status |= SERRF_RXFIFOOVERRUN;
331 fifo_push(&ser_handles[SER_UART0].rxfifo, c);
332 #if defined(CONFIG_SER_HW_HANDSHAKE)
333 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
340 * Serial 1 RX complete interrupt handler
342 #ifndef __AVR_ATmega103__
343 SIGNAL(SIG_UART1_RECV)
345 /* Should be read before UDR */
346 ser_handles[SER_UART1].status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
348 /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
349 * not going to accept the incoming data
353 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
354 ser_handles[SER_UART1].status |= SERRF_RXFIFOOVERRUN;
357 fifo_push(&ser_handles[SER_UART1].rxfifo, c);
358 #if defined(CONFIG_SER_HW_HANDSHAKE)
359 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
364 #endif /* !__AVR_ATmega103__ */
368 * SPI Flag: true if we are transmitting/receiving with the SPI.
370 * This kludge is necessary because the SPI sends and receives bytes
371 * at the same time and the SPI IRQ is unique for send/receive.
372 * The only way to start transmission is to write data in SPDR (this
373 * is done by ser_spi_starttx()). We do this *only* if a transfer is
374 * not already started.
376 static volatile bool spi_sending = false;
378 static void spi_starttx(UNUSED(struct SerialHardware *ctx))
382 DISABLE_IRQSAVE(flags);
384 /* Send data only if the SPI is not already transmitting */
385 if (!spi_sending && !fifo_isempty(&ser_handles[SER_SPI].txfifo))
387 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
391 ENABLE_IRQRESTORE(flags);
395 * SPI interrupt handler
399 /* Read incoming byte. */
400 if (!fifo_isfull(&ser_handles[SER_SPI].rxfifo))
401 fifo_push(&ser_handles[SER_SPI].rxfifo, SPDR);
405 ser_handles[SER_SPI].status |= SERRF_RXFIFOOVERRUN;
409 if (!fifo_isempty(&ser_handles[SER_SPI].txfifo))
410 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
418 #pragma vector = UART_TXC_vect
419 __interrupt void UART_TXC_interrupt(void)
423 UCSRB = RXCIE | RXEN | TXEN; //Abilito l'Interrupt in ricezione e RX e TX
428 static const struct SerialHardwareVT UART0_VT =
431 .cleanup = uart0_cleanup,
432 .setbaudrate = uart0_setbaudrate,
433 .setparity = uart0_setparity,
434 .enabletxirq = uart0_enabletxirq,
437 static const struct SerialHardwareVT UART1_VT =
440 .cleanup = uart1_cleanup,
441 .setbaudrate = uart1_setbaudrate,
442 .setparity = uart1_setparity,
443 .enabletxirq = uart1_enabletxirq,
446 static const struct SerialHardwareVT SPI_VT =
449 .cleanup = spi_cleanup,
450 .enabletxirq = spi_starttx,
453 static struct AvrSerial UARTDescs[SER_CNT] =
456 .hw = { .table = &UART0_VT },
460 .hw = { .table = &UART1_VT },
464 .hw = { .table = &SPI_VT },
468 struct SerialHardware* ser_hw_getdesc(int unit)
470 ASSERT(unit < SER_CNT);
471 return &UARTDescs[unit].hw;