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.
9 * \brief AVR UART and SPI I/O driver
11 * Rationale for project_ks hardware.
13 * The serial 0 on the board_kf board is used to communicate with the
14 * smart card, which has the TX and RX lines connected together. To
15 * allow the smart card to drive the RX line of the CPU the CPU TX has
16 * to be in a high impedance state.
17 * Whenever a transmission is done and there is nothing more to send
18 * the transmitter is turn off. The output pin is held in input with
19 * pull-up enabled, to avoid capturing noise from the nearby RX line.
21 * The line on the KBus port has to be active everytime, even when
22 * there is nothing to transmit, because the transmission of burst
23 * of data generate noise on the audio channels.
24 * This is accomplished with the multiprocessor mode of the ATmega64
26 * The receiver keep MPCM bit always on. When useful data
27 * is trasmitted the address bit is set. The receiver hardware
28 * consider the frame as address info and receive it.
29 * When useless fill bytes are sent the address bit is cleared
30 * and the receiver will ignore them, avoiding useless triggering
34 * \author Bernardo Innocenti <bernie@develer.com>
39 * Revision 1.6 2004/07/13 19:20:40 aleph
40 * Add and cleanup comments
42 * Revision 1.5 2004/06/27 15:25:40 aleph
43 * Add missing callbacks for SPI;
44 * Change UNUSED() macro to new version with two args;
45 * Use TX line filling only on the correct KBUS serial port;
46 * Fix nasty IRQ disabling bug in recv complete hander for port 1.
48 * Revision 1.4 2004/06/03 11:27:09 bernie
49 * Add dual-license information.
51 * Revision 1.3 2004/06/02 21:35:24 aleph
52 * Serial enhancements: interruptible receive handler and 8 bit serial status for AVR; remove volatile attribute to FIFOBuffer, useless for new fifobuf routens
54 * Revision 1.2 2004/05/23 18:21:53 bernie
55 * Trim CVS logs and cleanup header info.
64 #include <mware/fifobuf.h>
66 extern struct Serial ser_handles[SER_CNT];
70 struct SerialHardware hw;
71 struct Serial* serial;
75 /* Hardware handshake */
78 #define IS_CTS_ON true
79 #define IS_CTS_OFF false
82 /* SPI port and pin configuration */
83 #define SPI_PORT PORTB
85 #define SPI_SCK_BIT PORTB1
86 #define SPI_MOSI_BIT PORTB2
87 #define SPI_MISO_BIT PORTB3
90 #ifdef __AVR_ATmega103__
91 /* Macro for ATmega103 compatibility */
103 /* Transmission fill byte */
104 #define SER_FILL_BYTE 0xAA
107 static void uart0_enabletxirq(UNUSED(struct SerialHardware *, ctx))
109 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
110 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
112 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
116 static void uart0_init(struct SerialHardware *_hw, struct Serial *ser)
118 struct AvrSerial *hw = (struct AvrSerial *)_hw;
121 /* Set TX port as input with pull-up enabled to avoid
122 * noise on the remote RX when TX is disabled */
124 DISABLE_IRQSAVE(flags);
127 ENABLE_IRQRESTORE(flags);
129 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
131 * Set multiprocessor mode and 9 bit data frame.
132 * The receiver keep MPCM bit always on. When useful data
133 * is trasmitted the ninth bit is set and the receiver receive
135 * When useless fill bytes are sent the ninth bit is cleared
136 * and the receiver will ignore them.
139 UCSR0B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
141 UCSR0B = BV(RXCIE) | BV(RXEN);
147 static void uart0_cleanup(UNUSED(struct SerialHardware *, ctx))
152 static void uart0_setbaudrate(UNUSED(struct SerialHardware *, ctx), unsigned long rate)
154 /* Compute baud-rate period */
155 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
157 #ifndef __AVR_ATmega103__
158 UBRR0H = (period) >> 8;
164 #ifndef __AVR_ATmega103__
166 static void uart1_enabletxirq(UNUSED(struct SerialHardware *, ctx))
168 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
169 UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
171 UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
175 static void uart1_init(struct SerialHardware *_hw, struct Serial *ser)
177 struct AvrSerial *hw = (struct AvrSerial *)_hw;
180 /* Set TX port as input with pull-up enabled to avoid
181 * noise on the remote RX when TX is disabled */
183 DISABLE_IRQSAVE(flags);
186 ENABLE_IRQRESTORE(flags);
188 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
189 /*! See comment in uart0_init() */
191 UCSR1B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
193 UCSR1B = BV(RXCIE) | BV(RXEN);
199 static void uart1_cleanup(UNUSED(struct SerialHardware *, ctx))
204 static void uart1_setbaudrate(UNUSED(struct SerialHardware *, ctx), unsigned long rate)
206 /* Compute baud-rate period */
207 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
209 UBRR1H = (period) >> 8;
213 static void uart0_setparity(UNUSED(struct SerialHardware *, ctx), int parity)
215 UCSR0C |= (parity) << UPM0;
218 static void uart1_setparity(UNUSED(struct SerialHardware *, ctx), int parity)
220 UCSR1C |= (parity) << UPM0;
223 #endif /* !__AVR_ATmega103__ */
226 static void spi_init(struct SerialHardware *_hw, struct Serial *ser)
228 struct AvrSerial *hw = (struct AvrSerial *)_hw;
232 * Set MOSI and SCK ports out, MISO in.
234 * The ATmega64 datasheet explicitly states that the input/output
235 * state of the SPI pins is not significant, as when the SPI is
236 * active the I/O port are overrided.
237 * This is *blatantly FALSE*.
239 * Moreover the MISO pin on the board_kc *must* be in high impedance
240 * state even when the SPI is off, because the line is wired together
241 * with the KBus serial RX, and the transmitter of the slave boards
242 * could not be able to drive the line.
244 SPI_DDR |= BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT);
245 SPI_DDR &= ~BV(SPI_MISO_BIT);
246 /* Enable SPI, IRQ on, Master, CPU_CLOCK/16 */
247 SPCR = BV(SPE) | BV(SPIE) | BV(MSTR) | BV(SPR0);
250 static void spi_cleanup(UNUSED(struct SerialHardware *, ctx))
253 /* Set all pins as inputs */
254 SPI_DDR &= ~(BV(SPI_MISO_BIT) | BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT));
257 static void spi_setbaudrate(UNUSED(struct SerialHardware *, ctx), UNUSED(unsigned long, rate))
262 static void spi_setparity(UNUSED(struct SerialHardware *, ctx), UNUSED(int, parity))
268 #if defined(CONFIG_SER_HW_HANDSHAKE)
270 //! This interrupt is triggered when the CTS line goes high
273 // Re-enable UDR empty interrupt and TX, then disable CTS interrupt
274 UCR = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
275 cbi(EIMSK, EIMSKB_CTS);
278 #endif // CONFIG_SER_HW_HANDSHAKE
282 * Serial 0 TX interrupt handler
284 #ifdef __AVR_ATmega103__
285 SIGNAL(SIG_UART_DATA)
287 SIGNAL(SIG_UART0_DATA)
290 if (fifo_isempty(&ser_handles[SER_UART0].txfifo))
292 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
294 * To avoid audio interference: always transmit useless char.
295 * Send the byte with the ninth bit cleared, the receiver in MCPM mode
299 UDR0 = SER_FILL_BYTE;
301 /* Disable UDR empty interrupt and transmitter */
302 UCR = BV(RXCIE) | BV(RXEN);
305 #if defined(CONFIG_SER_HWHANDSHAKE)
308 // disable rx interrupt and tx, enable CTS interrupt
309 UCR = BV(RXCIE) | BV(RXEN);
310 sbi(EIFR, EIMSKB_CTS);
311 sbi(EIMSK, EIMSKB_CTS);
313 #endif // CONFIG_SER_HWHANDSHAKE
316 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
317 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
320 UDR = fifo_pop(&ser_handles[SER_UART0].txfifo);
325 * Serial 1 TX interrupt handler
327 #ifndef __AVR_ATmega103__
328 SIGNAL(SIG_UART1_DATA)
330 if (fifo_isempty(&ser_handles[SER_UART1].txfifo))
332 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
334 * To avoid audio interference: always transmit useless char.
335 * Send the byte with the ninth bit cleared, the receiver in MCPM mode
339 UDR1 = SER_FILL_BYTE;
341 /* Disable UDR empty interrupt and transmitter */
342 UCSR1B = BV(RXCIE) | BV(RXEN);
345 #if defined(CONFIG_SER_HWHANDSHAKE)
348 // disable rx interrupt and tx, enable CTS interrupt
349 UCSR1B = BV(RXCIE) | BV(RXEN);
350 sbi(EIFR, EIMSKB_CTS);
351 sbi(EIMSK, EIMSKB_CTS);
353 #endif // CONFIG_SER_HWHANDSHAKE
356 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
357 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
360 UDR1 = fifo_pop(&ser_handles[SER_UART1].txfifo);
363 #endif /* !__AVR_ATmega103__ */
367 * Serial 0 RX complete interrupt handler.
369 * This handler is interruptible.
370 * Interrupt are reenabled as soon as recv complete interrupt is
371 * disabled. Using INTERRUPT() is troublesome when the serial
372 * is heavily loaded, because an interrupt could be retriggered
373 * when executing the handler prologue before RXCIE is disabled.
375 #ifdef __AVR_ATmega103__
376 SIGNAL(SIG_UART_RECV)
378 SIGNAL(SIG_UART0_RECV)
381 /* Disable Recv complete IRQ */
385 /* Should be read before UDR */
386 ser_handles[SER_UART0].status |= USR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
388 /* To clear the RXC flag we must _always_ read the UDR even when we're
389 * not going to accept the incoming data, otherwise a new interrupt
390 * will occur once the handler terminates.
394 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
395 ser_handles[SER_UART0].status |= SERRF_RXFIFOOVERRUN;
398 fifo_push(&ser_handles[SER_UART0].rxfifo, c);
399 #if defined(CONFIG_SER_HW_HANDSHAKE)
400 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
404 /* Reenable receive complete int */
409 * Serial 1 RX complete interrupt handler.
411 * This handler is interruptible.
412 * Interrupt are reenabled as soon as recv complete interrupt is
413 * disabled. Using INTERRUPT() is troublesome when the serial
414 * is heavily loaded, because an interrupt could be retriggered
415 * when executing the handler prologue before RXCIE is disabled.
417 #ifndef __AVR_ATmega103__
418 SIGNAL(SIG_UART1_RECV)
420 /* Disable Recv complete IRQ */
421 UCSR1B &= ~BV(RXCIE);
424 /* Should be read before UDR */
425 ser_handles[SER_UART1].status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
427 /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
428 * not going to accept the incoming data
432 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
433 ser_handles[SER_UART1].status |= SERRF_RXFIFOOVERRUN;
436 fifo_push(&ser_handles[SER_UART1].rxfifo, c);
437 #if defined(CONFIG_SER_HW_HANDSHAKE)
438 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
442 /* Reenable receive complete int */
445 #endif /* !__AVR_ATmega103__ */
449 * SPI Flag: true if we are transmitting/receiving with the SPI.
451 * This kludge is necessary because the SPI sends and receives bytes
452 * at the same time and the SPI IRQ is unique for send/receive.
453 * The only way to start transmission is to write data in SPDR (this
454 * is done by spi_starttx()). We do this *only* if a transfer is
455 * not already started.
457 static volatile bool spi_sending = false;
459 static void spi_starttx(UNUSED(struct SerialHardware *, ctx))
463 DISABLE_IRQSAVE(flags);
465 /* Send data only if the SPI is not already transmitting */
466 if (!spi_sending && !fifo_isempty(&ser_handles[SER_SPI].txfifo))
468 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
472 ENABLE_IRQRESTORE(flags);
476 * SPI interrupt handler
480 /* Read incoming byte. */
481 if (!fifo_isfull(&ser_handles[SER_SPI].rxfifo))
482 fifo_push(&ser_handles[SER_SPI].rxfifo, SPDR);
486 ser_handles[SER_SPI].status |= SERRF_RXFIFOOVERRUN;
490 if (!fifo_isempty(&ser_handles[SER_SPI].txfifo))
491 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
499 #pragma vector = UART_TXC_vect
500 __interrupt void UART_TXC_interrupt(void)
504 UCSRB = RXCIE | RXEN | TXEN; //Abilito l'Interrupt in ricezione e RX e TX
509 static const struct SerialHardwareVT UART0_VT =
512 .cleanup = uart0_cleanup,
513 .setbaudrate = uart0_setbaudrate,
514 .setparity = uart0_setparity,
515 .enabletxirq = uart0_enabletxirq,
518 static const struct SerialHardwareVT UART1_VT =
521 .cleanup = uart1_cleanup,
522 .setbaudrate = uart1_setbaudrate,
523 .setparity = uart1_setparity,
524 .enabletxirq = uart1_enabletxirq,
527 static const struct SerialHardwareVT SPI_VT =
530 .cleanup = spi_cleanup,
531 .setbaudrate = spi_setbaudrate,
532 .setparity = spi_setparity,
533 .enabletxirq = spi_starttx,
536 static struct AvrSerial UARTDescs[SER_CNT] =
539 .hw = { .table = &UART0_VT },
543 .hw = { .table = &UART1_VT },
547 .hw = { .table = &SPI_VT },
551 struct SerialHardware* ser_hw_getdesc(int unit)
553 ASSERT(unit < SER_CNT);
554 return &UARTDescs[unit].hw;