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.2 2004/05/23 18:21:53 bernie
19 * Trim CVS logs and cleanup header info.
28 #include <mware/fifobuf.h>
30 extern struct Serial ser_handles[SER_CNT];
34 struct SerialHardware hw;
35 struct Serial* serial;
39 /* Hardware handshake */
42 #define IS_CTS_ON true
43 #define IS_CTS_OFF false
46 /* SPI port and pin configuration */
47 #define SPI_PORT PORTB
49 #define SPI_SCK_BIT PORTB1
50 #define SPI_MOSI_BIT PORTB2
51 #define SPI_MISO_BIT PORTB3
54 #ifdef __AVR_ATmega103__
55 /* Macro for ATmega103 compatibility */
67 /* Transmission fill byte */
68 #define SER_FILL_BYTE 0xAA
71 static void uart0_enabletxirq(UNUSED(struct SerialHardware *ctx))
73 #ifdef CONFIG_SER_TXFILL
74 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
76 UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
80 static void uart0_init(struct SerialHardware *_hw, struct Serial *ser)
82 struct AvrSerial *hw = (struct AvrSerial *)_hw;
85 /* Set TX port as input with pull-up enabled to avoid
86 * noise on the remote RX when TX is disabled */
88 DISABLE_IRQSAVE(flags);
91 ENABLE_IRQRESTORE(flags);
93 /* TODO: explain why TX is disabled whenever possible */
94 #ifdef CONFIG_SER_TXFILL
96 * Set multiprocessor mode and 9 bit data frame.
97 * The receiver keep MPCM bit always on. When useful data
98 * is trasmitted the ninth bit is set. Receiver consider the
99 * frame as address info and receive it.
100 * When useless fill bytes are sent the ninth bit is cleared
101 * and the receiver will ignore them, avoiding useless triggering
105 UCSR0B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
107 UCSR0B = BV(RXCIE) | BV(RXEN);
113 static void uart0_cleanup(UNUSED(struct SerialHardware *ctx))
118 static void uart0_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
120 // Compute baud-rate period
121 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
123 #ifndef __AVR_ATmega103__
124 UBRR0H = (period) >> 8;
130 #ifndef __AVR_ATmega103__
132 static void uart1_enabletxirq(UNUSED(struct SerialHardware *ctx))
134 UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
137 static void uart1_init(struct SerialHardware *_hw, struct Serial *ser)
139 struct AvrSerial *hw = (struct AvrSerial *)_hw;
142 /* Set TX port as input with pull-up enabled to avoid
143 * noise on the remote RX when TX is disabled */
145 DISABLE_IRQSAVE(flags);
148 ENABLE_IRQRESTORE(flags);
150 /* TODO: explain why TX is disabled whenever possible */
151 UCSR1B = BV(RXCIE) | BV(RXEN);
156 static void uart1_cleanup(UNUSED(struct SerialHardware *ctx))
161 static void uart1_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
163 // Compute baud-rate period
164 uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
166 UBRR1H = (period) >> 8;
170 static void uart0_setparity(UNUSED(struct SerialHardware *ctx), int parity)
172 UCSR0C |= (parity) << UPM0;
175 static void uart1_setparity(UNUSED(struct SerialHardware *ctx), int parity)
177 UCSR1C |= (parity) << UPM0;
180 #endif /* !__AVR_ATmega103__ */
183 static void spi_init(struct SerialHardware *_hw, struct Serial *ser)
185 struct AvrSerial *hw = (struct AvrSerial *)_hw;
188 /* MOSI and SCK out, MISO in */
189 SPI_DDR |= BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT);
190 SPI_DDR &= ~BV(SPI_MISO_BIT);
191 /* Enable SPI, IRQ on, Master, CPU_CLOCK/16 */
192 SPCR = BV(SPE) | BV(SPIE) | BV(MSTR) | BV(SPR0);
195 static void spi_cleanup(UNUSED(struct SerialHardware *ctx))
198 /* Set all pins as inputs */
199 SPI_DDR &= ~(BV(SPI_MISO_BIT) | BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT));
204 #if defined(CONFIG_SER_HW_HANDSHAKE)
206 //! This interrupt is triggered when the CTS line goes high
209 // Re-enable UDR empty interrupt and TX, then disable CTS interrupt
210 UCR = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
211 cbi(EIMSK, EIMSKB_CTS);
214 #endif // CONFIG_SER_HW_HANDSHAKE
218 * Serial 0 TX interrupt handler
220 #ifdef __AVR_ATmega103__
221 SIGNAL(SIG_UART_DATA)
223 SIGNAL(SIG_UART0_DATA)
226 if (fifo_isempty(&ser_handles[SER_UART0].txfifo))
228 #ifdef CONFIG_SER_TXFILL
230 * To avoid audio interference: always transmit useless char.
231 * Send the byte with the ninth bit cleared, the receiver in MCPM mode
235 UDR0 = SER_FILL_BYTE;
237 /* Disable UDR empty interrupt and transmitter */
238 UCR = BV(RXCIE) | BV(RXEN);
241 #if defined(CONFIG_SER_HWHANDSHAKE)
244 // disable rx interrupt and tx, enable CTS interrupt
245 UCR = BV(RXCIE) | BV(RXEN);
246 sbi(EIFR, EIMSKB_CTS);
247 sbi(EIMSK, EIMSKB_CTS);
249 #endif // CONFIG_SER_HWHANDSHAKE
252 #ifdef CONFIG_SER_TXFILL
253 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
256 UDR = fifo_pop(&ser_handles[SER_UART0].txfifo);
261 * Serial 1 TX interrupt handler
263 #ifndef __AVR_ATmega103__
264 SIGNAL(SIG_UART1_DATA)
266 if (fifo_isempty(&ser_handles[SER_UART1].txfifo))
268 /* Disable UDR empty interrupt and transmitter */
269 UCSR1B = BV(RXCIE) | BV(RXEN);
271 #if defined(CONFIG_SER_HWHANDSHAKE)
274 // disable rx interrupt and tx, enable CTS interrupt
275 UCSR1B = BV(RXCIE) | BV(RXEN);
276 sbi(EIFR, EIMSKB_CTS);
277 sbi(EIMSK, EIMSKB_CTS);
279 #endif // CONFIG_SER_HWHANDSHAKE
281 UDR1 = fifo_pop(&ser_handles[SER_UART1].txfifo);
283 #endif /* !__AVR_ATmega103__ */
287 * Serial 0 RX complete interrupt handler
289 #ifdef __AVR_ATmega103__
290 SIGNAL(SIG_UART_RECV)
292 SIGNAL(SIG_UART0_RECV)
295 /* Should be read before UDR */
296 ser_handles[SER_UART0].status |= USR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
298 /* To clear the RXC flag we must _always_ read the UDR even when we're
299 * not going to accept the incoming data, otherwise a new interrupt
300 * will occur once the handler terminates.
304 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
305 ser_handles[SER_UART0].status |= SERRF_RXFIFOOVERRUN;
308 fifo_push(&ser_handles[SER_UART0].rxfifo, c);
309 #if defined(CONFIG_SER_HW_HANDSHAKE)
310 if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
317 * Serial 1 RX complete interrupt handler
319 #ifndef __AVR_ATmega103__
320 SIGNAL(SIG_UART1_RECV)
322 /* Should be read before UDR */
323 ser_handles[SER_UART1].status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
325 /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
326 * not going to accept the incoming data
330 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
331 ser_handles[SER_UART1].status |= SERRF_RXFIFOOVERRUN;
334 fifo_push(&ser_handles[SER_UART1].rxfifo, c);
335 #if defined(CONFIG_SER_HW_HANDSHAKE)
336 if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
341 #endif /* !__AVR_ATmega103__ */
345 * SPI Flag: true if we are transmitting/receiving with the SPI.
347 * This kludge is necessary because the SPI sends and receives bytes
348 * at the same time and the SPI IRQ is unique for send/receive.
349 * The only way to start transmission is to write data in SPDR (this
350 * is done by ser_spi_starttx()). We do this *only* if a transfer is
351 * not already started.
353 static volatile bool spi_sending = false;
355 static void spi_starttx(UNUSED(struct SerialHardware *ctx))
359 DISABLE_IRQSAVE(flags);
361 /* Send data only if the SPI is not already transmitting */
362 if (!spi_sending && !fifo_isempty(&ser_handles[SER_SPI].txfifo))
364 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
368 ENABLE_IRQRESTORE(flags);
372 * SPI interrupt handler
376 /* Read incoming byte. */
377 if (!fifo_isfull(&ser_handles[SER_SPI].rxfifo))
378 fifo_push(&ser_handles[SER_SPI].rxfifo, SPDR);
382 ser_handles[SER_SPI].status |= SERRF_RXFIFOOVERRUN;
386 if (!fifo_isempty(&ser_handles[SER_SPI].txfifo))
387 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
395 #pragma vector = UART_TXC_vect
396 __interrupt void UART_TXC_interrupt(void)
400 UCSRB = RXCIE | RXEN | TXEN; //Abilito l'Interrupt in ricezione e RX e TX
405 static const struct SerialHardwareVT UART0_VT =
408 .cleanup = uart0_cleanup,
409 .setbaudrate = uart0_setbaudrate,
410 .setparity = uart0_setparity,
411 .enabletxirq = uart0_enabletxirq,
414 static const struct SerialHardwareVT UART1_VT =
417 .cleanup = uart1_cleanup,
418 .setbaudrate = uart1_setbaudrate,
419 .setparity = uart1_setparity,
420 .enabletxirq = uart1_enabletxirq,
423 static const struct SerialHardwareVT SPI_VT =
426 .cleanup = spi_cleanup,
427 .enabletxirq = spi_starttx,
430 static struct AvrSerial UARTDescs[SER_CNT] =
433 .hw = { .table = &UART0_VT },
437 .hw = { .table = &UART1_VT },
441 .hw = { .table = &SPI_VT },
445 struct SerialHardware* ser_hw_getdesc(int unit)
447 ASSERT(unit < SER_CNT);
448 return &UARTDescs[unit].hw;