]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M0+_Atmel_SAMD20_XPlained/RTOSDemo/src/ASF/sam0/drivers/sercom/usart/usart.c
Starting point for the SAMD20 demo.
[freertos] / FreeRTOS / Demo / CORTEX_M0+_Atmel_SAMD20_XPlained / RTOSDemo / src / ASF / sam0 / drivers / sercom / usart / usart.c
1 /**\r
2  * \file\r
3  *\r
4  * \brief SAM D20 SERCOM USART Driver\r
5  *\r
6  * Copyright (C) 2012-2013 Atmel Corporation. All rights reserved.\r
7  *\r
8  * \asf_license_start\r
9  *\r
10  * \page License\r
11  *\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
14  *\r
15  * 1. Redistributions of source code must retain the above copyright notice,\r
16  *    this list of conditions and the following disclaimer.\r
17  *\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
21  *\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
24  *\r
25  * 4. This software may only be redistributed and used in connection with an\r
26  *    Atmel microcontroller product.\r
27  *\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
39  *\r
40  * \asf_license_stop\r
41  *\r
42  */\r
43 #include "usart.h"\r
44 #include <pinmux.h>\r
45 #if USART_CALLBACK_MODE == true\r
46 #  include "usart_interrupt.h"\r
47 #endif\r
48 \r
49 /**\r
50  * \internal Checks a USART config against current set config\r
51  *\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
55  *\r
56  * \param[in]  module  Pointer to the software instance struct\r
57  * \param[in]  config  Pointer to the configuration struct\r
58  *\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
63  */\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
67 {\r
68                 /* Sanity check arguments */\r
69         Assert(module);\r
70         Assert(module->hw);\r
71 \r
72         SercomUsart *const usart_hw = &(module->hw->USART);\r
73         Sercom *const hw = (module->hw);\r
74 \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
79 \r
80         /* SERCOM PAD0 */\r
81         if (pad0 == PINMUX_DEFAULT) {\r
82                 pad0 = _sercom_get_default_pad(hw, 0);\r
83         }\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
87         }\r
88 \r
89         /* SERCOM PAD1 */\r
90         if (pad1 == PINMUX_DEFAULT) {\r
91                 pad1 = _sercom_get_default_pad(hw, 1);\r
92         }\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
96         }\r
97 \r
98         /* SERCOM PAD2 */\r
99         if (pad2 == PINMUX_DEFAULT) {\r
100                 pad2 = _sercom_get_default_pad(hw, 2);\r
101         }\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
105         }\r
106 \r
107         /* SERCOM PAD3 */\r
108         if (pad3 == PINMUX_DEFAULT) {\r
109                 pad3 = _sercom_get_default_pad(hw, 3);\r
110         }\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
114         }\r
115 \r
116         /* Find baud value and compare it */\r
117         uint16_t baud  = 0;\r
118         enum status_code status_code = STATUS_OK;\r
119 \r
120         switch (config->transfer_mode)\r
121         {\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
126                 }\r
127 \r
128                 break;\r
129 \r
130         case USART_TRANSFER_ASYNCHRONOUSLY:\r
131                 if (config->use_external_clock) {\r
132                         status_code =\r
133                                         _sercom_get_async_baud_val(config->baudrate,\r
134                                                 config->ext_clock_freq, &baud);\r
135                 } else {\r
136                         status_code =\r
137                                         _sercom_get_async_baud_val(config->baudrate,\r
138                                                 system_gclk_chan_get_hz(SERCOM_GCLK_ID), &baud);\r
139                 }\r
140 \r
141                 break;\r
142         }\r
143 \r
144         if (status_code != STATUS_OK) {\r
145                 /* Baud rate calculation error, return status code */\r
146                 return STATUS_ERR_DENIED;\r
147         }\r
148 \r
149         if (usart_hw->BAUD.reg != baud) {\r
150                 return STATUS_ERR_DENIED;\r
151         }\r
152 \r
153         uint32_t ctrla = 0;\r
154         uint32_t ctrlb = 0;\r
155 \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
162 \r
163         /* set enable bit */\r
164         ctrla |= (SERCOM_USART_CTRLA_ENABLE);\r
165 \r
166         if (config->use_external_clock == false) {\r
167                 ctrla |= SERCOM_USART_CTRLA_MODE_USART_INT_CLK;\r
168         }\r
169         else {\r
170                 ctrla |= SERCOM_USART_CTRLA_MODE_USART_EXT_CLK;\r
171         }\r
172 \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
177 \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
182         } else {\r
183                 ctrla |= SERCOM_USART_CTRLA_FORM(0);\r
184         }\r
185 \r
186         if (usart_hw->CTRLA.reg == ctrla && usart_hw->CTRLB.reg == ctrlb) {\r
187                 module->character_size = config->character_size;\r
188                 return STATUS_OK;\r
189         } else {\r
190                 module->hw = NULL;\r
191                 return STATUS_ERR_DENIED;\r
192         }\r
193 }\r
194 \r
195 /**\r
196  * \internal\r
197  * Set Configuration of the USART module\r
198  */\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
202 {\r
203         /* Sanity check arguments */\r
204         Assert(module);\r
205         Assert(module->hw);\r
206 \r
207         /* Get a pointer to the hardware module instance */\r
208         SercomUsart *const usart_hw = &(module->hw->USART);\r
209 \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
213 \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
217         uint16_t baud  = 0;\r
218 \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
223 \r
224         enum status_code status_code = STATUS_OK;\r
225 \r
226         /* Get baud value from mode and clock */\r
227         switch (config->transfer_mode)\r
228         {\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
233                         }\r
234 \r
235                         break;\r
236 \r
237                 case USART_TRANSFER_ASYNCHRONOUSLY:\r
238                         if (config->use_external_clock) {\r
239                                 status_code =\r
240                                                 _sercom_get_async_baud_val(config->baudrate,\r
241                                                         config->ext_clock_freq, &baud);\r
242                         } else {\r
243                                 status_code =\r
244                                                 _sercom_get_async_baud_val(config->baudrate,\r
245                                                         system_gclk_chan_get_hz(gclk_index), &baud);\r
246                         }\r
247 \r
248                         break;\r
249         }\r
250 \r
251         /* Check if calculating the baud rate failed */\r
252         if (status_code != STATUS_OK) {\r
253                 /* Abort */\r
254                 return status_code;\r
255         }\r
256 \r
257         /* Wait until synchronization is complete */\r
258         _usart_wait_for_sync(module);\r
259 \r
260         /*Set baud val */\r
261         usart_hw->BAUD.reg = baud;\r
262 \r
263         /* Set sample mode */\r
264         ctrla |= config->transfer_mode;\r
265 \r
266         if (config->use_external_clock == false) {\r
267                 ctrla |= SERCOM_USART_CTRLA_MODE_USART_INT_CLK;\r
268         }\r
269         else {\r
270                 ctrla |= SERCOM_USART_CTRLA_MODE_USART_EXT_CLK;\r
271         }\r
272 \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
277 \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
282         } else {\r
283                 ctrla |= SERCOM_USART_CTRLA_FORM(0);\r
284         }\r
285 \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
290         }\r
291 \r
292         /* Wait until synchronization is complete */\r
293         _usart_wait_for_sync(module);\r
294 \r
295         /* Write configuration to CTRLB */\r
296         usart_hw->CTRLB.reg = ctrlb;\r
297 \r
298         /* Wait until synchronization is complete */\r
299         _usart_wait_for_sync(module);\r
300 \r
301         /* Write configuration to CTRLA */\r
302         usart_hw->CTRLA.reg = ctrla;\r
303 \r
304         return STATUS_OK;\r
305 }\r
306 \r
307 /**\r
308  * \brief Initializes the device\r
309  *\r
310  * Initializes the USART device based on the setting specified in the\r
311  * configuration struct.\r
312  *\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
316  *\r
317  * \return Status of the initialization\r
318  *\r
319  * \retval STATUS_OK                       The initialization was successful\r
320  * \retval STATUS_BUSY                     The USART module is busy\r
321  *                                         resetting\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
328  *                                         configuration\r
329  * \retval STATUS_ERR_BAUD_UNAVAILABLE     The BAUD rate given by the\r
330  *                                         configuration\r
331  *                                         struct cannot be reached with\r
332  *                                         the current clock configuration\r
333  */\r
334 enum status_code usart_init(\r
335                 struct usart_module *const module,\r
336                 Sercom *const hw,\r
337                 const struct usart_config *const config)\r
338 {\r
339         /* Sanity check arguments */\r
340         Assert(module);\r
341         Assert(hw);\r
342         Assert(config);\r
343 \r
344         enum status_code status_code = STATUS_OK;\r
345 \r
346         /* Assign module pointer to software instance struct */\r
347         module->hw = hw;\r
348 \r
349         /* Get a pointer to the hardware module instance */\r
350         SercomUsart *const usart_hw = &(module->hw->USART);\r
351 \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
355 \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
359         }\r
360 \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
364         }\r
365 \r
366         /* Turn on module in PM */\r
367         system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);\r
368 \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
376 \r
377         /* Set character size */\r
378         module->character_size = config->character_size;\r
379 \r
380         /* Set transmitter and receiver status */\r
381         module->receiver_enabled = config->receiver_enable;\r
382         module->transmitter_enabled = config->transmitter_enable;\r
383 \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
388 \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
393         }\r
394 \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
399 \r
400         /* SERCOM PAD0 */\r
401         if (pad0 == PINMUX_DEFAULT) {\r
402                 pad0 = _sercom_get_default_pad(hw, 0);\r
403         }\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
407         }\r
408 \r
409         /* SERCOM PAD1 */\r
410         if (pad1 == PINMUX_DEFAULT) {\r
411                 pad1 = _sercom_get_default_pad(hw, 1);\r
412         }\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
416         }\r
417 \r
418         /* SERCOM PAD2 */\r
419         if (pad2 == PINMUX_DEFAULT) {\r
420                 pad2 = _sercom_get_default_pad(hw, 2);\r
421         }\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
425         }\r
426 \r
427         /* SERCOM PAD3 */\r
428         if (pad3 == PINMUX_DEFAULT) {\r
429                 pad3 = _sercom_get_default_pad(hw, 3);\r
430         }\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
434         }\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
439         }\r
440 \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
449 \r
450         /* Set interrupt handler and register USART software module struct in\r
451          * look-up table */\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
455 #endif\r
456         return status_code;\r
457 }\r
458 \r
459 /**\r
460  * \brief Transmit a character via the USART\r
461  *\r
462  * This blocking function will transmit a single character via the\r
463  * USART.\r
464  *\r
465  * \param[in]  module   Pointer to the software instance struct\r
466  * \param[in]  tx_data  Data to transfer\r
467  *\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
473  */\r
474 enum status_code usart_write_wait(\r
475                 struct usart_module *const module,\r
476                 const uint16_t tx_data)\r
477 {\r
478         /* Sanity check arguments */\r
479         Assert(module);\r
480         Assert(module->hw);\r
481 \r
482         /* Get a pointer to the hardware module instance */\r
483         SercomUsart *const usart_hw = &(module->hw->USART);\r
484 \r
485         /* Check that the transmitter is enabled */\r
486         if (!(module->transmitter_enabled)) {\r
487                 return STATUS_ERR_DENIED;\r
488         }\r
489 \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
494         }\r
495 \r
496 #else\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
501         }\r
502 #endif\r
503 \r
504         /* Wait until synchronization is complete */\r
505         _usart_wait_for_sync(module);\r
506 \r
507         /* Write data to USART module */\r
508         usart_hw->DATA.reg = tx_data;\r
509 \r
510         while (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) {\r
511                 /* Wait until data is sent */\r
512         }\r
513 \r
514         return STATUS_OK;\r
515 }\r
516 \r
517 /**\r
518  * \brief Receive a character via the USART\r
519  *\r
520  * This blocking function will receive a character via the USART.\r
521  *\r
522  * \param[in]   module   Pointer to the software instance struct\r
523  * \param[out]  rx_data  Pointer to received data\r
524  *\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
531  *                                  and the sender\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
538  */\r
539 enum status_code usart_read_wait(\r
540                 struct usart_module *const module,\r
541                 uint16_t *const rx_data)\r
542 {\r
543         /* Sanity check arguments */\r
544         Assert(module);\r
545         Assert(module->hw);\r
546 \r
547         /* Error variable */\r
548         uint8_t error_code;\r
549 \r
550         /* Get a pointer to the hardware module instance */\r
551         SercomUsart *const usart_hw = &(module->hw->USART);\r
552 \r
553         /* Check that the receiver is enabled */\r
554         if (!(module->receiver_enabled)) {\r
555                 return STATUS_ERR_DENIED;\r
556         }\r
557 \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
562         }\r
563 \r
564 #else\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
569         }\r
570 #endif\r
571 \r
572         /* Wait until synchronization is complete */\r
573         _usart_wait_for_sync(module);\r
574 \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
577 \r
578         /* Check if an error has occurred during the receiving */\r
579         if (error_code) {\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
585 \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
591 \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
597 \r
598                         return STATUS_ERR_BAD_DATA;\r
599                 }\r
600         }\r
601 \r
602         /* Read data from USART module */\r
603         *rx_data = usart_hw->DATA.reg;\r
604 \r
605         return STATUS_OK;\r
606 }\r
607 \r
608 /**\r
609  * \brief Transmit a buffer of characters via the USART\r
610  *\r
611  * This blocking function will transmit a block of \c length characters\r
612  * via the USART\r
613  *\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
617  *\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
621  *\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
625  *                                arguments\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
629  */\r
630 enum status_code usart_write_buffer_wait(\r
631                 struct usart_module *const module,\r
632                 const uint8_t *tx_data,\r
633                 uint16_t length)\r
634 {\r
635         /* Sanity check arguments */\r
636         Assert(module);\r
637         Assert(module->hw);\r
638 \r
639         /* Check if the buffer length is valid */\r
640         if (length == 0) {\r
641                 return STATUS_ERR_INVALID_ARG;\r
642         }\r
643 \r
644         /* Check that the transmitter is enabled */\r
645         if (!(module->transmitter_enabled)) {\r
646                 return STATUS_ERR_DENIED;\r
647         }\r
648 \r
649         /* Get a pointer to the hardware module instance */\r
650         SercomUsart *const usart_hw = &(module->hw->USART);\r
651 \r
652         /* Wait until synchronization is complete */\r
653         _usart_wait_for_sync(module);\r
654 \r
655         uint16_t tx_pos = 0;\r
656 \r
657         /* Blocks while buffer is being transferred */\r
658         while (length--) {\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
663                                 break;\r
664                         } else if (i == USART_TIMEOUT) {\r
665                                 return STATUS_ERR_TIMEOUT;\r
666                         }\r
667                 }\r
668 \r
669                 /* Data to send is at least 8 bits long */\r
670                 uint16_t data_to_send = tx_data[tx_pos++];\r
671 \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
675                 }\r
676 \r
677                 /* Send the data through the USART module */\r
678                 usart_write_wait(module, data_to_send);\r
679         }\r
680 \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
684                         break;\r
685                 } else if (i == USART_TIMEOUT) {\r
686                         return STATUS_ERR_TIMEOUT;\r
687                 }\r
688         }\r
689 \r
690         return STATUS_OK;\r
691 }\r
692 \r
693 /**\r
694  * \brief Receive a buffer of \c length characters via the USART\r
695  *\r
696  * This blocking function will receive a block of \c length characters\r
697  * via the USART.\r
698  *\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
702  *\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
706  *\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
722  */\r
723 enum status_code usart_read_buffer_wait(\r
724                 struct usart_module *const module,\r
725                 uint8_t *rx_data,\r
726                 uint16_t length)\r
727 {\r
728         /* Sanity check arguments */\r
729         Assert(module);\r
730         Assert(module->hw);\r
731 \r
732         /* Check if the buffer length is valid */\r
733         if (length == 0) {\r
734                 return STATUS_ERR_INVALID_ARG;\r
735         }\r
736 \r
737         /* Check that the receiver is enabled */\r
738         if (!(module->receiver_enabled)) {\r
739                 return STATUS_ERR_DENIED;\r
740         }\r
741 \r
742         /* Get a pointer to the hardware module instance */\r
743         SercomUsart *const usart_hw = &(module->hw->USART);\r
744 \r
745         uint16_t rx_pos = 0;\r
746 \r
747         /* Blocks while buffer is being received */\r
748         while (length--) {\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
753                                 break;\r
754                         } else if (i == USART_TIMEOUT) {\r
755                                 return STATUS_ERR_TIMEOUT;\r
756                         }\r
757                 }\r
758 \r
759                 enum status_code retval;\r
760                 uint16_t received_data = 0;\r
761 \r
762                 retval = usart_read_wait(module, &received_data);\r
763 \r
764                 if (retval != STATUS_OK) {\r
765                         /* Overflow, abort */\r
766                         return retval;\r
767                 }\r
768 \r
769                 /* Read value will be at least 8-bits long */\r
770                 rx_data[rx_pos++] = received_data;\r
771 \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
775                 }\r
776         }\r
777 \r
778         return STATUS_OK;\r
779 }\r