Add and cleanup comments
[bertos.git] / drv / ser_avr.c
1 /*!
2  * \file
3  * <!--
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.
7  * -->
8  *
9  * \brief AVR UART and SPI I/O driver
10  *
11  * Rationale for project_ks hardware.
12  *
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.
20  *
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
25  * serial.
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
31  * of RXC interrupt.
32  *
33  * \version $Id$
34  * \author Bernardo Innocenti <bernie@develer.com>
35  */
36
37 /*
38  * $Log$
39  * Revision 1.6  2004/07/13 19:20:40  aleph
40  * Add and cleanup comments
41  *
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.
47  *
48  * Revision 1.4  2004/06/03 11:27:09  bernie
49  * Add dual-license information.
50  *
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
53  *
54  * Revision 1.2  2004/05/23 18:21:53  bernie
55  * Trim CVS logs and cleanup header info.
56  *
57  */
58
59 #include "ser.h"
60 #include "ser_p.h"
61 #include "kdebug.h"
62 #include "config.h"
63 #include "hw.h"
64 #include <mware/fifobuf.h>
65
66 extern struct Serial ser_handles[SER_CNT];
67
68 struct AvrSerial
69 {
70         struct SerialHardware hw;
71         struct Serial* serial;
72 };
73
74
75 /* Hardware handshake */
76 #define RTS_ON
77 #define RTS_OFF
78 #define IS_CTS_ON   true
79 #define IS_CTS_OFF  false
80
81
82 /* SPI port and pin configuration */
83 #define SPI_PORT      PORTB
84 #define SPI_DDR       DDRB
85 #define SPI_SCK_BIT   PORTB1
86 #define SPI_MOSI_BIT  PORTB2
87 #define SPI_MISO_BIT  PORTB3
88
89
90 #ifdef __AVR_ATmega103__
91         /* Macro for ATmega103 compatibility */
92         #define UCSR0B UCR
93         #define UDR0   UDR
94         #define UCSR0A USR
95         #define UBRR0L UBRR
96 #else
97         #define UCR  UCSR0B
98         #define UDR  UDR0
99         #define USR  UCSR0A
100 #endif
101
102
103 /* Transmission fill byte */
104 #define SER_FILL_BYTE 0xAA
105
106
107 static void uart0_enabletxirq(UNUSED(struct SerialHardware *, ctx))
108 {
109 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
110         UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
111 #else
112         UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
113 #endif
114 }
115
116 static void uart0_init(struct SerialHardware *_hw, struct Serial *ser)
117 {
118         struct AvrSerial *hw = (struct AvrSerial *)_hw;
119         hw->serial = ser;
120
121         /* Set TX port as input with pull-up enabled to avoid
122          * noise on the remote RX when TX is disabled */
123         cpuflags_t flags;
124         DISABLE_IRQSAVE(flags);
125         DDRE &= ~BV(PORTE1);
126         PORTE |= BV(PORTE1);
127         ENABLE_IRQRESTORE(flags);
128
129 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
130         /*!
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
134          * the frame.
135          * When useless fill bytes are sent the ninth bit is cleared
136          * and the receiver will ignore them.
137          */
138         UCSR0A = BV(MPCM);
139         UCSR0B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
140 #else
141         UCSR0B = BV(RXCIE) | BV(RXEN);
142 #endif
143
144         RTS_ON;
145 }
146
147 static void uart0_cleanup(UNUSED(struct SerialHardware *, ctx))
148 {
149         UCSR0B = 0;
150 }
151
152 static void uart0_setbaudrate(UNUSED(struct SerialHardware *, ctx), unsigned long rate)
153 {
154         /* Compute baud-rate period */
155         uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
156
157 #ifndef __AVR_ATmega103__
158         UBRR0H = (period) >> 8;
159 #endif
160         UBRR0L = (period);
161 }
162
163
164 #ifndef __AVR_ATmega103__
165
166 static void uart1_enabletxirq(UNUSED(struct SerialHardware *, ctx))
167 {
168 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
169         UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
170 #else
171         UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
172 #endif
173 }
174
175 static void uart1_init(struct SerialHardware *_hw, struct Serial *ser)
176 {
177         struct AvrSerial *hw = (struct AvrSerial *)_hw;
178         hw->serial = ser;
179
180         /* Set TX port as input with pull-up enabled to avoid
181          * noise on the remote RX when TX is disabled */
182         cpuflags_t flags;
183         DISABLE_IRQSAVE(flags);
184         DDRD &= ~BV(PORTD3);
185         PORTD |= BV(PORTD3);
186         ENABLE_IRQRESTORE(flags);
187
188 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
189         /*! See comment in uart0_init() */
190         UCSR1A = BV(MPCM);
191         UCSR1B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
192 #else
193         UCSR1B = BV(RXCIE) | BV(RXEN);
194 #endif
195
196         RTS_ON;
197 }
198
199 static void uart1_cleanup(UNUSED(struct SerialHardware *, ctx))
200 {
201         UCSR1B = 0;
202 }
203
204 static void uart1_setbaudrate(UNUSED(struct SerialHardware *, ctx), unsigned long rate)
205 {
206         /* Compute baud-rate period */
207         uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
208
209         UBRR1H = (period) >> 8;
210         UBRR1L = (period);
211 }
212
213 static void uart0_setparity(UNUSED(struct SerialHardware *, ctx), int parity)
214 {
215         UCSR0C |= (parity) << UPM0;
216 }
217
218 static void uart1_setparity(UNUSED(struct SerialHardware *, ctx), int parity)
219 {
220         UCSR1C |= (parity) << UPM0;
221 }
222
223 #endif /* !__AVR_ATmega103__ */
224
225
226 static void spi_init(struct SerialHardware *_hw, struct Serial *ser)
227 {
228         struct AvrSerial *hw = (struct AvrSerial *)_hw;
229         hw->serial = ser;
230
231         /*
232          * Set MOSI and SCK ports out, MISO in.
233          *
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*.
238          *
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.
243          */
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);
248 }
249
250 static void spi_cleanup(UNUSED(struct SerialHardware *, ctx))
251 {
252         SPCR = 0;
253         /* Set all pins as inputs */
254         SPI_DDR &= ~(BV(SPI_MISO_BIT) | BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT));
255 }
256
257 static void spi_setbaudrate(UNUSED(struct SerialHardware *, ctx), UNUSED(unsigned long, rate))
258 {
259         // Do nothing
260 }
261
262 static void spi_setparity(UNUSED(struct SerialHardware *, ctx), UNUSED(int, parity))
263 {
264         // Do nothing
265 }
266
267
268 #if defined(CONFIG_SER_HW_HANDSHAKE)
269
270 //! This interrupt is triggered when the CTS line goes high
271 SIGNAL(SIG_CTS)
272 {
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);
276 }
277
278 #endif // CONFIG_SER_HW_HANDSHAKE
279
280
281 /*!
282  * Serial 0 TX interrupt handler
283  */
284 #ifdef __AVR_ATmega103__
285 SIGNAL(SIG_UART_DATA)
286 #else
287 SIGNAL(SIG_UART0_DATA)
288 #endif
289 {
290         if (fifo_isempty(&ser_handles[SER_UART0].txfifo))
291         {
292 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
293                 /*
294                  * To avoid audio interference: always transmit useless char.
295                  * Send the byte with the ninth bit cleared, the receiver in MCPM mode
296                  * will ignore it.
297                  */
298                 UCSR0B &= ~BV(TXB8);
299                 UDR0 = SER_FILL_BYTE;
300 #else
301                 /* Disable UDR empty interrupt and transmitter */
302                 UCR = BV(RXCIE) | BV(RXEN);
303 #endif
304         }
305 #if defined(CONFIG_SER_HWHANDSHAKE)
306         else if (IS_CTS_OFF)
307         {
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);
312         }
313 #endif // CONFIG_SER_HWHANDSHAKE
314         else
315         {
316 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 0)
317                 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
318                 UCSR0B |= BV(TXB8);
319 #endif
320                 UDR = fifo_pop(&ser_handles[SER_UART0].txfifo);
321         }
322 }
323
324 /*!
325  * Serial 1 TX interrupt handler
326  */
327 #ifndef __AVR_ATmega103__
328 SIGNAL(SIG_UART1_DATA)
329 {
330         if (fifo_isempty(&ser_handles[SER_UART1].txfifo))
331         {
332 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
333                 /*
334                  * To avoid audio interference: always transmit useless char.
335                  * Send the byte with the ninth bit cleared, the receiver in MCPM mode
336                  * will ignore it.
337                  */
338                 UCSR1B &= ~BV(TXB8);
339                 UDR1 = SER_FILL_BYTE;
340 #else
341                 /* Disable UDR empty interrupt and transmitter */
342                 UCSR1B = BV(RXCIE) | BV(RXEN);
343 #endif
344         }
345 #if defined(CONFIG_SER_HWHANDSHAKE)
346         else if (IS_CTS_OFF)
347         {
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);
352         }
353 #endif // CONFIG_SER_HWHANDSHAKE
354         else
355         {
356 #if defined(CONFIG_SER_TXFILL) && (CONFIG_KBUS_SERIAL_PORT == 1)
357                 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
358                 UCSR1B |= BV(TXB8);
359 #endif
360                 UDR1 = fifo_pop(&ser_handles[SER_UART1].txfifo);
361         }
362 }
363 #endif /* !__AVR_ATmega103__ */
364
365
366 /*!
367  * Serial 0 RX complete interrupt handler.
368  *
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.
374  */
375 #ifdef __AVR_ATmega103__
376 SIGNAL(SIG_UART_RECV)
377 #else
378 SIGNAL(SIG_UART0_RECV)
379 #endif
380 {
381         /* Disable Recv complete IRQ */
382         UCR &= ~BV(RXCIE);
383         ENABLE_INTS;
384
385         /* Should be read before UDR */
386         ser_handles[SER_UART0].status |= USR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
387
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.
391          */
392         char c = UDR;
393
394         if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
395                 ser_handles[SER_UART0].status |= SERRF_RXFIFOOVERRUN;
396         else
397         {
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))
401                         RTS_OFF;
402 #endif
403         }
404         /* Reenable receive complete int */
405         UCR |= BV(RXCIE);
406 }
407
408 /*!
409  * Serial 1 RX complete interrupt handler.
410  *
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.
416  */
417 #ifndef __AVR_ATmega103__
418 SIGNAL(SIG_UART1_RECV)
419 {
420         /* Disable Recv complete IRQ */
421         UCSR1B &= ~BV(RXCIE);
422         ENABLE_INTS;
423
424         /* Should be read before UDR */
425         ser_handles[SER_UART1].status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
426
427         /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
428          * not going to accept the incoming data
429          */
430         char c = UDR1;
431
432         if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
433                 ser_handles[SER_UART1].status |= SERRF_RXFIFOOVERRUN;
434         else
435         {
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))
439                         RTS_OFF;
440 #endif
441         }
442         /* Reenable receive complete int */
443         UCSR1B |= BV(RXCIE);
444 }
445 #endif /* !__AVR_ATmega103__ */
446
447
448 /*
449  * SPI Flag: true if we are transmitting/receiving with the SPI.
450  *
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.
456  */
457 static volatile bool spi_sending = false;
458
459 static void spi_starttx(UNUSED(struct SerialHardware *, ctx))
460 {
461         cpuflags_t flags;
462
463         DISABLE_IRQSAVE(flags);
464
465         /* Send data only if the SPI is not already transmitting */
466         if (!spi_sending && !fifo_isempty(&ser_handles[SER_SPI].txfifo))
467         {
468                 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
469                 spi_sending = true;
470         }
471
472         ENABLE_IRQRESTORE(flags);
473 }
474
475 /*!
476  * SPI interrupt handler
477  */
478 SIGNAL(SIG_SPI)
479 {
480         /* Read incoming byte. */
481         if (!fifo_isfull(&ser_handles[SER_SPI].rxfifo))
482                 fifo_push(&ser_handles[SER_SPI].rxfifo, SPDR);
483         /*
484          * FIXME
485         else
486                 ser_handles[SER_SPI].status |= SERRF_RXFIFOOVERRUN;
487         */
488
489         /* Send */
490         if (!fifo_isempty(&ser_handles[SER_SPI].txfifo))
491                 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
492         else
493                 spi_sending = false;
494 }
495
496
497 /*
498
499 #pragma vector = UART_TXC_vect
500 __interrupt void UART_TXC_interrupt(void)
501 {
502   UCSRB &= ~TXCIE;
503   ReceiveMode();
504   UCSRB = RXCIE | RXEN | TXEN;  //Abilito l'Interrupt in ricezione e RX e TX
505 }
506 */
507
508
509 static const struct SerialHardwareVT UART0_VT =
510 {
511         .init = uart0_init,
512         .cleanup = uart0_cleanup,
513         .setbaudrate = uart0_setbaudrate,
514         .setparity = uart0_setparity,
515         .enabletxirq = uart0_enabletxirq,
516 };
517
518 static const struct SerialHardwareVT UART1_VT =
519 {
520         .init = uart1_init,
521         .cleanup = uart1_cleanup,
522         .setbaudrate = uart1_setbaudrate,
523         .setparity = uart1_setparity,
524         .enabletxirq = uart1_enabletxirq,
525 };
526
527 static const struct SerialHardwareVT SPI_VT =
528 {
529         .init = spi_init,
530         .cleanup = spi_cleanup,
531         .setbaudrate = spi_setbaudrate,
532         .setparity = spi_setparity,
533         .enabletxirq = spi_starttx,
534 };
535
536 static struct AvrSerial UARTDescs[SER_CNT] =
537 {
538         {
539                 .hw = { .table = &UART0_VT },
540         },
541
542         {
543                 .hw = { .table = &UART1_VT },
544         },
545
546         {
547                 .hw = { .table = &SPI_VT },
548         },
549 };
550
551 struct SerialHardware* ser_hw_getdesc(int unit)
552 {
553         ASSERT(unit < SER_CNT);
554         return &UARTDescs[unit].hw;
555 }