4 * \brief SAM D20 SERCOM USART Driver
\r
6 * Copyright (C) 2012-2013 Atmel Corporation. All rights reserved.
\r
12 * Redistribution and use in source and binary forms, with or without
\r
13 * modification, are permitted provided that the following conditions are met:
\r
15 * 1. Redistributions of source code must retain the above copyright notice,
\r
16 * this list of conditions and the following disclaimer.
\r
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
19 * this list of conditions and the following disclaimer in the documentation
\r
20 * and/or other materials provided with the distribution.
\r
22 * 3. The name of Atmel may not be used to endorse or promote products derived
\r
23 * from this software without specific prior written permission.
\r
25 * 4. This software may only be redistributed and used in connection with an
\r
26 * Atmel microcontroller product.
\r
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
\r
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
\r
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
\r
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
\r
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
\r
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
\r
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
\r
38 * POSSIBILITY OF SUCH DAMAGE.
\r
45 #if USART_CALLBACK_MODE == true
\r
46 # include "usart_interrupt.h"
\r
50 * \internal Checks a USART config against current set config
\r
52 * This function will check that the config does not alter the
\r
53 * configuration of the module. If the new config changes any
\r
54 * setting, the initialization will be discarded.
\r
56 * \param[in] module Pointer to the software instance struct
\r
57 * \param[in] config Pointer to the configuration struct
\r
59 * \return The status of the configuration
\r
60 * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided.
\r
61 * \retval STATUS_ERR_DENIED If configuration was different from previous
\r
62 * \retval STATUS_OK If the configuration was written
\r
64 static enum status_code _usart_check_config(
\r
65 struct usart_module *const module,
\r
66 const struct usart_config *const config)
\r
68 /* Sanity check arguments */
\r
72 SercomUsart *const usart_hw = &(module->hw->USART);
\r
73 Sercom *const hw = (module->hw);
\r
75 uint32_t pad0 = config->pinmux_pad0;
\r
76 uint32_t pad1 = config->pinmux_pad1;
\r
77 uint32_t pad2 = config->pinmux_pad2;
\r
78 uint32_t pad3 = config->pinmux_pad3;
\r
81 if (pad0 == PINMUX_DEFAULT) {
\r
82 pad0 = _sercom_get_default_pad(hw, 0);
\r
84 if ((pad0 != PINMUX_UNUSED) && ((pad0 & 0xFFFF)!=
\r
85 system_pinmux_pin_get_mux_position(pad0 >> 16))) {
\r
86 return STATUS_ERR_DENIED;
\r
90 if (pad1 == PINMUX_DEFAULT) {
\r
91 pad1 = _sercom_get_default_pad(hw, 1);
\r
93 if ((pad1 != PINMUX_UNUSED) && ((pad1 & 0xFFFF) !=
\r
94 system_pinmux_pin_get_mux_position(pad1 >> 16))) {
\r
95 return STATUS_ERR_DENIED;
\r
99 if (pad2 == PINMUX_DEFAULT) {
\r
100 pad2 = _sercom_get_default_pad(hw, 2);
\r
102 if ((pad2 != PINMUX_UNUSED) && ((pad2 & 0xFFFF) !=
\r
103 system_pinmux_pin_get_mux_position(pad2 >> 16))) {
\r
104 return STATUS_ERR_DENIED;
\r
108 if (pad3 == PINMUX_DEFAULT) {
\r
109 pad3 = _sercom_get_default_pad(hw, 3);
\r
111 if ((pad3 != PINMUX_UNUSED) && ((pad3 & 0xFFFF) !=
\r
112 system_pinmux_pin_get_mux_position(pad3 >> 16))) {
\r
113 return STATUS_ERR_DENIED;
\r
116 /* Find baud value and compare it */
\r
118 enum status_code status_code = STATUS_OK;
\r
120 switch (config->transfer_mode)
\r
122 case USART_TRANSFER_SYNCHRONOUSLY:
\r
123 if (!config->use_external_clock) {
\r
124 status_code = _sercom_get_sync_baud_val(config->baudrate,
\r
125 system_gclk_chan_get_hz(SERCOM_GCLK_ID), &baud);
\r
130 case USART_TRANSFER_ASYNCHRONOUSLY:
\r
131 if (config->use_external_clock) {
\r
133 _sercom_get_async_baud_val(config->baudrate,
\r
134 config->ext_clock_freq, &baud);
\r
137 _sercom_get_async_baud_val(config->baudrate,
\r
138 system_gclk_chan_get_hz(SERCOM_GCLK_ID), &baud);
\r
144 if (status_code != STATUS_OK) {
\r
145 /* Baud rate calculation error, return status code */
\r
146 return STATUS_ERR_DENIED;
\r
149 if (usart_hw->BAUD.reg != baud) {
\r
150 return STATUS_ERR_DENIED;
\r
153 uint32_t ctrla = 0;
\r
154 uint32_t ctrlb = 0;
\r
156 /* Check sample mode, data order, internal muxing, and clock polarity */
\r
157 ctrla = (uint32_t)config->data_order |
\r
158 (uint32_t)config->mux_setting |
\r
159 (uint32_t)config->transfer_mode |
\r
160 SERCOM_USART_CTRLA_MODE(0) |
\r
161 (config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos);
\r
163 /* set enable bit */
\r
164 ctrla |= (SERCOM_USART_CTRLA_ENABLE);
\r
166 if (config->use_external_clock == false) {
\r
167 ctrla |= SERCOM_USART_CTRLA_MODE_USART_INT_CLK;
\r
170 ctrla |= SERCOM_USART_CTRLA_MODE_USART_EXT_CLK;
\r
173 /* Check stopbits and character size */
\r
174 ctrlb = (uint32_t)config->stopbits | (uint32_t)config->character_size |
\r
175 (config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) |
\r
176 (config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos);
\r
178 /* Check parity mode bits */
\r
179 if (config->parity != USART_PARITY_NONE) {
\r
180 ctrla |= SERCOM_USART_CTRLA_FORM(1);
\r
181 ctrlb |= config->parity;
\r
183 ctrla |= SERCOM_USART_CTRLA_FORM(0);
\r
186 if (usart_hw->CTRLA.reg == ctrla && usart_hw->CTRLB.reg == ctrlb) {
\r
187 module->character_size = config->character_size;
\r
191 return STATUS_ERR_DENIED;
\r
197 * Set Configuration of the USART module
\r
199 static enum status_code _usart_set_config(
\r
200 struct usart_module *const module,
\r
201 const struct usart_config *const config)
\r
203 /* Sanity check arguments */
\r
205 Assert(module->hw);
\r
207 /* Get a pointer to the hardware module instance */
\r
208 SercomUsart *const usart_hw = &(module->hw->USART);
\r
210 /* Index for generic clock */
\r
211 uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
\r
212 uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
\r
214 /* Cache new register values to minimize the number of register writes */
\r
215 uint32_t ctrla = 0;
\r
216 uint32_t ctrlb = 0;
\r
219 /* Set data order, internal muxing, and clock polarity */
\r
220 ctrla = (uint32_t)config->data_order |
\r
221 (uint32_t)config->mux_setting |
\r
222 (config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos);
\r
224 enum status_code status_code = STATUS_OK;
\r
226 /* Get baud value from mode and clock */
\r
227 switch (config->transfer_mode)
\r
229 case USART_TRANSFER_SYNCHRONOUSLY:
\r
230 if (!config->use_external_clock) {
\r
231 status_code = _sercom_get_sync_baud_val(config->baudrate,
\r
232 system_gclk_chan_get_hz(gclk_index), &baud);
\r
237 case USART_TRANSFER_ASYNCHRONOUSLY:
\r
238 if (config->use_external_clock) {
\r
240 _sercom_get_async_baud_val(config->baudrate,
\r
241 config->ext_clock_freq, &baud);
\r
244 _sercom_get_async_baud_val(config->baudrate,
\r
245 system_gclk_chan_get_hz(gclk_index), &baud);
\r
251 /* Check if calculating the baud rate failed */
\r
252 if (status_code != STATUS_OK) {
\r
254 return status_code;
\r
257 /* Wait until synchronization is complete */
\r
258 _usart_wait_for_sync(module);
\r
261 usart_hw->BAUD.reg = baud;
\r
263 /* Set sample mode */
\r
264 ctrla |= config->transfer_mode;
\r
266 if (config->use_external_clock == false) {
\r
267 ctrla |= SERCOM_USART_CTRLA_MODE_USART_INT_CLK;
\r
270 ctrla |= SERCOM_USART_CTRLA_MODE_USART_EXT_CLK;
\r
273 /* Set stopbits, character size and enable transceivers */
\r
274 ctrlb = (uint32_t)config->stopbits | (uint32_t)config->character_size |
\r
275 (config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) |
\r
276 (config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos);
\r
278 /* Set parity mode */
\r
279 if (config->parity != USART_PARITY_NONE) {
\r
280 ctrla |= SERCOM_USART_CTRLA_FORM(1);
\r
281 ctrlb |= config->parity;
\r
283 ctrla |= SERCOM_USART_CTRLA_FORM(0);
\r
286 /* Set run mode during device sleep */
\r
287 if (config->run_in_standby) {
\r
288 /* Enable in sleep mode */
\r
289 ctrla |= SERCOM_USART_CTRLA_RUNSTDBY;
\r
292 /* Wait until synchronization is complete */
\r
293 _usart_wait_for_sync(module);
\r
295 /* Write configuration to CTRLB */
\r
296 usart_hw->CTRLB.reg = ctrlb;
\r
298 /* Wait until synchronization is complete */
\r
299 _usart_wait_for_sync(module);
\r
301 /* Write configuration to CTRLA */
\r
302 usart_hw->CTRLA.reg = ctrla;
\r
308 * \brief Initializes the device
\r
310 * Initializes the USART device based on the setting specified in the
\r
311 * configuration struct.
\r
313 * \param[out] module Pointer to USART device
\r
314 * \param[in] hw Pointer to USART hardware instance
\r
315 * \param[in] config Pointer to configuration struct
\r
317 * \return Status of the initialization
\r
319 * \retval STATUS_OK The initialization was successful
\r
320 * \retval STATUS_BUSY The USART module is busy
\r
322 * \retval STATUS_ERR_DENIED The USART have not been disabled in
\r
323 * advance of initialization
\r
324 * \retval STATUS_ERR_INVALID_ARG The configuration struct contains
\r
325 * invalid configuration
\r
326 * \retval STATUS_ERR_ALREADY_INITIALIZED The SERCOM instance has already been
\r
327 * initialized with different clock
\r
329 * \retval STATUS_ERR_BAUD_UNAVAILABLE The BAUD rate given by the
\r
331 * struct cannot be reached with
\r
332 * the current clock configuration
\r
334 enum status_code usart_init(
\r
335 struct usart_module *const module,
\r
337 const struct usart_config *const config)
\r
339 /* Sanity check arguments */
\r
344 enum status_code status_code = STATUS_OK;
\r
346 /* Assign module pointer to software instance struct */
\r
349 /* Get a pointer to the hardware module instance */
\r
350 SercomUsart *const usart_hw = &(module->hw->USART);
\r
352 uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
\r
353 uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
\r
354 uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
\r
356 if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) {
\r
357 /* The module is busy resetting itself */
\r
358 return STATUS_BUSY;
\r
361 if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) {
\r
362 /* Check if the new setting are the same as the old */
\r
363 return _usart_check_config(module, config);
\r
366 /* Turn on module in PM */
\r
367 system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
\r
369 /* Set up the GCLK for the module */
\r
370 struct system_gclk_chan_config gclk_chan_conf;
\r
371 system_gclk_chan_get_config_defaults(&gclk_chan_conf);
\r
372 gclk_chan_conf.source_generator = config->generator_source;
\r
373 system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
\r
374 system_gclk_chan_enable(gclk_index);
\r
375 sercom_set_gclk_generator(config->generator_source, false);
\r
377 /* Set character size */
\r
378 module->character_size = config->character_size;
\r
380 /* Set transmitter and receiver status */
\r
381 module->receiver_enabled = config->receiver_enable;
\r
382 module->transmitter_enabled = config->transmitter_enable;
\r
384 /* Configure Pins */
\r
385 struct system_pinmux_config pin_conf;
\r
386 system_pinmux_get_config_defaults(&pin_conf);
\r
387 pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
\r
389 /* Set configuration according to the config struct */
\r
390 status_code = _usart_set_config(module, config);
\r
391 if(status_code != STATUS_OK) {
\r
392 return status_code;
\r
395 uint32_t pad0 = config->pinmux_pad0;
\r
396 uint32_t pad1 = config->pinmux_pad1;
\r
397 uint32_t pad2 = config->pinmux_pad2;
\r
398 uint32_t pad3 = config->pinmux_pad3;
\r
401 if (pad0 == PINMUX_DEFAULT) {
\r
402 pad0 = _sercom_get_default_pad(hw, 0);
\r
404 if (pad0 != PINMUX_UNUSED) {
\r
405 pin_conf.mux_position = pad0 & 0xFFFF;
\r
406 system_pinmux_pin_set_config(pad0 >> 16, &pin_conf);
\r
410 if (pad1 == PINMUX_DEFAULT) {
\r
411 pad1 = _sercom_get_default_pad(hw, 1);
\r
413 if (pad1 != PINMUX_UNUSED) {
\r
414 pin_conf.mux_position = pad1 & 0xFFFF;
\r
415 system_pinmux_pin_set_config(pad1 >> 16, &pin_conf);
\r
419 if (pad2 == PINMUX_DEFAULT) {
\r
420 pad2 = _sercom_get_default_pad(hw, 2);
\r
422 if (pad2 != PINMUX_UNUSED) {
\r
423 pin_conf.mux_position = pad2 & 0xFFFF;
\r
424 system_pinmux_pin_set_config(pad2 >> 16, &pin_conf);
\r
428 if (pad3 == PINMUX_DEFAULT) {
\r
429 pad3 = _sercom_get_default_pad(hw, 3);
\r
431 if (pad3 != PINMUX_UNUSED) {
\r
432 pin_conf.mux_position = pad3 & 0xFFFF;
\r
433 system_pinmux_pin_set_config(pad3 >> 16, &pin_conf);
\r
435 #if USART_CALLBACK_MODE == true
\r
436 /* Initialize parameters */
\r
437 for (uint32_t i = 0; i < USART_CALLBACK_N; i++) {
\r
438 module->callback[i] = NULL;
\r
441 module->tx_buffer_ptr = NULL;
\r
442 module->rx_buffer_ptr = NULL;
\r
443 module->remaining_tx_buffer_length = 0x0000;
\r
444 module->remaining_rx_buffer_length = 0x0000;
\r
445 module->callback_reg_mask = 0x00;
\r
446 module->callback_enable_mask = 0x00;
\r
447 module->rx_status = STATUS_OK;
\r
448 module->tx_status = STATUS_OK;
\r
450 /* Set interrupt handler and register USART software module struct in
\r
452 uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw);
\r
453 _sercom_set_handler(instance_index, _usart_interrupt_handler);
\r
454 _sercom_instances[instance_index] = module;
\r
456 return status_code;
\r
460 * \brief Transmit a character via the USART
\r
462 * This blocking function will transmit a single character via the
\r
465 * \param[in] module Pointer to the software instance struct
\r
466 * \param[in] tx_data Data to transfer
\r
468 * \return Status of the operation
\r
469 * \retval STATUS_OK If the operation was completed
\r
470 * \retval STATUS_BUSY If the operation was not completed, due to the USART
\r
471 * module being busy.
\r
472 * \retval STATUS_ERR_DENIED If the transmitter is not enabled
\r
474 enum status_code usart_write_wait(
\r
475 struct usart_module *const module,
\r
476 const uint16_t tx_data)
\r
478 /* Sanity check arguments */
\r
480 Assert(module->hw);
\r
482 /* Get a pointer to the hardware module instance */
\r
483 SercomUsart *const usart_hw = &(module->hw->USART);
\r
485 /* Check that the transmitter is enabled */
\r
486 if (!(module->transmitter_enabled)) {
\r
487 return STATUS_ERR_DENIED;
\r
490 #if USART_CALLBACK_MODE == true
\r
491 /* Check if the USART is busy doing asynchronous operation. */
\r
492 if (module->remaining_tx_buffer_length > 0) {
\r
493 return STATUS_BUSY;
\r
497 /* Check if USART is ready for new data */
\r
498 if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {
\r
499 /* Return error code */
\r
500 return STATUS_BUSY;
\r
504 /* Wait until synchronization is complete */
\r
505 _usart_wait_for_sync(module);
\r
507 /* Write data to USART module */
\r
508 usart_hw->DATA.reg = tx_data;
\r
510 while (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) {
\r
511 /* Wait until data is sent */
\r
518 * \brief Receive a character via the USART
\r
520 * This blocking function will receive a character via the USART.
\r
522 * \param[in] module Pointer to the software instance struct
\r
523 * \param[out] rx_data Pointer to received data
\r
525 * \return Status of the operation
\r
526 * \retval STATUS_OK If the operation was completed
\r
527 * \retval STATUS_BUSY If the operation was not completed,
\r
528 * due to the USART module being busy
\r
529 * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed,
\r
530 * due to configuration mismatch between USART
\r
532 * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed,
\r
533 * due to the baud rate being too low or the
\r
534 * system frequency being too high
\r
535 * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due to
\r
536 * data being corrupted
\r
537 * \retval STATUS_ERR_DENIED If the receiver is not enabled
\r
539 enum status_code usart_read_wait(
\r
540 struct usart_module *const module,
\r
541 uint16_t *const rx_data)
\r
543 /* Sanity check arguments */
\r
545 Assert(module->hw);
\r
547 /* Error variable */
\r
548 uint8_t error_code;
\r
550 /* Get a pointer to the hardware module instance */
\r
551 SercomUsart *const usart_hw = &(module->hw->USART);
\r
553 /* Check that the receiver is enabled */
\r
554 if (!(module->receiver_enabled)) {
\r
555 return STATUS_ERR_DENIED;
\r
558 #if USART_CALLBACK_MODE == true
\r
559 /* Check if the USART is busy doing asynchronous operation. */
\r
560 if (module->remaining_rx_buffer_length > 0) {
\r
561 return STATUS_BUSY;
\r
565 /* Check if USART has new data */
\r
566 if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)) {
\r
567 /* Return error code */
\r
568 return STATUS_BUSY;
\r
572 /* Wait until synchronization is complete */
\r
573 _usart_wait_for_sync(module);
\r
575 /* Read out the status code and mask away all but the 3 LSBs*/
\r
576 error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
\r
578 /* Check if an error has occurred during the receiving */
\r
580 /* Check which error occurred */
\r
581 if (error_code & SERCOM_USART_STATUS_FERR) {
\r
582 /* Clear flag by writing a 1 to it and
\r
583 * return with an error code */
\r
584 usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR;
\r
586 return STATUS_ERR_BAD_FORMAT;
\r
587 } else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
\r
588 /* Clear flag by writing a 1 to it and
\r
589 * return with an error code */
\r
590 usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF;
\r
592 return STATUS_ERR_OVERFLOW;
\r
593 } else if (error_code & SERCOM_USART_STATUS_PERR) {
\r
594 /* Clear flag by writing a 1 to it and
\r
595 * return with an error code */
\r
596 usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR;
\r
598 return STATUS_ERR_BAD_DATA;
\r
602 /* Read data from USART module */
\r
603 *rx_data = usart_hw->DATA.reg;
\r
609 * \brief Transmit a buffer of characters via the USART
\r
611 * This blocking function will transmit a block of \c length characters
\r
614 * \note Using this function in combination with the interrupt (\c _job) functions is
\r
615 * not recommended as it has no functionality to check if there is an
\r
616 * ongoing interrupt driven operation running or not.
\r
618 * \param[in] module Pointer to USART software instance struct
\r
619 * \param[in] tx_data Pointer to data to transmit
\r
620 * \param[in] length Number of characters to transmit
\r
622 * \return Status of the operation
\r
623 * \retval STATUS_OK If operation was completed
\r
624 * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid
\r
626 * \retval STATUS_ERR_TIMEOUT If operation was not completed, due to USART
\r
627 * module timing out
\r
628 * \retval STATUS_ERR_DENIED If the transmitter is not enabled
\r
630 enum status_code usart_write_buffer_wait(
\r
631 struct usart_module *const module,
\r
632 const uint8_t *tx_data,
\r
635 /* Sanity check arguments */
\r
637 Assert(module->hw);
\r
639 /* Check if the buffer length is valid */
\r
641 return STATUS_ERR_INVALID_ARG;
\r
644 /* Check that the transmitter is enabled */
\r
645 if (!(module->transmitter_enabled)) {
\r
646 return STATUS_ERR_DENIED;
\r
649 /* Get a pointer to the hardware module instance */
\r
650 SercomUsart *const usart_hw = &(module->hw->USART);
\r
652 /* Wait until synchronization is complete */
\r
653 _usart_wait_for_sync(module);
\r
655 uint16_t tx_pos = 0;
\r
657 /* Blocks while buffer is being transferred */
\r
659 /* Wait for the USART to be ready for new data and abort
\r
660 * operation if it doesn't get ready within the timeout*/
\r
661 for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
\r
662 if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE) {
\r
664 } else if (i == USART_TIMEOUT) {
\r
665 return STATUS_ERR_TIMEOUT;
\r
669 /* Data to send is at least 8 bits long */
\r
670 uint16_t data_to_send = tx_data[tx_pos++];
\r
672 /* Check if the character size exceeds 8 bit */
\r
673 if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
\r
674 data_to_send |= (tx_data[tx_pos++] << 8);
\r
677 /* Send the data through the USART module */
\r
678 usart_write_wait(module, data_to_send);
\r
681 /* Wait until Transmit is complete or timeout */
\r
682 for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
\r
683 if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) {
\r
685 } else if (i == USART_TIMEOUT) {
\r
686 return STATUS_ERR_TIMEOUT;
\r
694 * \brief Receive a buffer of \c length characters via the USART
\r
696 * This blocking function will receive a block of \c length characters
\r
699 * \note Using this function in combination with the interrupt (\c *_job)
\r
700 * functions is not recommended as it has no functionality to check if
\r
701 * there is an ongoing interrupt driven operation running or not.
\r
703 * \param[in] module Pointer to USART software instance struct
\r
704 * \param[out] rx_data Pointer to receive buffer
\r
705 * \param[in] length Number of characters to receive
\r
707 * \return Status of the operation.
\r
708 * \retval STATUS_OK If operation was completed
\r
709 * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to an
\r
710 * invalid argument being supplied
\r
711 * \retval STATUS_ERR_TIMEOUT If operation was not completed, due
\r
712 * to USART module timing out
\r
713 * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed,
\r
714 * due to a configuration mismatch
\r
715 * between USART and the sender
\r
716 * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed,
\r
717 * due to the baud rate being too low or the
\r
718 * system frequency being too high
\r
719 * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due
\r
720 * to data being corrupted
\r
721 * \retval STATUS_ERR_DENIED If the receiver is not enabled
\r
723 enum status_code usart_read_buffer_wait(
\r
724 struct usart_module *const module,
\r
728 /* Sanity check arguments */
\r
730 Assert(module->hw);
\r
732 /* Check if the buffer length is valid */
\r
734 return STATUS_ERR_INVALID_ARG;
\r
737 /* Check that the receiver is enabled */
\r
738 if (!(module->receiver_enabled)) {
\r
739 return STATUS_ERR_DENIED;
\r
742 /* Get a pointer to the hardware module instance */
\r
743 SercomUsart *const usart_hw = &(module->hw->USART);
\r
745 uint16_t rx_pos = 0;
\r
747 /* Blocks while buffer is being received */
\r
749 /* Wait for the USART to have new data and abort operation if it
\r
750 * doesn't get ready within the timeout*/
\r
751 for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
\r
752 if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) {
\r
754 } else if (i == USART_TIMEOUT) {
\r
755 return STATUS_ERR_TIMEOUT;
\r
759 enum status_code retval;
\r
760 uint16_t received_data = 0;
\r
762 retval = usart_read_wait(module, &received_data);
\r
764 if (retval != STATUS_OK) {
\r
765 /* Overflow, abort */
\r
769 /* Read value will be at least 8-bits long */
\r
770 rx_data[rx_pos++] = received_data;
\r
772 /* If 9-bit data, write next received byte to the buffer */
\r
773 if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
\r
774 rx_data[rx_pos++] = (received_data >> 8);
\r