1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2015, Atmel Corporation
\r
6 * All rights reserved.
\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
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\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
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
30 /** \addtogroup usart_module Working with USART
\r
32 * The USART driver provides the interface to configure and use the USART peripheral.\n
\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
37 * To start a USART transfer with \ref dmad_module "DMA" support, the user could follow these steps:
\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
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
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
56 * For more accurate information, please look at the USART section of the
\r
67 * Implementation of USART (Universal Synchronous Asynchronous Receiver Transmitter)
\r
71 /*-----------------------------------------------------------------------------
\r
73 *---------------------------------------------------------------------------*/
\r
76 #include "compiler.h"
\r
77 #include "peripherals/usart.h"
\r
78 #include "peripherals/pmc.h"
\r
86 /*-----------------------------------------------------------------------------
\r
88 *---------------------------------------------------------------------------*/
\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
94 *control_reg |= US_CR_FIFODIS | US_CR_TXFCLR | US_CR_RXFCLR | US_CR_TXFLCLR;
\r
97 #define _clear_fifo_control_flags(dummy) do {} while(0)
\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
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
109 /*----------------------------------------------------------------------------
\r
110 * Exported functions
\r
111 *----------------------------------------------------------------------------*/
\r
114 * \brief Reset status bits (PARE, OVER, MANERR, UNRE and PXBRK in US_CSR).
\r
116 * \param usart Pointer to a USART instance.
\r
118 void usart_reset_status(Usart *usart)
\r
120 usart->US_CR = US_CR_RSTSTA;
\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
131 void usart_configure(Usart *usart, uint32_t mode, uint32_t baudrate)
\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
139 usart->US_CR = control;
\r
140 /* Configure mode */
\r
141 usart->US_MR = mode;
\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
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
154 if ((mode & US_MR_USCLKS_DIV) == US_MR_USCLKS_DIV) {
\r
155 usart->US_BRGR = clock / baudrate / 8;
\r
159 #endif /* CONFIG_HAVE_USART_SPI_MODE */
\r
161 /* TODO other modes */
\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
170 * \brief Get present status
\r
171 * \param usart Pointer to an USART peripheral.
\r
173 uint32_t usart_get_status(Usart *usart)
\r
175 return usart->US_CSR;
\r
179 * \brief Enable interrupt
\r
180 * \param usart Pointer to an USART peripheral.
\r
181 * \param mode Interrupt mode.
\r
183 void usart_enable_it(Usart *usart, uint32_t mode)
\r
185 usart->US_IER = mode;
\r
189 * \brief Disable interrupt
\r
190 * \param usart Pointer to an USART peripheral.
\r
191 * \param mode Interrupt mode.
\r
193 void usart_disable_it(Usart *usart, uint32_t mode)
\r
195 usart->US_IDR = mode;
\r
199 * \brief Return interrupt mask
\r
200 * \param usart Pointer to an USART peripheral.
\r
202 uint32_t usart_get_it_mask(Usart *usart)
\r
204 return usart->US_IMR;
\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
213 void usart_set_transmitter_enabled(Usart *usart, uint8_t enabled)
\r
216 usart->US_CR = US_CR_TXEN;
\r
218 usart->US_CR = US_CR_TXDIS;
\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
227 void usart_set_receiver_enabled(Usart *usart, uint8_t enabled)
\r
230 usart->US_CR = US_CR_RXEN;
\r
232 usart->US_CR = US_CR_RXDIS;
\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
241 void usart_set_rts_enabled(Usart *usart, uint8_t enabled)
\r
244 usart->US_CR = US_CR_RTSEN;
\r
246 usart->US_CR = US_CR_RTSDIS;
\r
251 * \brief Immediately stop and disable USART transmitter.
\r
253 * \param usart Pointer to a USART instance.
\r
255 void usart_reset_tx(Usart *usart)
\r
257 /* Reset transmitter */
\r
258 usart->US_CR = US_CR_RSTTX | US_CR_TXDIS;
\r
262 * \brief Configure the transmit timeguard register.
\r
264 * \param usart Pointer to a USART instance.
\r
265 * \param timeguard The value of transmit timeguard.
\r
267 void usart_set_tx_timeguard(Usart *usart, uint32_t timeguard)
\r
269 usart->US_TTGR = timeguard;
\r
273 * \brief Immediately stop and disable USART receiver.
\r
275 * \param usart Pointer to a USART instance.
\r
277 void usart_reset_rx(Usart *usart)
\r
279 /* Reset Receiver */
\r
280 usart->US_CR = US_CR_RSTRX | US_CR_RXDIS;
\r
284 * \brief Configure the receive timeout register.
\r
286 * \param usart Pointer to a USART instance.
\r
287 * \param timeout The value of receive timeout.
\r
289 void usart_set_rx_timeout(Usart *usart, uint32_t timeout)
\r
291 usart->US_RTOR = timeout;
\r
296 * \brief Start transmission of a break.
\r
298 * \param usart Pointer to a USART instance.
\r
300 void usart_start_tx_break(Usart *usart)
\r
302 usart->US_CR = US_CR_STTBRK;
\r
306 * \brief Stop transmission of a break.
\r
308 * \param usart Pointer to a USART instance.
\r
310 void usart_stop_tx_break(Usart *usart)
\r
312 usart->US_CR = US_CR_STPBRK;
\r
316 * \brief Start waiting for a character before clocking the timeout count.
\r
317 * Reset the status bit TIMEOUT in US_CSR.
\r
319 * \param usart Pointer to a USART instance.
\r
321 void usart_start_rx_timeout(Usart *usart)
\r
323 usart->US_CR = US_CR_STTTO;
\r
327 * \brief Reset the ITERATION in US_CSR when the ISO7816 mode is enabled.
\r
329 * \param usart Pointer to a USART instance.
\r
331 void usart_reset_iterations(Usart *usart)
\r
333 usart->US_CR = US_CR_RSTIT;
\r
337 * \brief Reset NACK in US_CSR.
\r
339 * \param usart Pointer to a USART instance.
\r
341 void usart_reset_nack(Usart *usart)
\r
343 usart->US_CR = US_CR_RSTNACK;
\r
347 * \brief Restart the receive timeout.
\r
349 * \param usart Pointer to a USART instance.
\r
351 void usart_restart_rx_timeout(Usart *usart)
\r
353 usart->US_CR = US_CR_RETTO;
\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
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
365 void usart_write(Usart *usart, uint16_t data, volatile uint32_t timeout)
\r
367 if (timeout == 0) {
\r
368 while ((usart->US_CSR & US_CSR_TXRDY) == 0) ;
\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
378 usart->US_THR = data;
\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
385 * \param usart Pointer to an USART peripheral.
\r
386 * \param timeout Time out value (0 -> no timeout).
\r
388 uint16_t usart_read(Usart *usart, volatile uint32_t timeout)
\r
390 if (timeout == 0) {
\r
391 while ((usart->US_CSR & US_CSR_RXRDY) == 0) ;
\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
401 return usart->US_RHR;
\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
409 uint8_t usart_is_data_available(Usart *usart)
\r
411 if ((usart->US_CSR & US_CSR_RXRDY) != 0) {
\r
419 * \brief Return 1 if a character can be read in USART
\r
420 * \param usart Pointer to an USART peripheral.
\r
422 uint32_t usart_is_rx_ready(Usart *usart)
\r
424 return (usart->US_CSR & US_CSR_RXRDY);
\r
428 * \brief Return 1 if a character send in USART
\r
429 * \param usart Pointer to an USART peripheral.
\r
431 uint32_t usart_is_tx_ready(Usart *usart)
\r
433 return (usart->US_CSR & US_CSR_TXRDY);
\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
440 * \param usart Pointer to an USART peripheral.
\r
441 * \param c Character to send
\r
443 void usart_put_char(Usart *usart, uint8_t c)
\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
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
458 uint8_t usart_get_char(Usart *usart)
\r
460 while ((usart->US_CSR & US_CSR_RXRDY) == 0) ;
\r
461 /* Force an octet read to avoid race conditions with FIFO mode */
\r
463 readb(&usart->US_RHR, &v);
\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
472 void usart_set_irda_filter(Usart *usart, uint8_t filter)
\r
474 assert(usart != NULL);
\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
482 * \brief Select the SCK pin as the source of baud rate for the USART
\r
483 * synchronous slave modes.
\r
485 * \param usart Pointer to a USART instance.
\r
487 void usart_set_sync_slave_baudrate(Usart *usart)
\r
489 usart->US_MR = (usart->US_MR & ~US_MR_USCLKS_Msk) | US_MR_USCLKS_SCK | US_MR_SYNC;
\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
496 * \note Baud rate calculation:
\r
497 * \f$ Baudrate = \frac{SelectedClock}{CD} \f$.
\r
499 * \param usart Pointer to a USART instance.
\r
500 * \param baudrate Baud rate set point.
\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
506 uint32_t usart_set_spi_master_baudrate(Usart *usart, uint32_t baudrate)
\r
509 uint32_t clock = pmc_get_peripheral_clock(get_usart_id_from_addr(usart));
\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
516 usart->US_BRGR = cd << US_BRGR_CD_Pos;
\r
521 * \brief Select the SCK pin as the source of baudrate for the USART SPI slave
\r
524 * \param usart Pointer to a USART instance.
\r
526 void usart_set_spi_slave_baudrate(Usart *usart)
\r
528 usart->US_MR &= ~US_MR_USCLKS_Msk;
\r
529 usart->US_MR |= US_MR_USCLKS_SCK;
\r
533 * \brief Configure USART to work in hardware handshaking mode.
\r
535 * \note By default, the transmitter and receiver aren't enabled.
\r
537 * \param usart Pointer to a USART instance.
\r
539 * \retval 0 on success.
\r
540 * \retval 1 on failure.
\r
542 uint32_t usart_init_hw_handshaking(Usart *usart)
\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
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
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
559 * \param usart Pointer to a USART instance.
\r
560 * \param baudrate Baud rate set point.
\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
566 uint32_t usart_set_async_baudrate(Usart *usart, uint32_t baudrate)
\r
568 uint32_t over, cd_fp, cd, fp;
\r
571 /* get peripheral clock */
\r
572 mck = pmc_get_peripheral_clock(get_usart_id_from_addr(usart));
\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
578 over = LOW_FRQ_SAMPLE_DIV;
\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
585 if (cd < MIN_CD_VALUE || cd > MAX_CD_VALUE) {
\r
589 /* Configure the OVER bit in MR register. */
\r
591 usart->US_MR |= US_MR_OVER;
\r
594 /* Configure the baudrate generate register. */
\r
595 usart->US_BRGR = (cd << US_BRGR_CD_Pos) | (fp << US_BRGR_FP_Pos);
\r
600 /*-----------------------------------------------------------------------------
\r
601 * Functions if FIFO are used
\r
602 *---------------------------------------------------------------------------*/
\r
604 #ifdef CONFIG_HAVE_USART_FIFO
\r
606 * \brief Configure the FIFO of USART device
\r
608 * \param usart Pointer to an USART instance.
\r
610 * \param rx_down_thres
\r
611 * \param rx_up_thres
\r
612 * \param ready_modes
\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
618 /* Disable transmitter & receiver */
\r
619 usart->US_CR = US_CR_RXDIS | US_CR_TXDIS;
\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
626 /* Disable all fifo related interrupts */
\r
627 usart->US_FIDR = 0xFFFFFFFF;
\r
629 /* Reenable receiver & transmitter */
\r
630 usart->US_CR = US_CR_RXEN | US_CR_TXEN;
\r
634 * \brief Disable the FIFO mode from the USART device
\r
636 * \param usart Pointer to an USART instance.
\r
637 * \note receiver and transmitter are reenabled.
\r
639 void usart_fifo_disable(Usart *usart)
\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
646 usart->US_CR = control;
\r
648 /* Reenable receiver & transmitter */
\r
649 usart->US_CR = US_CR_RXEN | US_CR_TXEN;
\r
653 * \brief Enable FIFO related interrupts according to the given mask
\r
655 * \param usart Pointer to an USART instance.
\r
656 * \param interrupt_mask The mask to apply
\r
658 void usart_fifo_enable_it(Usart *usart, uint32_t interrupt_mask)
\r
660 usart->US_FIER = interrupt_mask;
\r
664 * \brief Disable FIFO related interrupts according to the given mask
\r
666 * \param usart Pointer to an USART instance.
\r
667 * \param interrupt_mask The mask to apply
\r
669 void usart_fifo_disable_it(Usart *usart, uint32_t interrupt_mask)
\r
671 usart->US_FIDR = interrupt_mask;
\r
675 * \brief Retrive FIFO related interrupt mask.
\r
677 * \param usart Pointer to an USART instance.
\r
678 * \return current FIFO interrupt mask.
\r
680 uint32_t usart_fifo_get_interrupts(Usart *usart)
\r
682 return usart->US_FIMR;
\r
687 * \brief Get the size occupied in the input FIFO of USART device.
\r
689 * \param usart Pointer to an USART instance.
\r
690 * \return Size occupied in the input FIFO (not read yet) in octet
\r
692 uint32_t usart_fifo_rx_size(Usart *usart)
\r
694 return (usart->US_FLR & US_FLR_RXFL_Msk) >> US_FLR_RXFL_Pos;
\r
698 * \brief Get the size occupied in the ouput FIFO of USART device.
\r
700 * \param usart Pointer to an USART instance.
\r
701 * \return Size occupied in the output FIFO (not sent yet) in octet
\r
703 uint32_t usart_fifo_tx_size(Usart *usart)
\r
705 return (usart->US_FLR & US_FLR_TXFL_Msk) >> US_FLR_TXFL_Pos;
\r
709 * \brief Reads from USART device input channel until the specified length is
\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
716 * \return Number of read octets
\r
718 * \warning WORKS ONLY IN LITTLE ENDIAN MODE!
\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
724 uint32_t usart_read_stream(Usart *usart, void *stream, uint32_t len)
\r
726 uint8_t* buffer = stream;
\r
727 uint32_t left = len;
\r
729 /* Stop reception if a timeout or break occur */
\r
730 if ((usart->US_CSR & (US_CSR_TIMEOUT | US_CSR_RXBRK)) != 0) {
\r
735 if ((usart->US_CSR & US_CSR_RXRDY) == 0) continue;
\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
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
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
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
768 * \brief Writes given data to USART device output channel until the specified
\r
769 * length is reached.
\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
775 * \return Number of written octets
\r
777 * \warning WORKS ONLY IN LITTLE ENDIAN MODE!
\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
784 uint32_t usart_write_stream(Usart *usart, const void *stream, uint32_t len)
\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
793 if ((usart->US_CSR & US_CSR_TXRDY) == 0) continue;
\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
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
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
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