Trim CVS logs and cleanup header info.
[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  * All Rights Reserved.
7  * -->
8  *
9  * \version $Id$
10  *
11  * \author Bernardo Innocenti <bernie@develer.com>
12  *
13  * \brief AVR UART and SPI I/O driver
14  */
15
16 /*
17  * $Log$
18  * Revision 1.2  2004/05/23 18:21:53  bernie
19  * Trim CVS logs and cleanup header info.
20  *
21  */
22
23 #include "ser.h"
24 #include "ser_p.h"
25 #include "kdebug.h"
26 #include "config.h"
27 #include "hw.h"
28 #include <mware/fifobuf.h>
29
30 extern struct Serial ser_handles[SER_CNT];
31
32 struct AvrSerial
33 {
34         struct SerialHardware hw;
35         struct Serial* serial;
36 };
37
38
39 /* Hardware handshake */
40 #define RTS_ON
41 #define RTS_OFF
42 #define IS_CTS_ON   true
43 #define IS_CTS_OFF  false
44
45
46 /* SPI port and pin configuration */
47 #define SPI_PORT      PORTB
48 #define SPI_DDR       DDRB
49 #define SPI_SCK_BIT   PORTB1
50 #define SPI_MOSI_BIT  PORTB2
51 #define SPI_MISO_BIT  PORTB3
52
53
54 #ifdef __AVR_ATmega103__
55         /* Macro for ATmega103 compatibility */
56         #define UCSR0B UCR
57         #define UDR0   UDR
58         #define UCSR0A USR
59         #define UBRR0L UBRR
60 #else
61         #define UCR  UCSR0B
62         #define UDR  UDR0
63         #define USR  UCSR0A
64 #endif
65
66
67 /* Transmission fill byte */
68 #define SER_FILL_BYTE 0xAA
69
70
71 static void uart0_enabletxirq(UNUSED(struct SerialHardware *ctx))
72 {
73 #ifdef CONFIG_SER_TXFILL
74         UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
75 #else
76         UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
77 #endif
78 }
79
80 static void uart0_init(struct SerialHardware *_hw, struct Serial *ser)
81 {
82         struct AvrSerial *hw = (struct AvrSerial *)_hw;
83         hw->serial = ser;
84
85         /* Set TX port as input with pull-up enabled to avoid
86          * noise on the remote RX when TX is disabled */
87         cpuflags_t flags;
88         DISABLE_IRQSAVE(flags);
89         DDRE &= ~BV(PORTE1);
90         PORTE |= BV(PORTE1);
91         ENABLE_IRQRESTORE(flags);
92
93         /* TODO: explain why TX is disabled whenever possible */
94 #ifdef CONFIG_SER_TXFILL
95         /*!
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
102          * of RXC interrupt.
103          */
104         UCSR0A = BV(MPCM);
105         UCSR0B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
106 #else
107         UCSR0B = BV(RXCIE) | BV(RXEN);
108 #endif
109
110         RTS_ON;
111 }
112
113 static void uart0_cleanup(UNUSED(struct SerialHardware *ctx))
114 {
115         UCSR0B = 0;
116 }
117
118 static void uart0_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
119 {
120         // Compute baud-rate period
121         uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
122
123 #ifndef __AVR_ATmega103__
124         UBRR0H = (period) >> 8;
125 #endif
126         UBRR0L = (period);
127 }
128
129
130 #ifndef __AVR_ATmega103__
131
132 static void uart1_enabletxirq(UNUSED(struct SerialHardware *ctx))
133 {
134         UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
135 }
136
137 static void uart1_init(struct SerialHardware *_hw, struct Serial *ser)
138 {
139         struct AvrSerial *hw = (struct AvrSerial *)_hw;
140         hw->serial = ser;
141
142         /* Set TX port as input with pull-up enabled to avoid
143          * noise on the remote RX when TX is disabled */
144         cpuflags_t flags;
145         DISABLE_IRQSAVE(flags);
146         DDRD &= ~BV(PORTD3);
147         PORTD |= BV(PORTD3);
148         ENABLE_IRQRESTORE(flags);
149
150         /* TODO: explain why TX is disabled whenever possible */
151         UCSR1B = BV(RXCIE) | BV(RXEN);
152
153         RTS_ON;
154 }
155
156 static void uart1_cleanup(UNUSED(struct SerialHardware *ctx))
157 {
158         UCSR1B = 0;
159 }
160
161 static void uart1_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
162 {
163         // Compute baud-rate period
164         uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
165
166         UBRR1H = (period) >> 8;
167         UBRR1L = (period);
168 }
169
170 static void uart0_setparity(UNUSED(struct SerialHardware *ctx), int parity)
171 {
172         UCSR0C |= (parity) << UPM0;
173 }
174
175 static void uart1_setparity(UNUSED(struct SerialHardware *ctx), int parity)
176 {
177         UCSR1C |= (parity) << UPM0;
178 }
179
180 #endif /* !__AVR_ATmega103__ */
181
182
183 static void spi_init(struct SerialHardware *_hw, struct Serial *ser)
184 {
185         struct AvrSerial *hw = (struct AvrSerial *)_hw;
186         hw->serial = ser;
187
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);
193 }
194
195 static void spi_cleanup(UNUSED(struct SerialHardware *ctx))
196 {
197         SPCR = 0;
198         /* Set all pins as inputs */
199         SPI_DDR &= ~(BV(SPI_MISO_BIT) | BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT));
200 }
201
202
203
204 #if defined(CONFIG_SER_HW_HANDSHAKE)
205
206 //! This interrupt is triggered when the CTS line goes high
207 SIGNAL(SIG_CTS)
208 {
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);
212 }
213
214 #endif // CONFIG_SER_HW_HANDSHAKE
215
216
217 /*!
218  * Serial 0 TX interrupt handler
219  */
220 #ifdef __AVR_ATmega103__
221 SIGNAL(SIG_UART_DATA)
222 #else
223 SIGNAL(SIG_UART0_DATA)
224 #endif
225 {
226         if (fifo_isempty(&ser_handles[SER_UART0].txfifo))
227         {
228 #ifdef CONFIG_SER_TXFILL
229                 /*
230                  * To avoid audio interference: always transmit useless char.
231                  * Send the byte with the ninth bit cleared, the receiver in MCPM mode
232                  * will ignore it.
233                  */
234                 UCSR0B &= ~BV(TXB8);
235                 UDR0 = SER_FILL_BYTE;
236 #else
237                 /* Disable UDR empty interrupt and transmitter */
238                 UCR = BV(RXCIE) | BV(RXEN);
239 #endif
240         }
241 #if defined(CONFIG_SER_HWHANDSHAKE)
242         else if (IS_CTS_OFF)
243         {
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);
248         }
249 #endif // CONFIG_SER_HWHANDSHAKE
250         else
251         {
252 #ifdef CONFIG_SER_TXFILL
253                 /* Send with ninth bit set. Receiver in MCPM mode will receive it */
254                 UCSR0B |= BV(TXB8);
255 #endif
256                 UDR = fifo_pop(&ser_handles[SER_UART0].txfifo);
257         }
258 }
259
260 /*!
261  * Serial 1 TX interrupt handler
262  */
263 #ifndef __AVR_ATmega103__
264 SIGNAL(SIG_UART1_DATA)
265 {
266         if (fifo_isempty(&ser_handles[SER_UART1].txfifo))
267         {
268                 /* Disable UDR empty interrupt and transmitter */
269                 UCSR1B = BV(RXCIE) | BV(RXEN);
270         }
271 #if defined(CONFIG_SER_HWHANDSHAKE)
272         else if (IS_CTS_OFF)
273         {
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);
278         }
279 #endif // CONFIG_SER_HWHANDSHAKE
280         else
281                 UDR1 = fifo_pop(&ser_handles[SER_UART1].txfifo);
282 }
283 #endif /* !__AVR_ATmega103__ */
284
285
286 /*!
287  * Serial 0 RX complete interrupt handler
288  */
289 #ifdef __AVR_ATmega103__
290 SIGNAL(SIG_UART_RECV)
291 #else
292 SIGNAL(SIG_UART0_RECV)
293 #endif
294 {
295         /* Should be read before UDR */
296         ser_handles[SER_UART0].status |= USR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
297
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.
301          */
302         char c = UDR;
303
304         if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
305                 ser_handles[SER_UART0].status |= SERRF_RXFIFOOVERRUN;
306         else
307         {
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))
311                         RTS_OFF;
312 #endif
313         }
314 }
315
316 /*!
317  * Serial 1 RX complete interrupt handler
318  */
319 #ifndef __AVR_ATmega103__
320 SIGNAL(SIG_UART1_RECV)
321 {
322         /* Should be read before UDR */
323         ser_handles[SER_UART1].status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
324
325         /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
326          * not going to accept the incoming data
327          */
328         char c = UDR1;
329
330         if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
331                 ser_handles[SER_UART1].status |= SERRF_RXFIFOOVERRUN;
332         else
333         {
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))
337                         RTS_OFF;
338 #endif
339         }
340 }
341 #endif /* !__AVR_ATmega103__ */
342
343
344 /*
345  * SPI Flag: true if we are transmitting/receiving with the SPI.
346  *
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.
352  */
353 static volatile bool spi_sending = false;
354
355 static void spi_starttx(UNUSED(struct SerialHardware *ctx))
356 {
357         cpuflags_t flags;
358
359         DISABLE_IRQSAVE(flags);
360
361         /* Send data only if the SPI is not already transmitting */
362         if (!spi_sending && !fifo_isempty(&ser_handles[SER_SPI].txfifo))
363         {
364                 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
365                 spi_sending = true;
366         }
367
368         ENABLE_IRQRESTORE(flags);
369 }
370
371 /*!
372  * SPI interrupt handler
373  */
374 SIGNAL(SIG_SPI)
375 {
376         /* Read incoming byte. */
377         if (!fifo_isfull(&ser_handles[SER_SPI].rxfifo))
378                 fifo_push(&ser_handles[SER_SPI].rxfifo, SPDR);
379         /*
380          * FIXME
381         else
382                 ser_handles[SER_SPI].status |= SERRF_RXFIFOOVERRUN;
383         */
384
385         /* Send */
386         if (!fifo_isempty(&ser_handles[SER_SPI].txfifo))
387                 SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
388         else
389                 spi_sending = false;
390 }
391
392
393 /*
394
395 #pragma vector = UART_TXC_vect
396 __interrupt void UART_TXC_interrupt(void)
397 {
398   UCSRB &= ~TXCIE;
399   ReceiveMode();
400   UCSRB = RXCIE | RXEN | TXEN;  //Abilito l'Interrupt in ricezione e RX e TX
401 }
402 */
403
404
405 static const struct SerialHardwareVT UART0_VT =
406 {
407         .init = uart0_init,
408         .cleanup = uart0_cleanup,
409         .setbaudrate = uart0_setbaudrate,
410         .setparity = uart0_setparity,
411         .enabletxirq = uart0_enabletxirq,
412 };
413
414 static const struct SerialHardwareVT UART1_VT =
415 {
416         .init = uart1_init,
417         .cleanup = uart1_cleanup,
418         .setbaudrate = uart1_setbaudrate,
419         .setparity = uart1_setparity,
420         .enabletxirq = uart1_enabletxirq,
421 };
422
423 static const struct SerialHardwareVT SPI_VT =
424 {
425         .init = spi_init,
426         .cleanup = spi_cleanup,
427         .enabletxirq = spi_starttx,
428 };
429
430 static struct AvrSerial UARTDescs[SER_CNT] =
431 {
432         {
433                 .hw = { .table = &UART0_VT },
434         },
435
436         {
437                 .hw = { .table = &UART1_VT },
438         },
439
440         {
441                 .hw = { .table = &SPI_VT },
442         },
443 };
444
445 struct SerialHardware* ser_hw_getdesc(int unit)
446 {
447         ASSERT(unit < SER_CNT);
448         return &UARTDescs[unit].hw;
449 }