Contiki-NG
uart-driver.c
1 /*
2  * Copyright (c) 2015 NXP B.V.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of NXP B.V. nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY NXP B.V. AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL NXP B.V. OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  * Author: Lee Mitchell
32  * Integrated into Contiki by Beshr Al Nahas
33  *
34  */
35 
36 #include <jendefs.h>
37 
38 #ifdef DEBUG
39 #include <dbg.h>
40 #else
41 #define DBG_vPrintf(...)
42 #endif
43 
44 #include "contiki.h"
45 #include "uart-driver.h"
46 #include "sys/rtimer.h"
47 #include "watchdog.h"
48 #include <math.h>
49 #include <AppHardwareApi.h>
50 
51 #if UART_XONXOFF_FLOW_CTRL
52 
53 #include "sys/process.h"
54 
55 #define TX_FIFO_SW_FLOW_LIMIT 8 /* Maximum allowed fill level for tx fifo */
56 #if TX_FIFO_SW_FLOW_LIMIT > 16
57 #undef TX_FIFO_SW_FLOW_LIMIT
58 #define TX_FIFO_SW_FLOW_LIMIT 16
59 #warning "TX_FIFO_SW_FLOW_LIMIT too big. Forced to 16."
60 #endif /* TX_FIFO_SW_FLOW_LIMIT > 16 */
61 
62 #define XON 17
63 #define XOFF 19
64 
65 extern volatile unsigned char xonxoff_state;
66 
67 #endif /* UART_XONXOFF_FLOW_CTRL */
68 
69 /*** Macro Definitions ***/
70 #define BUSYWAIT_UNTIL(cond, max_time) \
71  do { \
72  rtimer_clock_t t0; \
73  t0 = RTIMER_NOW(); \
74  while(!(cond) && RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) ; \
75  } while(0)
76 
77 #define DEBUG_UART_BUFFERED FALSE
78 
79 #define CHAR_DEADLINE (uart_char_delay * 100)
80 
81 /*** Local Function Prototypes ***/
82 static void uart_driver_isr(uint32_t device_id, uint32_t item_bitmap);
83 #if !UART_XONXOFF_FLOW_CTRL
84 static int16_t uart_driver_get_tx_fifo_available_space(uint8_t uart_dev);
85 #endif /* !UART_XONXOFF_FLOW_CTRL */
86 static void uart_driver_set_baudrate(uint8_t uart_dev, uint8_t br);
87 static void uart_driver_set_high_baudrate(uint8_t uart_dev, uint32_t baud_rate);
88 
89 /*** Local Variables ***/
90 #define UART_NUM_UARTS 2
91 static uint16_t tx_fifo_size[UART_NUM_UARTS] = { 0 };
92 static uint8_t active_uarts[UART_NUM_UARTS] = { 0 };
93 /** slip input function pointer */
94 static int(*uart_input[UART_NUM_UARTS]) (unsigned char) = { 0 };
95 /* time in uSec for transmitting 1 char */
96 static uint16_t uart_char_delay = 0;
97 static volatile int8_t interrupt_enabled[UART_NUM_UARTS] = { 0 };
98 static volatile int8_t interrupt_enabled_saved[UART_NUM_UARTS] = { 0 };
99 
100 /****************************************************************************
101  *
102  * NAME: uart_driver_init
103  *
104  * DESCRIPTION:
105  * Initializes the specified UART device.
106  *
107  * PARAMETERS: Name RW Usage
108  * uart_dev R UART to initialise, eg, E_AHI_UART_0
109  * br R Baudrate to use (e.g. UART_RATE_115200)
110  * if br > UART_RATE_115200
111  * then uart_driver_set_baud_rate is called
112  * else vAHI_UartSetClockDivisor
113  * txbuf_data R Pointer to a memory block to use
114  * and rxbuf_data as uart tx/rx fifo
115  * txbuf_size R size of tx fifo (valid range: 16-2047)
116  * txbuf_size R size of rx fifo (valid range: 16-2047)
117  * uart_input_function a function pointer to input uart rx bytes
118  * RETURNS:
119  * void
120  *
121  ****************************************************************************/
122 void
123 uart_driver_init(uint8_t uart_dev, uint8_t br, uint8_t *txbuf_data,
124  uint16_t txbuf_size, uint8_t *rxbuf_data, uint16_t rxbuf_size,
125  int (*uart_input_function)(unsigned char c))
126 {
127 #if !UART_HW_FLOW_CTRL
128  /* Disable RTS/CTS */
129  vAHI_UartSetRTSCTS(uart_dev, FALSE);
130 #endif
131 
132  tx_fifo_size[uart_dev] = txbuf_size;
133 
134  /* Configure the selected Uart */
135  uint8_t uart_enabled = bAHI_UartEnable(uart_dev, txbuf_data, txbuf_size,
136  rxbuf_data, rxbuf_size);
137  /* fallback to internal buffers */
138  if(!uart_enabled) {
139  vAHI_UartEnable(uart_dev);
140  tx_fifo_size[uart_dev] = 16; /* Fixed size */
141  }
142  /* Reset tx/rx fifos */
143  vAHI_UartReset(uart_dev, TRUE, TRUE);
144  vAHI_UartReset(uart_dev, FALSE, FALSE);
145 
146  uart_driver_set_baudrate(uart_dev, br);
147 
148  /* install interrupt service callback */
149  if(uart_dev == E_AHI_UART_0) {
150  vAHI_Uart0RegisterCallback((void *)uart_driver_isr);
151  } else {
152  vAHI_Uart1RegisterCallback((void *)uart_driver_isr);
153  /* Enable RX interrupt */
154  }
155  uart_driver_enable_interrupts(uart_dev);
156  uart_input[uart_dev] = uart_input_function;
157  active_uarts[uart_dev] = 1;
158 
159 #if UART_HW_FLOW_CTRL
160  /* Configure HW flow control */
161  vAHI_UartSetAutoFlowCtrl(uart_dev, E_AHI_UART_FIFO_ARTS_LEVEL_13, /* uint8 const u8RxFifoLevel,*/
162  FALSE, /* bool_t const bFlowCtrlPolarity,*/
163  TRUE, /* bool_t const bAutoRts, */
164  TRUE /* bool_t const bAutoCts */);
165 #endif
166 
167  DBG_vPrintf("UART %d init: using %s buffers %d\n", uart_dev,
168  uart_enabled ? "external" : "internal", tx_fifo_size[uart_dev]);
169 }
170 void
171 uart_driver_enable_interrupts(uint8_t uart_dev)
172 {
173  /* wait while char being tx is done */
174  while((u8AHI_UartReadLineStatus(uart_dev) & E_AHI_UART_LS_THRE) == 0) ;
175 
176  vAHI_UartSetInterrupt(uart_dev, FALSE /*bEnableModemStatus*/,
177  FALSE /*bEnableRxLineStatus == Break condition */,
178  FALSE /*bEnableTxFifoEmpty*/,
179  TRUE /* bEnableRxData */, E_AHI_UART_FIFO_LEVEL_14);
180  interrupt_enabled[uart_dev] = 1;
181 }
182 void
183 uart_driver_disable_interrupts(uint8_t uart_dev)
184 {
185  /* wait while char being tx is done */
186  while((u8AHI_UartReadLineStatus(uart_dev) & E_AHI_UART_LS_THRE) == 0) ;
187 
188  vAHI_UartSetInterrupt(uart_dev, FALSE /*bEnableModemStatus*/,
189  FALSE /*bEnableRxLineStatus == Break condition */,
190  FALSE /*bEnableTxFifoEmpty*/,
191  FALSE /* bEnableRxData */, E_AHI_UART_FIFO_LEVEL_14);
192  interrupt_enabled[uart_dev] = 0;
193 }
194 void
195 uart_driver_store_interrupts(uint8_t uart_dev)
196 {
197  interrupt_enabled_saved[uart_dev] = interrupt_enabled[uart_dev];
198 }
199 void
200 uart_driver_restore_interrupts(uint8_t uart_dev)
201 {
202  if(interrupt_enabled_saved[uart_dev]) {
203  uart_driver_enable_interrupts(uart_dev);
204  } else {
205  uart_driver_disable_interrupts(uart_dev);
206  }
207 }
208 int8_t
209 uart_driver_interrupt_is_enabled(uint8_t uart_dev)
210 {
211  return interrupt_enabled[uart_dev];
212 }
213 void
214 uart_driver_set_input(uint8_t uart_dev, int
215  (*uart_input_function)(unsigned char c))
216 {
217  uart_input[uart_dev] = uart_input_function;
218 }
219 /****************************************************************************
220  *
221  * NAME: uart_driver_read
222  *
223  * DESCRIPTION:
224  * Reads 1 byte from the RX buffer. If there is no data in the
225  * buffer, then return FALSE
226  *
227  * PARAMETERS: Name RW Usage
228  * uart_dev R UART to use, eg, E_AHI_UART_0
229  *
230  * RETURNS:
231  * TRUE if a byte has been read from the queue
232  *
233  ****************************************************************************/
234 uint8_t
235 uart_driver_read(uint8_t uart_dev, uint8_t *data)
236 {
237  if(data && u16AHI_UartReadRxFifoLevel(uart_dev) > 0) {
238  *data = u8AHI_UartReadData(uart_dev);
239  return TRUE;
240  }
241  return FALSE;
242 }
243 void
244 uart_driver_write_buffered(uint8_t uart_dev, uint8_t ch)
245 {
246  uart_driver_write_with_deadline(uart_dev, ch);
247 }
248 /****************************************************************************
249  *
250  * NAME: uart_driver_write_with_deadline
251  *
252  * DESCRIPTION:
253  * Writes one byte to the specified uart for transmission
254  *
255  * PARAMETERS: Name RW Usage
256  * uart_dev R UART to use, eg, E_AHI_UART_0
257  * ch R data to transmit
258  *
259  * RETURNS:
260  * void
261  *
262  ****************************************************************************/
263 void
264 uart_driver_write_with_deadline(uint8_t uart_dev, uint8_t ch)
265 {
266 #if UART_XONXOFF_FLOW_CTRL
267  /* Block until host can receive data */
268  /* Wait until there are less than N characters in TX FIFO */
269  while(xonxoff_state != XON
270  || u16AHI_UartReadTxFifoLevel(uart_dev) > TX_FIFO_SW_FLOW_LIMIT) {
272  }
273  /* write to TX FIFO and return immediately */
274  vAHI_UartWriteData(uart_dev, ch);
275 #else /* UART_XONXOFF_FLOW_CTRL */
276  volatile int16_t write = 0;
278  /* wait until there is space in tx fifo */
279  BUSYWAIT_UNTIL(write = (uart_driver_get_tx_fifo_available_space(uart_dev) > 0),
280  CHAR_DEADLINE);
281  /* write only if there is space so we do not get stuck */
282  if(write) {
283  /* write to TX FIFO and return immediately */
284  vAHI_UartWriteData(uart_dev, ch);
285  }
286 #endif /* UART_XONXOFF_FLOW_CTRL */
287 }
288 void
289 uart_driver_write_direct(uint8_t uart_dev, uint8_t ch)
290 {
291  /* Write character */
292  vAHI_UartWriteData(uart_dev, ch);
293  /* Wait for buffers to empty */
294  while((u8AHI_UartReadLineStatus(uart_dev) & E_AHI_UART_LS_THRE) == 0) ;
295  while((u8AHI_UartReadLineStatus(uart_dev) & E_AHI_UART_LS_TEMT) == 0) ;
296 }
297 /****************************************************************************
298  *
299  * NAME: uart_driver_rx_handler
300  *
301  * DESCRIPTION:
302  * Interrupt service callback for UART data reception. Reads a received
303  * byte from the UART and writes it to the reception buffer if it is not
304  * full.
305  *
306  * PARAMETERS: Name RW Usage
307  * uart_dev R Uart to read from
308  *
309  * RETURNS:
310  * void
311  *
312  ****************************************************************************/
313 void
314 uart_driver_rx_handler(uint8_t uart_dev)
315 {
316  /* optimization for high throughput: Read upto 32 bytes from RX fifo.
317  * Disabled because it does not work with current slip_input_byte */
318 
319  /* Status from uart_input:
320  * 0 means do not exit power saving mode
321  * -1 means RX buffer overflow ==> stop reading
322  * 1 means end of slip packet
323  */
324 #if UART_XONXOFF_FLOW_CTRL
325  /* save old status */
326  int xonxoff_state_old = xonxoff_state;
327 #endif /* UART_XONXOFF_FLOW_CTRL */
328  int status = 0;
329  int c = 0;
330  while(u16AHI_UartReadRxFifoLevel(uart_dev) > 0 && c++ < 32 && status == 0) {
331  if(uart_input[uart_dev] != NULL) { /* read one char at a time */
332 
333  /* process received character */
334  status = (uart_input[uart_dev])(u8AHI_UartReadData(uart_dev));
335 
336 #if UART_XONXOFF_FLOW_CTRL
337  /* Process XON-XOFF*/
338  if(xonxoff_state == XOFF) {
339  /* XXX do not set break condition as it corrupts one character, instead we block on TX */
340  /* Instruct uart to stop TX */
341  /* vAHI_UartSetBreak(uart_dev, TRUE); */
342  break;
343  } else if(xonxoff_state_old == XOFF && xonxoff_state == XON) {
344  /* Instruct uart to resume TX if it was stopped */
345  /* vAHI_UartSetBreak(uart_dev, FALSE); */
346  }
347 #endif /* UART_XONXOFF_FLOW_CTRL */
348  } else {
349  /* no input handler, or no bytes to read: Discard byte. */
350  u8AHI_UartReadData(uart_dev);
351  }
352  }
353 }
354 /****************************************************************************/
355 /*** Local Functions ***/
356 /****************************************************************************/
357 
358 #if !UART_XONXOFF_FLOW_CTRL
359 /* Returns the free space in tx fifo, i.e., how many characters we can put */
360 static int16_t
361 uart_driver_get_tx_fifo_available_space(uint8_t uart_dev)
362 {
363  return tx_fifo_size[uart_dev] - u16AHI_UartReadTxFifoLevel(uart_dev);
364 }
365 #endif /* !UART_XONXOFF_FLOW_CTRL */
366 /* Initializes the specified UART with auto-selection of
367  baudrate tuning method */
368 static void
369 uart_driver_set_baudrate(uint8_t uart_dev, uint8_t br)
370 {
371  uint32_t high_br = 0;
372  uint8_t low_br = 0;
373 
374  switch(br) {
375  case UART_RATE_4800:
376  low_br = E_AHI_UART_RATE_4800;
377  uart_char_delay = 1667;
378  break;
379  case UART_RATE_9600:
380  low_br = E_AHI_UART_RATE_9600;
381  uart_char_delay = 834;
382  break;
383  case UART_RATE_19200:
384  low_br = E_AHI_UART_RATE_19200;
385  uart_char_delay = 417;
386  break;
387  case UART_RATE_38400:
388  low_br = E_AHI_UART_RATE_38400;
389  uart_char_delay = 209;
390  break;
391  case UART_RATE_76800:
392  low_br = E_AHI_UART_RATE_76800;
393  uart_char_delay = 105;
394  break;
395  case UART_RATE_115200:
396  low_br = E_AHI_UART_RATE_115200;
397  uart_char_delay = 69;
398  break;
399  case UART_RATE_230400:
400  high_br = 230400UL;
401  uart_char_delay = 35;
402  break;
403  case UART_RATE_460800:
404  high_br = 460800UL;
405  uart_char_delay = 18;
406  break;
407  case UART_RATE_500000:
408  high_br = 500000UL;
409  uart_char_delay = 16;
410  break;
411  case UART_RATE_576000:
412  high_br = 576000UL;
413  uart_char_delay = 14;
414  break;
415  case UART_RATE_921600:
416  high_br = 921600UL;
417  uart_char_delay = 9;
418  break;
419  case UART_RATE_1000000:
420  high_br = 1000000UL;
421  uart_char_delay = 8;
422  break;
423  default:
424  high_br = 1000000UL;
425  uart_char_delay = 8;
426  break;
427  }
428  if(high_br == 0) {
429  vAHI_UartSetClockDivisor(uart_dev, low_br);
430  } else {
431  uart_driver_set_high_baudrate(uart_dev, high_br);
432  }
433 }
434 /****************************************************************************
435  *
436  * NAME: uart_driver_set_high_baudrate
437  *
438  * DESCRIPTION:
439  * Sets the baud rate for the specified uart
440  *
441  * PARAMETERS: Name RW Usage
442  * uart_dev R UART to initialise, eg, E_AHI_UART_0
443  * baud_rate R Baudrate to use (bps eg 921600)
444  *
445  * RETURNS:
446  * void
447  *
448  ****************************************************************************/
449 static void
450 uart_driver_set_high_baudrate(uint8_t uart_dev, uint32_t baud_rate)
451 {
452  uint16 u16Divisor = 1;
453  uint32_t u32Remainder;
454  uint8_t u8ClocksPerBit = 16;
455 
456 #if (ENABLE_ADVANCED_BAUD_SELECTION)
457  /* Defining ENABLE_ADVANCED_BAUD_SELECTION in the Makefile
458  * enables this code which searches for a clocks per bit setting
459  * that gets closest to the configured rate.
460  */
461  uint32_t u32CalcBaudRate = 0;
462  int32 i32BaudError = 0x7FFFFFFF;
463 
464  DBG_vPrintf(DEBUG_UART_BUFFERED, "Config uart=%d, baud=%d\n", uart_dev,
465  baud_rate);
466 
467  while(ABS(i32BaudError) > (int32)(baud_rate >> 4)) { /* 6.25% (100/16) error */
468  if(--u8ClocksPerBit < 3) {
469  DBG_vPrintf(DEBUG_UART_BUFFERED,
470  "Could not calculate UART settings for target baud!");
471  return;
472  }
473 #endif /* ENABLE_ADVANCED_BAUD_SELECTION */
474 
475  /* Calculate Divisor register = 16MHz / (16 x baud rate) */
476  u16Divisor = (uint16)(16000000UL / ((u8ClocksPerBit + 1) * baud_rate));
477 
478  /* Correct for rounding errors */
479  u32Remainder =
480  (uint32_t)(16000000UL % ((u8ClocksPerBit + 1) * baud_rate));
481 
482  if(u32Remainder >= (((u8ClocksPerBit + 1) * baud_rate) / 2)) {
483  u16Divisor += 1;
484  }
485 #if (ENABLE_ADVANCED_BAUD_SELECTION)
486  DBG_vPrintf(DEBUG_UART_BUFFERED, "Divisor=%d, cpb=%d\n", u16Divisor,
487  u8ClocksPerBit);
488 
489  u32CalcBaudRate = (16000000UL / ((u8ClocksPerBit + 1) * u16Divisor));
490 
491  DBG_vPrintf(DEBUG_UART_BUFFERED, "Calculated baud=%d\n", u32CalcBaudRate);
492 
493  i32BaudError = (int32)u32CalcBaudRate - (int32)baud_rate;
494 
495  DBG_vPrintf(DEBUG_UART_BUFFERED, "Error baud=%d\n", i32BaudError);
496 }
497 DBG_vPrintf(DEBUG_UART_BUFFERED, "Config uart=%d: Divisor=%d, cpb=%d\n",
498  uart_dev, u16Divisor, u8ClocksPerBit);
499 
500 /* Set the calculated clocks per bit */
501 vAHI_UartSetClocksPerBit(uart_dev, u8ClocksPerBit);
502 #endif /* ENABLE_ADVANCED_BAUD_SELECTION */
503 
504  /* Set the calculated divisor */
505  vAHI_UartSetBaudDivisor(uart_dev, u16Divisor);
506 }
507 
508 /****************************************************************************
509  *
510  * NAME: uart_driver_isr
511  *
512  * DESCRIPTION:
513  * Interrupt service callback for UART's
514  *
515  * PARAMETERS: Name RW Usage
516  * device_id R Device ID of whatever generated the
517  * interrupt
518  * item_bitmap R Which part of the device generated
519  * the interrupt
520  *
521  * RETURNS:
522  * void
523  *
524  ****************************************************************************/
525 static void
526 uart_driver_isr(uint32_t device_id, uint32_t item_bitmap)
527 {
528  uint8_t uart_dev;
529  switch(device_id) {
530  case E_AHI_DEVICE_UART0:
531  uart_dev = E_AHI_UART_0;
532  break;
533  case E_AHI_DEVICE_UART1:
534  uart_dev = E_AHI_UART_1;
535  break;
536  default:
537  return;
538  }
539  switch(item_bitmap) {
540  /* byte available since a long time but RX-fifo not full: */
541  case E_AHI_UART_INT_TIMEOUT:
542  /* RX-fifo full: */
543  case E_AHI_UART_INT_RXDATA:
544  uart_driver_rx_handler(uart_dev);
545  break;
546  case E_AHI_UART_INT_TX:
547  break;
548  case E_AHI_UART_INT_RXLINE:
549  /* rx-line interrupt is disabled. Should not get here */
550  /* An error condition has occurred on the RxD line, such as
551  a break indication, framing error, parity error or over-run. */
552  break;
553  }
554 }
555 /****************************************************************************
556  *
557  * NAME: uart_driver_tx_in_progress
558  *
559  * DESCRIPTION:
560  * Returns the state of data transmission
561  *
562  * PARAMETERS: Name RW Usage
563  * uart_dev R UART to use, eg, E_AHI_UART_0
564  *
565  * RETURNS:
566  * uint8_t: TRUE if data in buffer is being transmitted
567  * FALSE if all data in buffer has been transmitted by the UART
568  *
569  ****************************************************************************/
570 uint8_t
571 uart_driver_tx_in_progress(uint8_t uart_dev)
572 {
573 
574  if(u16AHI_UartReadTxFifoLevel(uart_dev) == 0) {
575  if((u8AHI_UartReadLineStatus(uart_dev) & E_AHI_UART_LS_TEMT) != 0) {
576  return FALSE;
577  }
578  }
579  return TRUE;
580 }
581 #ifdef UART_EXTRAS
582 
583 /****************************************************************************
584  *
585  * NAME: uart_driver_flush
586  *
587  * DESCRIPTION:
588  * Flushes the buffers of the specified UART
589  *
590  * PARAMETERS: Name RW Usage
591  * uart_dev R UART to disable, eg, E_AHI_UART_0
592  * reset_tx R to reset the transmit FIFO
593  * reset_rx R to reset the receive FIFO
594  *
595  * RETURNS:
596  * void
597  *
598  ****************************************************************************/
599 void
600 uart_driver_flush(uint8_t uart_dev, bool_t reset_tx, bool_t reset_rx)
601 {
602  /* Disable TX Fifo empty and Rx data interrupts */
603  uart_driver_disable_interrupts(uart_dev);
604 
605  /* flush hardware buffer */
606  vAHI_UartReset(uart_dev, reset_tx, reset_rx);
607  vAHI_UartReset(uart_dev, FALSE, FALSE);
608 
609  /* Re-enable TX Fifo empty and Rx data interrupts */
610  uart_driver_enable_interrupts(uart_dev);
611 }
612 #endif /* UART_EXTRAS */
Header file for the dbg-io module.
Header file for the real-time timer module.
Header file for the Contiki process interface.
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:85