1 /**
2 * \file
3 *
4 * \brief SAM SERCOM USART Driver
5 *
6 * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43 /*
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45 */
46 #include "usart.h"
47 #include <pinmux.h>
48 #if USART_CALLBACK_MODE == true
49 # include "usart_interrupt.h"
50 #endif
51
52 /**
53 * \internal
54 * Set Configuration of the USART module
55 */
_usart_set_config(struct usart_module * const module,const struct usart_config * const config)56 static enum status_code _usart_set_config(
57 struct usart_module *const module,
58 const struct usart_config *const config)
59 {
60 /* Sanity check arguments */
61 Assert(module);
62 Assert(module->hw);
63
64 /* Get a pointer to the hardware module instance */
65 SercomUsart *const usart_hw = &(module->hw->USART);
66
67 /* Index for generic clock */
68 uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
69 uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
70
71 /* Cache new register values to minimize the number of register writes */
72 uint32_t ctrla = 0;
73 uint32_t ctrlb = 0;
74 #ifdef FEATURE_USART_ISO7816
75 uint32_t ctrlc = 0;
76 #endif
77 uint16_t baud = 0;
78 uint32_t transfer_mode;
79
80 enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
81 enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
82
83 #ifdef FEATURE_USART_OVER_SAMPLE
84 switch (config->sample_rate) {
85 case USART_SAMPLE_RATE_16X_ARITHMETIC:
86 mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
87 sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
88 break;
89 case USART_SAMPLE_RATE_8X_ARITHMETIC:
90 mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
91 sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
92 break;
93 case USART_SAMPLE_RATE_3X_ARITHMETIC:
94 mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
95 sample_num = SERCOM_ASYNC_SAMPLE_NUM_3;
96 break;
97 case USART_SAMPLE_RATE_16X_FRACTIONAL:
98 mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
99 sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
100 break;
101 case USART_SAMPLE_RATE_8X_FRACTIONAL:
102 mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
103 sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
104 break;
105 }
106 #endif
107
108 /* Set data order, internal muxing, and clock polarity */
109 ctrla = (uint32_t)config->data_order |
110 (uint32_t)config->mux_setting |
111 #ifdef FEATURE_USART_OVER_SAMPLE
112 config->sample_adjustment |
113 config->sample_rate |
114 #endif
115 #ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION
116 (config->immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) |
117 #endif
118 (config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos);
119
120 enum status_code status_code = STATUS_OK;
121
122 transfer_mode = (uint32_t)config->transfer_mode;
123 #ifdef FEATURE_USART_ISO7816
124 if(config->iso7816_config.enabled) {
125 transfer_mode = config->iso7816_config.protocol_t;
126 }
127 #endif
128 /* Get baud value from mode and clock */
129 #ifdef FEATURE_USART_ISO7816
130 if(config->iso7816_config.enabled) {
131 baud = config->baudrate;
132 } else {
133 #endif
134 switch (transfer_mode)
135 {
136 case USART_TRANSFER_SYNCHRONOUSLY:
137 if (!config->use_external_clock) {
138 status_code = _sercom_get_sync_baud_val(config->baudrate,
139 system_gclk_chan_get_hz(gclk_index), &baud);
140 }
141
142 break;
143
144 case USART_TRANSFER_ASYNCHRONOUSLY:
145 if (config->use_external_clock) {
146 status_code =
147 _sercom_get_async_baud_val(config->baudrate,
148 config->ext_clock_freq, &baud, mode, sample_num);
149 } else {
150 status_code =
151 _sercom_get_async_baud_val(config->baudrate,
152 system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num);
153 }
154
155 break;
156 }
157
158 /* Check if calculating the baudrate failed */
159 if (status_code != STATUS_OK) {
160 /* Abort */
161 return status_code;
162 }
163 #ifdef FEATURE_USART_ISO7816
164 }
165 #endif
166
167 #ifdef FEATURE_USART_IRDA
168 if(config->encoding_format_enable) {
169 usart_hw->RXPL.reg = config->receive_pulse_length;
170 }
171 #endif
172
173 /* Wait until synchronization is complete */
174 _usart_wait_for_sync(module);
175
176 /*Set baud val */
177 usart_hw->BAUD.reg = baud;
178
179 /* Set sample mode */
180 ctrla |= transfer_mode;
181
182 if (config->use_external_clock == false) {
183 ctrla |= SERCOM_USART_CTRLA_MODE(0x1);
184 }
185 else {
186 ctrla |= SERCOM_USART_CTRLA_MODE(0x0);
187 }
188
189 /* Set stopbits and enable transceivers */
190 ctrlb =
191 #ifdef FEATURE_USART_IRDA
192 (config->encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) |
193 #endif
194 #ifdef FEATURE_USART_START_FRAME_DECTION
195 (config->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) |
196 #endif
197 #ifdef FEATURE_USART_COLLISION_DECTION
198 (config->collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) |
199 #endif
200 (config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) |
201 (config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos);
202
203 #ifdef FEATURE_USART_ISO7816
204 if(config->iso7816_config.enabled) {
205 ctrla |= SERCOM_USART_CTRLA_FORM(0x07);
206 if (config->iso7816_config.enable_inverse) {
207 ctrla |= SERCOM_USART_CTRLA_TXINV | SERCOM_USART_CTRLA_RXINV;
208 }
209 ctrlb |= USART_CHARACTER_SIZE_8BIT;
210
211 switch(config->iso7816_config.protocol_t) {
212 case ISO7816_PROTOCOL_T_0:
213 ctrlb |= (uint32_t)config->stopbits;
214 ctrlc |= SERCOM_USART_CTRLC_GTIME(config->iso7816_config.guard_time) | \
215 (config->iso7816_config.inhibit_nack) | \
216 (config->iso7816_config.successive_recv_nack) | \
217 SERCOM_USART_CTRLC_MAXITER(config->iso7816_config.max_iterations);
218 break;
219 case ISO7816_PROTOCOL_T_1:
220 ctrlb |= USART_STOPBITS_1;
221 break;
222 }
223 } else {
224 #endif
225 ctrlb |= (uint32_t)config->stopbits;
226 ctrlb |= (uint32_t)config->character_size;
227 /* Check parity mode bits */
228 if (config->parity != USART_PARITY_NONE) {
229 ctrla |= SERCOM_USART_CTRLA_FORM(1);
230 ctrlb |= config->parity;
231 } else {
232 #ifdef FEATURE_USART_LIN_SLAVE
233 if(config->lin_slave_enable) {
234 ctrla |= SERCOM_USART_CTRLA_FORM(0x4);
235 } else {
236 ctrla |= SERCOM_USART_CTRLA_FORM(0);
237 }
238 #else
239 ctrla |= SERCOM_USART_CTRLA_FORM(0);
240 #endif
241 }
242 #ifdef FEATURE_USART_ISO7816
243 }
244 #endif
245
246 #ifdef FEATURE_USART_LIN_MASTER
247 usart_hw->CTRLC.reg = ((usart_hw->CTRLC.reg) & SERCOM_USART_CTRLC_GTIME_Msk)
248 | config->lin_header_delay
249 | config->lin_break_length;
250
251 if (config->lin_node != LIN_INVALID_MODE) {
252 ctrla &= ~(SERCOM_USART_CTRLA_FORM(0xf));
253 ctrla |= config->lin_node;
254 }
255 #endif
256
257 /* Set whether module should run in standby. */
258 if (config->run_in_standby || system_is_debugger_present()) {
259 ctrla |= SERCOM_USART_CTRLA_RUNSTDBY;
260 }
261
262 /* Wait until synchronization is complete */
263 _usart_wait_for_sync(module);
264
265 /* Write configuration to CTRLB */
266 usart_hw->CTRLB.reg = ctrlb;
267
268 /* Wait until synchronization is complete */
269 _usart_wait_for_sync(module);
270
271 /* Write configuration to CTRLA */
272 usart_hw->CTRLA.reg = ctrla;
273
274 #ifdef FEATURE_USART_RS485
275 if ((usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_FORM_Msk) != \
276 SERCOM_USART_CTRLA_FORM(0x07)) {
277 usart_hw->CTRLC.reg &= ~(SERCOM_USART_CTRLC_GTIME(0x7));
278 usart_hw->CTRLC.reg |= SERCOM_USART_CTRLC_GTIME(config->rs485_guard_time);
279 }
280 #endif
281
282 #ifdef FEATURE_USART_ISO7816
283 if(config->iso7816_config.enabled) {
284 _usart_wait_for_sync(module);
285 usart_hw->CTRLC.reg = ctrlc;
286 }
287 #endif
288
289 return STATUS_OK;
290 }
291
292 /**
293 * \brief Initializes the device
294 *
295 * Initializes the USART device based on the setting specified in the
296 * configuration struct.
297 *
298 * \param[out] module Pointer to USART device
299 * \param[in] hw Pointer to USART hardware instance
300 * \param[in] config Pointer to configuration struct
301 *
302 * \return Status of the initialization.
303 *
304 * \retval STATUS_OK The initialization was successful
305 * \retval STATUS_BUSY The USART module is busy
306 * resetting
307 * \retval STATUS_ERR_DENIED The USART has not been disabled in
308 * advance of initialization
309 * \retval STATUS_ERR_INVALID_ARG The configuration struct contains
310 * invalid configuration
311 * \retval STATUS_ERR_ALREADY_INITIALIZED The SERCOM instance has already been
312 * initialized with different clock
313 * configuration
314 * \retval STATUS_ERR_BAUD_UNAVAILABLE The BAUD rate given by the
315 * configuration
316 * struct cannot be reached with
317 * the current clock configuration
318 */
usart_init(struct usart_module * const module,Sercom * const hw,const struct usart_config * const config)319 enum status_code usart_init(
320 struct usart_module *const module,
321 Sercom *const hw,
322 const struct usart_config *const config)
323 {
324 /* Sanity check arguments */
325 Assert(module);
326 Assert(hw);
327 Assert(config);
328
329 enum status_code status_code = STATUS_OK;
330
331 /* Assign module pointer to software instance struct */
332 module->hw = hw;
333
334 /* Get a pointer to the hardware module instance */
335 SercomUsart *const usart_hw = &(module->hw->USART);
336
337 uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
338 uint32_t pm_index, gclk_index;
339 #if (SAML22) || (SAMC20)
340 pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
341 gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
342 #elif (SAML21) || (SAMR30)
343 if (sercom_index == 5) {
344 pm_index = MCLK_APBDMASK_SERCOM5_Pos;
345 gclk_index = SERCOM5_GCLK_ID_CORE;
346 } else {
347 pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
348 gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
349 }
350 #elif (SAMC21)
351 pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
352
353 if (sercom_index == 5){
354 gclk_index = SERCOM5_GCLK_ID_CORE;
355 } else {
356 gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
357 }
358 #else
359 pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
360 gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
361 #endif
362
363 if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) {
364 /* The module is busy resetting itself */
365 return STATUS_BUSY;
366 }
367
368 if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) {
369 /* Check the module is enabled */
370 return STATUS_ERR_DENIED;
371 }
372
373 /* Turn on module in PM */
374 #if (SAML21) || (SAMR30)
375 if (sercom_index == 5) {
376 system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index);
377 } else {
378 system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
379 }
380 #else
381 system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
382 #endif
383
384 /* Set up the GCLK for the module */
385 struct system_gclk_chan_config gclk_chan_conf;
386 system_gclk_chan_get_config_defaults(&gclk_chan_conf);
387 gclk_chan_conf.source_generator = config->generator_source;
388 system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
389 system_gclk_chan_enable(gclk_index);
390 sercom_set_gclk_generator(config->generator_source, false);
391
392 /* Set character size */
393 module->character_size = config->character_size;
394
395 /* Set transmitter and receiver status */
396 module->receiver_enabled = config->receiver_enable;
397 module->transmitter_enabled = config->transmitter_enable;
398
399 #ifdef FEATURE_USART_LIN_SLAVE
400 module->lin_slave_enabled = config->lin_slave_enable;
401 #endif
402 #ifdef FEATURE_USART_START_FRAME_DECTION
403 module->start_frame_detection_enabled = config->start_frame_detection_enable;
404 #endif
405 #ifdef FEATURE_USART_ISO7816
406 module->iso7816_mode_enabled = config->iso7816_config.enabled;
407 #endif
408 /* Set configuration according to the config struct */
409 status_code = _usart_set_config(module, config);
410 if(status_code != STATUS_OK) {
411 return status_code;
412 }
413
414 struct system_pinmux_config pin_conf;
415 system_pinmux_get_config_defaults(&pin_conf);
416 pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
417 pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
418
419 uint32_t pad_pinmuxes[] = {
420 config->pinmux_pad0, config->pinmux_pad1,
421 config->pinmux_pad2, config->pinmux_pad3
422 };
423
424 /* Configure the SERCOM pins according to the user configuration */
425 for (uint8_t pad = 0; pad < 4; pad++) {
426 uint32_t current_pinmux = pad_pinmuxes[pad];
427
428 if (current_pinmux == PINMUX_DEFAULT) {
429 current_pinmux = _sercom_get_default_pad(hw, pad);
430 }
431
432 if (current_pinmux != PINMUX_UNUSED) {
433 pin_conf.mux_position = current_pinmux & 0xFFFF;
434 system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf);
435 }
436 }
437
438 #if USART_CALLBACK_MODE == true
439 /* Initialize parameters */
440 for (uint32_t i = 0; i < USART_CALLBACK_N; i++) {
441 module->callback[i] = NULL;
442 }
443
444 module->tx_buffer_ptr = NULL;
445 module->rx_buffer_ptr = NULL;
446 module->remaining_tx_buffer_length = 0x0000;
447 module->remaining_rx_buffer_length = 0x0000;
448 module->callback_reg_mask = 0x00;
449 module->callback_enable_mask = 0x00;
450 module->rx_status = STATUS_OK;
451 module->tx_status = STATUS_OK;
452
453 /* Set interrupt handler and register USART software module struct in
454 * look-up table */
455 uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw);
456 _sercom_set_handler(instance_index, _usart_interrupt_handler);
457 _sercom_instances[instance_index] = module;
458 #endif
459
460 return status_code;
461 }
462
463 /**
464 * \brief Transmit a character via the USART
465 *
466 * This blocking function will transmit a single character via the
467 * USART.
468 *
469 * \param[in] module Pointer to the software instance struct
470 * \param[in] tx_data Data to transfer
471 *
472 * \return Status of the operation.
473 * \retval STATUS_OK If the operation was completed
474 * \retval STATUS_BUSY If the operation was not completed, due to the USART
475 * module being busy
476 * \retval STATUS_ERR_DENIED If the transmitter is not enabled
477 */
usart_write_wait(struct usart_module * const module,const uint16_t tx_data)478 enum status_code usart_write_wait(
479 struct usart_module *const module,
480 const uint16_t tx_data)
481 {
482 /* Sanity check arguments */
483 Assert(module);
484 Assert(module->hw);
485
486 /* Get a pointer to the hardware module instance */
487 SercomUsart *const usart_hw = &(module->hw->USART);
488
489 /* Check that the transmitter is enabled */
490 if (!(module->transmitter_enabled)) {
491 return STATUS_ERR_DENIED;
492 }
493
494 #if USART_CALLBACK_MODE == true
495 /* Check if the USART is busy doing asynchronous operation. */
496 if (module->remaining_tx_buffer_length > 0) {
497 return STATUS_BUSY;
498 }
499
500 #else
501 /* Check if USART is ready for new data */
502 if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {
503 /* Return error code */
504 return STATUS_BUSY;
505 }
506 #endif
507
508 /* Wait until synchronization is complete */
509 _usart_wait_for_sync(module);
510
511 /* Write data to USART module */
512 usart_hw->DATA.reg = tx_data;
513
514 while (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) {
515 /* Wait until data is sent */
516 }
517
518 return STATUS_OK;
519 }
520
521 /**
522 * \brief Receive a character via the USART
523 *
524 * This blocking function will receive a character via the USART.
525 *
526 * \param[in] module Pointer to the software instance struct
527 * \param[out] rx_data Pointer to received data
528 *
529 * \return Status of the operation.
530 * \retval STATUS_OK If the operation was completed
531 * \retval STATUS_BUSY If the operation was not completed,
532 * due to the USART module being busy
533 * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed,
534 * due to configuration mismatch between USART
535 * and the sender
536 * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed,
537 * due to the baudrate being too low or the
538 * system frequency being too high
539 * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due to
540 * data being corrupted
541 * \retval STATUS_ERR_DENIED If the receiver is not enabled
542 */
usart_read_wait(struct usart_module * const module,uint16_t * const rx_data)543 enum status_code usart_read_wait(
544 struct usart_module *const module,
545 uint16_t *const rx_data)
546 {
547 /* Sanity check arguments */
548 Assert(module);
549 Assert(module->hw);
550
551 /* Error variable */
552 uint8_t error_code;
553
554 /* Get a pointer to the hardware module instance */
555 SercomUsart *const usart_hw = &(module->hw->USART);
556
557 /* Check that the receiver is enabled */
558 if (!(module->receiver_enabled)) {
559 return STATUS_ERR_DENIED;
560 }
561
562 #if USART_CALLBACK_MODE == true
563 /* Check if the USART is busy doing asynchronous operation. */
564 if (module->remaining_rx_buffer_length > 0) {
565 return STATUS_BUSY;
566 }
567 #endif
568
569 /* Check if USART has new data */
570 if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)) {
571 /* Return error code */
572 return STATUS_BUSY;
573 }
574
575 /* Wait until synchronization is complete */
576 _usart_wait_for_sync(module);
577
578 /* Read out the status code and mask away all but the 3 LSBs*/
579 error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
580
581 /* Check if an error has occurred during the receiving */
582 if (error_code) {
583 /* Check which error occurred */
584 if (error_code & SERCOM_USART_STATUS_FERR) {
585 /* Clear flag by writing a 1 to it and
586 * return with an error code */
587 usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR;
588
589 return STATUS_ERR_BAD_FORMAT;
590 } else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
591 /* Clear flag by writing a 1 to it and
592 * return with an error code */
593 usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF;
594
595 return STATUS_ERR_OVERFLOW;
596 } else if (error_code & SERCOM_USART_STATUS_PERR) {
597 /* Clear flag by writing a 1 to it and
598 * return with an error code */
599 usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR;
600
601 return STATUS_ERR_BAD_DATA;
602 }
603 #ifdef FEATURE_USART_LIN_SLAVE
604 else if (error_code & SERCOM_USART_STATUS_ISF) {
605 /* Clear flag by writing 1 to it and
606 * return with an error code */
607 usart_hw->STATUS.reg = SERCOM_USART_STATUS_ISF;
608
609 return STATUS_ERR_PROTOCOL;
610 }
611 #endif
612 #ifdef FEATURE_USART_COLLISION_DECTION
613 else if (error_code & SERCOM_USART_STATUS_COLL) {
614 /* Clear flag by writing 1 to it
615 * return with an error code */
616 usart_hw->STATUS.reg = SERCOM_USART_STATUS_COLL;
617
618 return STATUS_ERR_PACKET_COLLISION;
619 }
620 #endif
621 }
622
623 /* Read data from USART module */
624 *rx_data = usart_hw->DATA.reg;
625
626 return STATUS_OK;
627 }
628
629 /**
630 * \brief Transmit a buffer of characters via the USART
631 *
632 * This blocking function will transmit a block of \c length characters
633 * via the USART.
634 *
635 * \note Using this function in combination with the interrupt (\c _job) functions is
636 * not recommended as it has no functionality to check if there is an
637 * ongoing interrupt driven operation running or not.
638 *
639 * \param[in] module Pointer to USART software instance struct
640 * \param[in] tx_data Pointer to data to transmit
641 * \param[in] length Number of characters to transmit
642 *
643 * \note If using 9-bit data, the array that *tx_data point to should be defined
644 * as uint16_t array and should be casted to uint8_t* pointer. Because it
645 * is an address pointer, the highest byte is not discarded. For example:
646 * \code
647 #define TX_LEN 3
648 uint16_t tx_buf[TX_LEN] = {0x0111, 0x0022, 0x0133};
649 usart_write_buffer_wait(&module, (uint8_t*)tx_buf, TX_LEN);
650 \endcode
651 *
652 * \return Status of the operation.
653 * \retval STATUS_OK If operation was completed
654 * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid
655 * arguments
656 * \retval STATUS_ERR_TIMEOUT If operation was not completed, due to USART
657 * module timing out
658 * \retval STATUS_ERR_DENIED If the transmitter is not enabled
659 */
usart_write_buffer_wait(struct usart_module * const module,const uint8_t * tx_data,uint16_t length)660 enum status_code usart_write_buffer_wait(
661 struct usart_module *const module,
662 const uint8_t *tx_data,
663 uint16_t length)
664 {
665 /* Sanity check arguments */
666 Assert(module);
667 Assert(module->hw);
668
669 /* Check if the buffer length is valid */
670 if (length == 0) {
671 return STATUS_ERR_INVALID_ARG;
672 }
673
674 /* Check that the transmitter is enabled */
675 if (!(module->transmitter_enabled)) {
676 return STATUS_ERR_DENIED;
677 }
678
679 /* Get a pointer to the hardware module instance */
680 SercomUsart *const usart_hw = &(module->hw->USART);
681
682 /* Wait until synchronization is complete */
683 _usart_wait_for_sync(module);
684
685 uint16_t tx_pos = 0;
686
687 /* Blocks while buffer is being transferred */
688 while (length--) {
689 /* Wait for the USART to be ready for new data and abort
690 * operation if it doesn't get ready within the timeout*/
691 for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
692 if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE) {
693 break;
694 } else if (i == USART_TIMEOUT) {
695 return STATUS_ERR_TIMEOUT;
696 }
697 }
698
699 /* Data to send is at least 8 bits long */
700 uint16_t data_to_send = tx_data[tx_pos++];
701
702 /* Check if the character size exceeds 8 bit */
703 if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
704 data_to_send |= (tx_data[tx_pos++] << 8);
705 }
706
707 /* Send the data through the USART module */
708 usart_write_wait(module, data_to_send);
709 }
710
711 /* Wait until Transmit is complete or timeout */
712 for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
713 if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) {
714 break;
715 } else if (i == USART_TIMEOUT) {
716 return STATUS_ERR_TIMEOUT;
717 }
718 }
719
720 return STATUS_OK;
721 }
722
723 /**
724 * \brief Receive a buffer of \c length characters via the USART
725 *
726 * This blocking function will receive a block of \c length characters
727 * via the USART.
728 *
729 * \note Using this function in combination with the interrupt (\c *_job)
730 * functions is not recommended as it has no functionality to check if
731 * there is an ongoing interrupt driven operation running or not.
732 *
733 * \param[in] module Pointer to USART software instance struct
734 * \param[out] rx_data Pointer to receive buffer
735 * \param[in] length Number of characters to receive
736 *
737 * \note If using 9-bit data, the array that *rx_data point to should be defined
738 * as uint16_t array and should be casted to uint8_t* pointer. Because it
739 * is an address pointer, the highest byte is not discarded. For example:
740 * \code
741 #define RX_LEN 3
742 uint16_t rx_buf[RX_LEN] = {0x0,};
743 usart_read_buffer_wait(&module, (uint8_t*)rx_buf, RX_LEN);
744 \endcode
745 *
746 * \return Status of the operation.
747 * \retval STATUS_OK If operation was completed
748 * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to an
749 * invalid argument being supplied
750 * \retval STATUS_ERR_TIMEOUT If operation was not completed, due
751 * to USART module timing out
752 * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed,
753 * due to a configuration mismatch
754 * between USART and the sender
755 * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed,
756 * due to the baudrate being too low or the
757 * system frequency being too high
758 * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due
759 * to data being corrupted
760 * \retval STATUS_ERR_DENIED If the receiver is not enabled
761 */
usart_read_buffer_wait(struct usart_module * const module,uint8_t * rx_data,uint16_t length)762 enum status_code usart_read_buffer_wait(
763 struct usart_module *const module,
764 uint8_t *rx_data,
765 uint16_t length)
766 {
767 /* Sanity check arguments */
768 Assert(module);
769 Assert(module->hw);
770
771 /* Check if the buffer length is valid */
772 if (length == 0) {
773 return STATUS_ERR_INVALID_ARG;
774 }
775
776 /* Check that the receiver is enabled */
777 if (!(module->receiver_enabled)) {
778 return STATUS_ERR_DENIED;
779 }
780
781 /* Get a pointer to the hardware module instance */
782 SercomUsart *const usart_hw = &(module->hw->USART);
783
784 uint16_t rx_pos = 0;
785
786 /* Blocks while buffer is being received */
787 while (length--) {
788 /* Wait for the USART to have new data and abort operation if it
789 * doesn't get ready within the timeout*/
790 for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
791 if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) {
792 break;
793 } else if (i == USART_TIMEOUT) {
794 return STATUS_ERR_TIMEOUT;
795 }
796 }
797
798 enum status_code retval;
799 uint16_t received_data = 0;
800
801 retval = usart_read_wait(module, &received_data);
802
803 if (retval != STATUS_OK) {
804 /* Overflow, abort */
805 return retval;
806 }
807
808 /* Read value will be at least 8-bits long */
809 rx_data[rx_pos++] = received_data;
810
811 /* If 9-bit data, write next received byte to the buffer */
812 if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
813 rx_data[rx_pos++] = (received_data >> 8);
814 }
815 }
816
817 return STATUS_OK;
818 }
819