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