]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/usart.c
600a4f2b0e3bcb5866921f5b509be73db2ed4d74
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D2x_Xplained_IAR / AtmelFiles / drivers / peripherals / usart.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2015, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 /** \addtogroup usart_module Working with USART\r
31  * \section Purpose\r
32  * The USART driver provides the interface to configure and use the USART peripheral.\n\r
33  *\r
34  * The USART supports several kinds of communication modes such as full-duplex asynchronous/\r
35  * synchronous serial communication,RS485 with driver control signal,ISO7816,SPI and Test modes.\r
36  *\r
37  * To start a USART transfer with \ref dmad_module "DMA" support, the user could follow these steps:\r
38  * <ul>\r
39  * <li> Configure USART with expected mode and baudrate(see \ref usart_configure), which could be done by:\r
40  * -# Resetting and disabling transmitter and receiver by setting US_CR(Control Register). </li>\r
41  * -# Configuring the USART in a specific mode by setting USART_MODE bits in US_MR(Mode Register) </li>\r
42  * -# Setting baudrate which is different from mode to mode.\r
43    </li>\r
44  * <li> Enable transmitter or receiver respectively by set US_CR_TXEN or US_CR_RXEN in US_CR.</li>\r
45  * <li> Read from or write to the peripheral with  \ref dmad_module </li>\r
46  * </ul>\r
47  *\r
48  * \section Usage\r
49  * <ul>\r
50  * <li>  Enable or disable USART transmitter or receiver using\r
51  * usart_set_transmitter_enabled() and usart_set_receiver_enabled().\r
52  * <li>  Enable or disable USART interrupt using usart_enable_it() or usart_disable_it().\r
53  * </li>\r
54  * </ul>\r
55  *\r
56  * For more accurate information, please look at the USART section of the\r
57  * Datasheet.\r
58  *\r
59  * Related files :\n\r
60  * \ref usart.c\n\r
61  * \ref usart.h\n\r
62 */\r
63 \r
64 /**\r
65  * \file\r
66  *\r
67  * Implementation of USART (Universal Synchronous Asynchronous Receiver Transmitter)\r
68  * controller.\r
69  *\r
70  */\r
71 /*-----------------------------------------------------------------------------\r
72 *         Headers\r
73  *---------------------------------------------------------------------------*/\r
74 \r
75 #include "chip.h"\r
76 #include "compiler.h"\r
77 #include "peripherals/usart.h"\r
78 #include "peripherals/pmc.h"\r
79 \r
80 #include "trace.h"\r
81 #include "io.h"\r
82 \r
83 #include <assert.h>\r
84 #include <string.h>\r
85 \r
86 /*-----------------------------------------------------------------------------\r
87 *\r
88  *---------------------------------------------------------------------------*/\r
89 \r
90 #ifdef CONFIG_HAVE_USART_FIFO\r
91 /* Clear FIFO related register if present. Dummy function otherwise. */\r
92 static inline void _clear_fifo_control_flags(uint32_t* control_reg)\r
93 {\r
94         *control_reg |= US_CR_FIFODIS | US_CR_TXFCLR | US_CR_RXFCLR | US_CR_TXFLCLR;\r
95 }\r
96 #else\r
97 #define _clear_fifo_control_flags(dummy) do {} while(0)\r
98 #endif\r
99 \r
100 /* The CD value scope programmed in MR register. */\r
101 #define MIN_CD_VALUE                  0x01\r
102 #define MIN_CD_VALUE_SPI              0x04\r
103 #define MAX_CD_VALUE                  US_BRGR_CD_Msk\r
104 \r
105 /* The receiver sampling divide of baudrate clock. */\r
106 #define HIGH_FRQ_SAMPLE_DIV           16\r
107 #define LOW_FRQ_SAMPLE_DIV            8\r
108 \r
109 /*----------------------------------------------------------------------------\r
110  *         Exported functions\r
111  *----------------------------------------------------------------------------*/\r
112 \r
113 /**\r
114  * \brief Reset status bits (PARE, OVER, MANERR, UNRE and PXBRK in US_CSR).\r
115  *\r
116  * \param usart Pointer to a USART instance.\r
117  */\r
118 void usart_reset_status(Usart *usart)\r
119 {\r
120         usart->US_CR = US_CR_RSTSTA;\r
121 }\r
122 \r
123 \r
124 /**\r
125  * \brief Configures an USART peripheral with the specified parameters.\r
126  *  \param usart  Pointer to the USART peripheral to configure.\r
127  *  \param mode  Desired value for the USART mode register (see the datasheet).\r
128  *  \param baudrate  Baudrate at which the USART should operate (in Hz).\r
129  *  \param clock  Frequency of the system master clock (in Hz).\r
130  */\r
131 void usart_configure(Usart *usart, uint32_t mode, uint32_t baudrate)\r
132 {\r
133         uint32_t clock = pmc_get_peripheral_clock(get_usart_id_from_addr(usart));\r
134         /* Reset and disable receiver & transmitter */\r
135         uint32_t control = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS;\r
136         /* Reset and disable FIFO if present */\r
137         _clear_fifo_control_flags(&control);\r
138         /* apply */\r
139         usart->US_CR = control;\r
140         /* Configure mode */\r
141         usart->US_MR = mode;\r
142 \r
143         /* Configure baudrate */\r
144         /* Asynchronous, no oversampling */\r
145         if (((mode & US_MR_SYNC) == 0) && ((mode & US_MR_OVER) == 0)) {\r
146                 usart->US_BRGR = (clock / baudrate) / 16;\r
147         }\r
148 #ifdef CONFIG_HAVE_USART_SPI_MODE\r
149         if (((mode & US_MR_USART_MODE_SPI_MASTER) ==\r
150              US_MR_USART_MODE_SPI_MASTER) || ((mode & US_MR_SYNC) == US_MR_SYNC)) {\r
151                 if ((mode & US_MR_USCLKS_Msk) == US_MR_USCLKS_MCK) {\r
152                         usart->US_BRGR = clock / baudrate;\r
153                 } else {\r
154                         if ((mode & US_MR_USCLKS_DIV) == US_MR_USCLKS_DIV) {\r
155                                 usart->US_BRGR = clock / baudrate / 8;\r
156                         }\r
157                 }\r
158         }\r
159 #endif /* CONFIG_HAVE_USART_SPI_MODE */\r
160 \r
161         /* TODO other modes */\r
162 \r
163         /* Disable all interrupts */\r
164         usart->US_IDR = 0xFFFFFFFF;\r
165         /* Enable receiver and transmitter */\r
166         usart->US_CR = US_CR_RXEN | US_CR_TXEN;\r
167 }\r
168 \r
169 /**\r
170  * \brief   Get present status\r
171  * \param usart  Pointer to an USART peripheral.\r
172  */\r
173 uint32_t usart_get_status(Usart *usart)\r
174 {\r
175         return usart->US_CSR;\r
176 }\r
177 \r
178 /**\r
179  * \brief   Enable interrupt\r
180  * \param usart  Pointer to an USART peripheral.\r
181  * \param mode  Interrupt mode.\r
182  */\r
183 void usart_enable_it(Usart *usart, uint32_t mode)\r
184 {\r
185         usart->US_IER = mode;\r
186 }\r
187 \r
188 /**\r
189  * \brief   Disable interrupt\r
190  * \param usart  Pointer to an USART peripheral.\r
191  * \param mode  Interrupt mode.\r
192  */\r
193 void usart_disable_it(Usart *usart, uint32_t mode)\r
194 {\r
195         usart->US_IDR = mode;\r
196 }\r
197 \r
198 /**\r
199  * \brief   Return interrupt mask\r
200  * \param usart  Pointer to an USART peripheral.\r
201  */\r
202 uint32_t usart_get_it_mask(Usart *usart)\r
203 {\r
204         return usart->US_IMR;\r
205 }\r
206 \r
207 /**\r
208  * \brief Enables or disables the transmitter of an USART peripheral.\r
209  * \param usart  Pointer to an USART peripheral\r
210  * \param enabled  If true, the transmitter is enabled; otherwise it is\r
211  *                disabled.\r
212  */\r
213 void usart_set_transmitter_enabled(Usart *usart, uint8_t enabled)\r
214 {\r
215         if (enabled) {\r
216                 usart->US_CR = US_CR_TXEN;\r
217         } else {\r
218                 usart->US_CR = US_CR_TXDIS;\r
219         }\r
220 }\r
221 \r
222 /**\r
223  * \brief Enables or disables the receiver of an USART peripheral\r
224  * \param usart  Pointer to an USART peripheral\r
225  * \param enabled  If true, the receiver is enabled; otherwise it is disabled.\r
226  */\r
227 void usart_set_receiver_enabled(Usart *usart, uint8_t enabled)\r
228 {\r
229         if (enabled) {\r
230                 usart->US_CR = US_CR_RXEN;\r
231         } else {\r
232                 usart->US_CR = US_CR_RXDIS;\r
233         }\r
234 }\r
235 \r
236 /**\r
237  * \brief Enables or disables the Request To Send (RTS) of an USART peripheral\r
238  * \param usart  Pointer to an USART peripheral\r
239  * \param enabled  If true, the RTS is enabled (0); otherwise it is disabled.\r
240  */\r
241 void usart_set_rts_enabled(Usart *usart, uint8_t enabled)\r
242 {\r
243         if (enabled) {\r
244                 usart->US_CR = US_CR_RTSEN;\r
245         } else {\r
246                 usart->US_CR = US_CR_RTSDIS;\r
247         }\r
248 }\r
249 \r
250 /**\r
251  * \brief Immediately stop and disable USART transmitter.\r
252  *\r
253  * \param usart Pointer to a USART instance.\r
254  */\r
255 void usart_reset_tx(Usart *usart)\r
256 {\r
257         /* Reset transmitter */\r
258         usart->US_CR = US_CR_RSTTX | US_CR_TXDIS;\r
259 }\r
260 \r
261 /**\r
262  * \brief Configure the transmit timeguard register.\r
263  *\r
264  * \param usart Pointer to a USART instance.\r
265  * \param timeguard The value of transmit timeguard.\r
266  */\r
267 void usart_set_tx_timeguard(Usart *usart, uint32_t timeguard)\r
268 {\r
269         usart->US_TTGR = timeguard;\r
270 }\r
271 \r
272 /**\r
273  * \brief Immediately stop and disable USART receiver.\r
274  *\r
275  * \param usart Pointer to a USART instance.\r
276  */\r
277 void usart_reset_rx(Usart *usart)\r
278 {\r
279         /* Reset Receiver */\r
280         usart->US_CR = US_CR_RSTRX | US_CR_RXDIS;\r
281 }\r
282 \r
283 /**\r
284  * \brief Configure the receive timeout register.\r
285  *\r
286  * \param usart Pointer to a USART instance.\r
287  * \param timeout The value of receive timeout.\r
288  */\r
289 void usart_set_rx_timeout(Usart *usart, uint32_t timeout)\r
290 {\r
291         usart->US_RTOR = timeout;\r
292 }\r
293 \r
294 \r
295 /**\r
296  * \brief Start transmission of a break.\r
297  *\r
298  * \param usart Pointer to a USART instance.\r
299  */\r
300 void usart_start_tx_break(Usart *usart)\r
301 {\r
302         usart->US_CR = US_CR_STTBRK;\r
303 }\r
304 \r
305 /**\r
306  * \brief Stop transmission of a break.\r
307  *\r
308  * \param usart Pointer to a USART instance.\r
309  */\r
310 void usart_stop_tx_break(Usart *usart)\r
311 {\r
312         usart->US_CR = US_CR_STPBRK;\r
313 }\r
314 \r
315 /**\r
316  * \brief Start waiting for a character before clocking the timeout count.\r
317  * Reset the status bit TIMEOUT in US_CSR.\r
318  *\r
319  * \param usart Pointer to a USART instance.\r
320  */\r
321 void usart_start_rx_timeout(Usart *usart)\r
322 {\r
323         usart->US_CR = US_CR_STTTO;\r
324 }\r
325 \r
326 /**\r
327  * \brief Reset the ITERATION in US_CSR when the ISO7816 mode is enabled.\r
328  *\r
329  * \param usart Pointer to a USART instance.\r
330  */\r
331 void usart_reset_iterations(Usart *usart)\r
332 {\r
333         usart->US_CR = US_CR_RSTIT;\r
334 }\r
335 \r
336 /**\r
337  * \brief Reset NACK in US_CSR.\r
338  *\r
339  * \param usart Pointer to a USART instance.\r
340  */\r
341 void usart_reset_nack(Usart *usart)\r
342 {\r
343         usart->US_CR = US_CR_RSTNACK;\r
344 }\r
345 \r
346 /**\r
347  * \brief Restart the receive timeout.\r
348  *\r
349  * \param usart Pointer to a USART instance.\r
350  */\r
351 void usart_restart_rx_timeout(Usart *usart)\r
352 {\r
353         usart->US_CR = US_CR_RETTO;\r
354 }\r
355 \r
356 /**\r
357  * \brief Sends one packet of data through the specified USART peripheral. This\r
358  * function operates synchronously, so it only returns when the data has been\r
359  * actually sent.\r
360  * \param usart  Pointer to an USART peripheral.\r
361  * \param data  Data to send including 9nth bit and sync field if necessary (in\r
362  *        the same format as the US_THR register in the datasheet).\r
363  * \param timeout  Time out value (0 = no timeout).\r
364  */\r
365 void usart_write(Usart *usart, uint16_t data, volatile uint32_t timeout)\r
366 {\r
367         if (timeout == 0) {\r
368                 while ((usart->US_CSR & US_CSR_TXRDY) == 0) ;\r
369         } else {\r
370                 while ((usart->US_CSR & US_CSR_TXRDY) == 0) {\r
371                         if (timeout == 0) {\r
372                                 trace_error("usart_write: Timed out.\n\r");\r
373                                 return;\r
374                         }\r
375                         timeout--;\r
376                 }\r
377         }\r
378         usart->US_THR = data;\r
379 }\r
380 \r
381 /**\r
382  * \brief  Reads and return a packet of data on the specified USART peripheral. This\r
383  * function operates asynchronously, so it waits until some data has been\r
384  * received.\r
385  * \param usart  Pointer to an USART peripheral.\r
386  * \param timeout  Time out value (0 -> no timeout).\r
387  */\r
388 uint16_t usart_read(Usart *usart, volatile uint32_t timeout)\r
389 {\r
390         if (timeout == 0) {\r
391                 while ((usart->US_CSR & US_CSR_RXRDY) == 0) ;\r
392         } else {\r
393                 while ((usart->US_CSR & US_CSR_RXRDY) == 0) {\r
394                         if (timeout == 0) {\r
395                                 trace_error("usart_read: Timed out.\n\r");\r
396                                 return 0;\r
397                         }\r
398                         timeout--;\r
399                 }\r
400         }\r
401         return usart->US_RHR;\r
402 }\r
403 \r
404 /**\r
405  * \brief  Returns 1 if some data has been received and can be read from an USART;\r
406  * otherwise returns 0.\r
407  * \param usart  Pointer to an USART instance.\r
408  */\r
409 uint8_t usart_is_data_available(Usart *usart)\r
410 {\r
411         if ((usart->US_CSR & US_CSR_RXRDY) != 0) {\r
412                 return 1;\r
413         } else {\r
414                 return 0;\r
415         }\r
416 }\r
417 \r
418 /**\r
419  * \brief   Return 1 if a character can be read in USART\r
420  * \param usart  Pointer to an USART peripheral.\r
421  */\r
422 uint32_t usart_is_rx_ready(Usart *usart)\r
423 {\r
424         return (usart->US_CSR & US_CSR_RXRDY);\r
425 }\r
426 \r
427 /**\r
428  * \brief   Return 1 if a character send in USART\r
429  * \param usart  Pointer to an USART peripheral.\r
430  */\r
431 uint32_t usart_is_tx_ready(Usart *usart)\r
432 {\r
433         return (usart->US_CSR & US_CSR_TXRDY);\r
434 }\r
435 \r
436 /**\r
437  * \brief  Sends one packet of data through the specified USART peripheral. This\r
438  * function operates synchronously, so it only returns when the data has been\r
439  * actually sent.\r
440  * \param usart  Pointer to an USART peripheral.\r
441  * \param c  Character to send\r
442  */\r
443 void usart_put_char(Usart *usart, uint8_t c)\r
444 {\r
445         /* Wait for the transmitter to be ready */\r
446         while ((usart->US_CSR & US_CSR_TXEMPTY) == 0) ;\r
447         /* Send character */\r
448         /* Force an octet write to avoid race conditions with FIFO mode */\r
449         writeb(&usart->US_THR, c);\r
450 }\r
451 \r
452 /**\r
453  * \brief  Reads and returns a character from the USART.\r
454  * \note This function is synchronous (i.e. uses polling).\r
455  * \param usart  Pointer to an USART peripheral.\r
456  * \return Character received.\r
457  */\r
458 uint8_t usart_get_char(Usart *usart)\r
459 {\r
460         while ((usart->US_CSR & US_CSR_RXRDY) == 0) ;\r
461         /* Force an octet read to avoid race conditions with FIFO mode */\r
462         uint8_t v;\r
463         readb(&usart->US_RHR, &v);\r
464         return v;\r
465 }\r
466 \r
467 /**\r
468  * \brief  Sets the filter value for the IRDA demodulator.\r
469  * \param usart  Pointer to an USART instance.\r
470  * \param filter  Filter value.\r
471  */\r
472 void usart_set_irda_filter(Usart *usart, uint8_t filter)\r
473 {\r
474         assert(usart != NULL);\r
475 \r
476         usart->US_IF = filter;\r
477         /* Set IrDA mode. */\r
478         usart->US_MR = (usart->US_MR & ~US_MR_USART_MODE_Msk) | US_MR_USART_MODE_IRDA;\r
479 }\r
480 \r
481 /**\r
482  * \brief Select the SCK pin as the source of baud rate for the USART\r
483  * synchronous slave modes.\r
484  *\r
485  * \param usart Pointer to a USART instance.\r
486  */\r
487 void usart_set_sync_slave_baudrate(Usart *usart)\r
488 {\r
489         usart->US_MR = (usart->US_MR & ~US_MR_USCLKS_Msk) | US_MR_USCLKS_SCK | US_MR_SYNC;\r
490 }\r
491 \r
492 /**\r
493  * \brief Calculate a clock divider (\e CD) for the USART SPI master mode to\r
494  * generate a baud rate as close as possible to the baud rate set point.\r
495  *\r
496  * \note Baud rate calculation:\r
497  * \f$ Baudrate = \frac{SelectedClock}{CD} \f$.\r
498  *\r
499  * \param usart Pointer to a USART instance.\r
500  * \param baudrate Baud rate set point.\r
501  *\r
502  * \retval 0 Baud rate is successfully initialized.\r
503  * \retval 1 Baud rate set point is out of range for the given input clock\r
504  * frequency.\r
505  */\r
506 uint32_t usart_set_spi_master_baudrate(Usart *usart, uint32_t baudrate)\r
507 {\r
508         uint32_t cd;\r
509         uint32_t clock = pmc_get_peripheral_clock(get_usart_id_from_addr(usart));\r
510 \r
511         /* Calculate the clock divider according to the formula in SPI mode. */\r
512         cd = (clock + baudrate / 2) / baudrate;\r
513         if (cd < MIN_CD_VALUE_SPI || cd > MAX_CD_VALUE) {\r
514                 return 1;\r
515         }\r
516         usart->US_BRGR = cd << US_BRGR_CD_Pos;\r
517         return 0;\r
518 }\r
519 \r
520 /**\r
521  * \brief Select the SCK pin as the source of baudrate for the USART SPI slave\r
522  * mode.\r
523  *\r
524  * \param usart Pointer to a USART instance.\r
525  */\r
526 void usart_set_spi_slave_baudrate(Usart *usart)\r
527 {\r
528         usart->US_MR &= ~US_MR_USCLKS_Msk;\r
529         usart->US_MR |= US_MR_USCLKS_SCK;\r
530 }\r
531 \r
532 /**\r
533  * \brief Configure USART to work in hardware handshaking mode.\r
534  *\r
535  * \note By default, the transmitter and receiver aren't enabled.\r
536  *\r
537  * \param usart Pointer to a USART instance.\r
538  *\r
539  * \retval 0 on success.\r
540  * \retval 1 on failure.\r
541  */\r
542 uint32_t usart_init_hw_handshaking(Usart *usart)\r
543 {\r
544         /* The USART should be initialized first as standard RS232. */\r
545         /* Set hardware handshaking mode. */\r
546         usart->US_MR = (usart->US_MR & ~US_MR_USART_MODE_Msk) | US_MR_USART_MODE_HW_HANDSHAKING;\r
547         return 0;\r
548 }\r
549 \r
550 /**\r
551  * \brief Calculate a clock divider(CD) and a fractional part (FP) for the\r
552  * USART asynchronous modes to generate a baudrate as close as possible to\r
553  * the baudrate set point.\r
554  *\r
555  * \note Baud rate calculation: Baudrate = mck/(Over * (CD + FP/8))\r
556  * (Over being 16 or 8). The maximal oversampling is selected if it allows to\r
557  * generate a baudrate close to the set point.\r
558  *\r
559  * \param usart Pointer to a USART instance.\r
560  * \param baudrate Baud rate set point.\r
561  *\r
562  * \retval 0 Baud rate is successfully initialized.\r
563  * \retval 1 Baud rate set point is out of range for the given input clock\r
564  * frequency.\r
565  */\r
566 uint32_t usart_set_async_baudrate(Usart *usart, uint32_t baudrate)\r
567 {\r
568         uint32_t over, cd_fp, cd, fp;\r
569         uint32_t mck;\r
570 \r
571         /* get peripheral clock */\r
572         mck = pmc_get_peripheral_clock(get_usart_id_from_addr(usart));\r
573 \r
574         /* Calculate the receiver sampling divide of baudrate clock. */\r
575         if (mck >= HIGH_FRQ_SAMPLE_DIV * baudrate) {\r
576                 over = HIGH_FRQ_SAMPLE_DIV;\r
577         } else {\r
578                 over = LOW_FRQ_SAMPLE_DIV;\r
579         }\r
580 \r
581         /* Calculate clock divider according to the fraction calculated formula. */\r
582         cd_fp = (8 * mck + (over * baudrate) / 2) / (over * baudrate);\r
583         cd = cd_fp >> 0x03;\r
584         fp = cd_fp & 0x07;\r
585         if (cd < MIN_CD_VALUE || cd > MAX_CD_VALUE) {\r
586                 return 1;\r
587         }\r
588 \r
589         /* Configure the OVER bit in MR register. */\r
590         if (over == 8) {\r
591                 usart->US_MR |= US_MR_OVER;\r
592         }\r
593 \r
594         /* Configure the baudrate generate register. */\r
595         usart->US_BRGR = (cd << US_BRGR_CD_Pos) | (fp << US_BRGR_FP_Pos);\r
596 \r
597         return 0;\r
598 }\r
599 \r
600 /*-----------------------------------------------------------------------------\r
601 *        Functions if FIFO are used\r
602  *---------------------------------------------------------------------------*/\r
603 \r
604 #ifdef CONFIG_HAVE_USART_FIFO\r
605 /**\r
606  * \brief Configure the FIFO of USART device\r
607  *\r
608  * \param usart Pointer to an USART instance.\r
609  * \param tx_thres\r
610  * \param rx_down_thres\r
611  * \param rx_up_thres\r
612  * \param ready_modes\r
613  */\r
614 void usart_fifo_configure(Usart *usart, uint8_t tx_thres,\r
615                           uint8_t rx_down_thres, uint8_t rx_up_thres,\r
616                           uint32_t ready_modes)\r
617 {\r
618         /* Disable transmitter & receiver */\r
619         usart->US_CR = US_CR_RXDIS | US_CR_TXDIS;\r
620         /* Enable FIFO */\r
621         usart->US_CR = US_CR_FIFOEN;\r
622         /* Configure FIFO */\r
623         usart->US_FMR = US_FMR_TXFTHRES(tx_thres) | US_FMR_RXFTHRES(rx_down_thres)\r
624                 | US_FMR_RXFTHRES2(rx_up_thres) | ready_modes;\r
625 \r
626         /* Disable all fifo related interrupts */\r
627         usart->US_FIDR = 0xFFFFFFFF;\r
628 \r
629         /* Reenable receiver & transmitter */\r
630         usart->US_CR = US_CR_RXEN | US_CR_TXEN;\r
631 }\r
632 \r
633 /**\r
634  * \brief Disable the FIFO mode from the USART device\r
635  *\r
636  * \param usart Pointer to an USART instance.\r
637  * \note receiver and transmitter are reenabled.\r
638  */\r
639 void usart_fifo_disable(Usart *usart)\r
640 {\r
641         /* Reset and disable receiver & transmitter */\r
642         uint32_t control = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS;\r
643         /* clear and disable FIFO */\r
644         _clear_fifo_control_flags(&control);\r
645         /* apply */\r
646         usart->US_CR = control;\r
647 \r
648         /* Reenable receiver & transmitter */\r
649         usart->US_CR = US_CR_RXEN | US_CR_TXEN;\r
650 }\r
651 \r
652 /**\r
653  * \brief Enable FIFO related interrupts according to the given mask\r
654  *\r
655  * \param usart Pointer to an USART instance.\r
656  * \param interrupt_mask The mask to apply\r
657  */\r
658 void usart_fifo_enable_it(Usart *usart, uint32_t interrupt_mask)\r
659 {\r
660         usart->US_FIER = interrupt_mask;\r
661 }\r
662 \r
663 /**\r
664  * \brief Disable FIFO related interrupts according to the given mask\r
665  *\r
666  * \param usart Pointer to an USART instance.\r
667  * \param interrupt_mask The mask to apply\r
668  */\r
669 void usart_fifo_disable_it(Usart *usart, uint32_t interrupt_mask)\r
670 {\r
671         usart->US_FIDR = interrupt_mask;\r
672 }\r
673 \r
674 /**\r
675  * \brief Retrive FIFO related interrupt mask.\r
676  *\r
677  * \param usart Pointer to an USART instance.\r
678  * \return current FIFO interrupt mask.\r
679  */\r
680 uint32_t usart_fifo_get_interrupts(Usart *usart)\r
681 {\r
682         return usart->US_FIMR;\r
683 }\r
684 \r
685 \r
686 /**\r
687  * \brief Get the size occupied in the input FIFO of USART device.\r
688  *\r
689  * \param usart Pointer to an USART instance.\r
690  * \return Size occupied in the input FIFO (not read yet) in octet\r
691  */\r
692 uint32_t usart_fifo_rx_size(Usart *usart)\r
693 {\r
694         return (usart->US_FLR & US_FLR_RXFL_Msk) >> US_FLR_RXFL_Pos;\r
695 }\r
696 \r
697 /**\r
698  * \brief Get the size occupied in the ouput FIFO of USART device.\r
699  *\r
700  * \param usart Pointer to an USART instance.\r
701  * \return Size occupied in the output FIFO (not sent yet) in octet\r
702  */\r
703 uint32_t usart_fifo_tx_size(Usart *usart)\r
704 {\r
705         return (usart->US_FLR & US_FLR_TXFL_Msk) >> US_FLR_TXFL_Pos;\r
706 }\r
707 \r
708 /**\r
709  * \brief Reads from USART device input channel until the specified length is\r
710  * reached.\r
711  *\r
712  * \param usart Pointer to an USART instance.\r
713  * \param stream Pointer to the receive buffer.\r
714  * \param len Size of the receive buffer, in octets.\r
715  *\r
716  * \return Number of read octets\r
717  *\r
718  * \warning WORKS ONLY IN LITTLE ENDIAN MODE!\r
719  *\r
720  * \note The FIFO must be configured before using this function.\r
721  * \note In case of a TIMEOUT or a BREAK, a null character is appended to the\r
722  * buffer and the returned value should be inferior to \ref len.\r
723  */\r
724 uint32_t usart_read_stream(Usart *usart, void *stream, uint32_t len)\r
725 {\r
726         uint8_t* buffer = stream;\r
727         uint32_t left = len;\r
728         while (left > 0) {\r
729                 /* Stop reception if a timeout or break occur */\r
730                 if ((usart->US_CSR & (US_CSR_TIMEOUT | US_CSR_RXBRK)) != 0) {\r
731                         *buffer = '\0';\r
732                         break;\r
733                 }\r
734 \r
735                 if ((usart->US_CSR & US_CSR_RXRDY) == 0) continue;\r
736 \r
737                 /* Get FIFO size (in octets) and clamp it */\r
738                 uint32_t buf_size = usart_fifo_rx_size(usart);\r
739                 buf_size = buf_size > left ? left : buf_size;\r
740 \r
741                 /* Fill the buffer as must as possible with four data reads */\r
742                 while (buf_size >= sizeof(uint32_t)) {\r
743                         *(uint32_t*)buffer = usart->US_RHR;\r
744                         buffer += sizeof(uint32_t);\r
745                         left -= sizeof(uint32_t);\r
746                         buf_size -= sizeof(uint32_t);\r
747                 }\r
748                 /* Add tail data if stream is not 4 octet aligned */\r
749                 if (buf_size >= sizeof(uint16_t)) {\r
750                         /* two data read */\r
751                         readhw(&usart->US_RHR, (uint16_t*)buffer);\r
752                         left -= sizeof(uint16_t);\r
753                         buffer += sizeof(uint16_t);\r
754                         buf_size -= sizeof(uint16_t);\r
755                 }\r
756                 if (buf_size >= sizeof(uint8_t)) {\r
757                         /* one data read */\r
758                         readb(&usart->US_RHR, buffer);\r
759                         buffer += sizeof(uint8_t);\r
760                         left -= sizeof(uint8_t);\r
761                         buf_size -= sizeof(uint8_t);\r
762                 }\r
763         }\r
764         return len - left;\r
765 }\r
766 \r
767 /**\r
768  * \brief Writes given data to USART device output channel until the specified\r
769  * length is reached.\r
770  *\r
771  * \param usart Pointer to an USART instance.\r
772  * \param stream Pointer to the data to send.\r
773  * \param len Size of the data to send, in octets.\r
774  *\r
775  * \return Number of written octets\r
776  *\r
777  * \warning WORKS ONLY IN LITTLE ENDIAN MODE!\r
778  *\r
779  * \note The FIFO must be configured before using this function.\r
780  * \note This function do not wait for the FIFO to be empty.\r
781  * \note In case of a TIMEOUT the transmission is aborted and the returned value\r
782  * should be inferior to \ref len.\r
783  */\r
784 uint32_t usart_write_stream(Usart *usart, const void *stream, uint32_t len)\r
785 {\r
786         const uint8_t* buffer = stream;\r
787         uint32_t left = len;\r
788         int32_t fifo_size = get_peripheral_fifo_depth(usart);\r
789         if (fifo_size < 0)\r
790                 return 0;\r
791 \r
792         while (left > 0) {\r
793                 if ((usart->US_CSR & US_CSR_TXRDY) == 0) continue;\r
794 \r
795                 /* Get FIFO free size (int octet) and clamp it */\r
796                 uint32_t buf_size = fifo_size - usart_fifo_tx_size(usart);\r
797                 buf_size = buf_size > left ? left : buf_size;\r
798 \r
799                 /* Fill the FIFO as must as possible with four data writes */\r
800                 while (buf_size >= sizeof(uint32_t)) {\r
801                         usart->US_THR = *(uint32_t*)buffer;\r
802                         buffer += sizeof(uint32_t);\r
803                         left -= sizeof(uint32_t);\r
804                         buf_size -= sizeof(uint32_t);\r
805                 }\r
806                 /* Add tail data if stream is not 4 octet aligned */\r
807                 if (buf_size >= sizeof(uint16_t)) {\r
808                         /* two data write */\r
809                         writehw(&usart->US_THR, *(uint16_t*)buffer);\r
810                         buffer += sizeof(uint16_t);\r
811                         left -= sizeof(uint16_t);\r
812                         buf_size -= sizeof(uint16_t);\r
813                 }\r
814                 if (buf_size >= sizeof(uint8_t)) {\r
815                         /* one data write */\r
816                         writeb(&usart->US_THR, *buffer);\r
817                         buffer += sizeof(uint8_t);\r
818                         left -= sizeof(uint8_t);\r
819                         buf_size -= sizeof(uint8_t);\r
820                 }\r
821         }\r
822         return len - left;\r
823 }\r
824 \r
825 #endif\r