mbed library sources

Fork of mbed-src by mbed official

Revision:
592:a274ee790e56
Parent:
579:53297373a894
--- a/targets/hal/TARGET_Atmel/TARGET_SAM21/serial_api.c	Wed Jul 15 08:15:08 2015 +0100
+++ b/targets/hal/TARGET_Atmel/TARGET_SAM21/serial_api.c	Fri Jul 17 09:15:10 2015 +0100
@@ -20,7 +20,12 @@
 #include "pinmap.h"
 #include "PeripheralPins.h"
 #include "usart.h"
-#include "samr21_xplained_pro.h"
+#include "pinmap_function.h"
+
+#define USART_TX_INDEX		0
+#define USART_RX_INDEX		1
+#define USART_RXFLOW_INDEX	2
+#define USART_TXFLOW_INDEX	3
 
 #if DEVICE_SERIAL_ASYNCH
 #define pUSART_S(obj)			obj->serial.usart
@@ -35,6 +40,13 @@
 
 uint8_t serial_get_index(serial_t *obj);
 IRQn_Type get_serial_irq_num (serial_t *obj);
+uint32_t get_serial_vector (serial_t *obj);
+void uart0_irq();
+void uart1_irq();
+void uart2_irq();
+void uart3_irq();
+void uart4_irq();
+void uart5_irq();
 
 static uint32_t serial_irq_ids[USART_NUM] = {0};
 static uart_irq_handler irq_handler;
@@ -90,9 +102,54 @@
     _USART(obj).CTRLA.reg = SERCOM_USART_CTRLA_SWRST;
 }
 
-static enum status_code usart_set_config_default( serial_t *obj)
+uint32_t serial_find_mux_settings (serial_t *obj)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    uint32_t mux_setting = 0;
+    uint32_t pinpad[4] = {0};
+    uint8_t i = 0;
+    uint32_t sercom_index = pinmap_merge_sercom(pSERIAL_S(obj)->pins[0], pSERIAL_S(obj)->pins[1]);
 
+    for (i = 0; i < 4 ; i++) {
+        pinpad[i] = pinmap_pad_sercom(pSERIAL_S(obj)->pins[i], sercom_index);
+    }
+
+    switch(pinpad[USART_RX_INDEX]) {
+        case 0:
+            mux_setting |= SERCOM_USART_CTRLA_RXPO(0);
+            break;
+        case 1:
+            mux_setting |= SERCOM_USART_CTRLA_RXPO(1);
+            break;
+        case 2:
+            mux_setting |= SERCOM_USART_CTRLA_RXPO(2);
+            break;
+        case 3:
+            mux_setting |= SERCOM_USART_CTRLA_RXPO(3);
+            break;
+    }
+
+    if ((pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] == NC) && (pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] == NC)) {
+        if (pinpad[USART_TX_INDEX] == 0) {
+            mux_setting |= SERCOM_USART_CTRLA_TXPO(0);
+        } else if(pinpad[USART_RX_INDEX] == 2) {
+            mux_setting |= SERCOM_USART_CTRLA_TXPO(1);
+        } else {
+            mux_setting = mux_setting;  // dummy condition
+        }
+    } else { // for hardware flow control and uart // expecting the tx in pad 0, rts in pad2 and cts in pad 3
+        if((pinpad[USART_TX_INDEX] == 0) && (pinpad[USART_RXFLOW_INDEX]/*rts pin*/ == 2) && (pinpad[USART_TXFLOW_INDEX] /*cts pin*/ == 3)) {
+            mux_setting |= SERCOM_USART_CTRLA_TXPO(2);
+        }
+    }
+    return mux_setting;
+}
+
+static enum status_code usart_set_config_default(serial_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     /* Index for generic clock */
     uint32_t sercom_index = _sercom_get_sercom_inst_index(pUSART_S(obj));
     uint32_t gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
@@ -155,85 +212,60 @@
 
 void get_default_serial_values(serial_t *obj)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     /* Set default config to object */
     pSERIAL_S(obj)->parity = USART_PARITY_NONE;
     pSERIAL_S(obj)->stopbits = USART_STOPBITS_1;
     pSERIAL_S(obj)->character_size = USART_CHARACTER_SIZE_8BIT;
     pSERIAL_S(obj)->baudrate = 9600;
     pSERIAL_S(obj)->mux_setting = USART_RX_1_TX_2_XCK_3;
-    pSERIAL_S(obj)->pinmux_pad0 = PINMUX_DEFAULT;
-    pSERIAL_S(obj)->pinmux_pad1 = PINMUX_DEFAULT;
-    pSERIAL_S(obj)->pinmux_pad2 = PINMUX_DEFAULT;
-    pSERIAL_S(obj)->pinmux_pad3 = PINMUX_DEFAULT;
 };
 
 void serial_init(serial_t *obj, PinName tx, PinName rx)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     if (g_sys_init == 0) {
         system_init();
         g_sys_init = 1;
     }
-
     struct system_gclk_chan_config gclk_chan_conf;
     UARTName uart;
     uint32_t gclk_index;
     uint32_t pm_index;
     uint32_t sercom_index = 0;
     uint32_t muxsetting = 0;
-    uint32_t padsetting[4] = {0};
 
     /* Disable USART module */
     disable_usart(obj);
 
     get_default_serial_values(obj);
 
-    find_pin_settings(tx, rx, NC, NC, &padsetting[0]);  // tx, rx, clk(rts), chipsel(cts) pad array  // getting pads from pins
-    muxsetting = find_mux_setting(tx, rx, NC, NC);  // getting mux setting from pins
-    sercom_index = pinmap_sercom_peripheral(tx, rx);  // same variable sercom_index reused for optimization
-    switch (sercom_index) {
-        case 0:
-            uart = UART_0;
-            pUSART_S(obj) = SERCOM0;
-            break;
-        case 1:
-            uart = UART_1;
-            pUSART_S(obj) = SERCOM1;
-            break;
-        case 2:
-            uart = UART_2;
-            pUSART_S(obj) = SERCOM2;
-            break;
-        case 3:
-            uart = UART_3;
-            pUSART_S(obj) = SERCOM3;
-            break;
-        case 4:
-            uart = UART_4;
-            pUSART_S(obj) = SERCOM4;
-            break;
-        case 5:
-            uart = UART_5;
-            pUSART_S(obj) = SERCOM5;
-            break;
+    pSERIAL_S(obj)->pins[USART_TX_INDEX] = tx;
+    pSERIAL_S(obj)->pins[USART_RX_INDEX] = rx;
+    pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] = NC;
+    pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] = NC;
+
+    muxsetting = serial_find_mux_settings(obj);  // getting mux setting from pins
+    sercom_index = pinmap_merge_sercom(tx, rx);  // same variable sercom_index reused for optimization
+    if (sercom_index == (uint32_t)NC) {
+        /*expecting a valid value for sercom index*/
+        return;
     }
-
-    pSERIAL_S(obj)->txpin = tx;
-    pSERIAL_S(obj)->rxpin = rx;
-    pSERIAL_S(obj)->mux_setting = muxsetting;//EDBG_CDC_SERCOM_MUX_SETTING;
-    pSERIAL_S(obj)->pinmux_pad0 = padsetting[0];//EDBG_CDC_SERCOM_PINMUX_PAD0;
-    pSERIAL_S(obj)->pinmux_pad1 = padsetting[1];//EDBG_CDC_SERCOM_PINMUX_PAD1;
-    pSERIAL_S(obj)->pinmux_pad2 = padsetting[2];//EDBG_CDC_SERCOM_PINMUX_PAD2;
-    pSERIAL_S(obj)->pinmux_pad3 = padsetting[3];//EDBG_CDC_SERCOM_PINMUX_PAD3;
+    sercom_index &= 0x0F;
+    uart = pinmap_peripheral_sercom(NC, sercom_index);
+    pUSART_S(obj) = (Sercom *)uart;
 
     pm_index     = sercom_index + PM_APBCMASK_SERCOM0_Pos;
     gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
 
     if (_USART(obj).CTRLA.reg & SERCOM_USART_CTRLA_SWRST) {
-        /* The module is busy resetting itself */
+        return;  /* The module is busy resetting itself */
     }
 
     if (_USART(obj).CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) {
-        /* Check the module is enabled */
+        return;    /* Check the module is enabled */
     }
 
     /* Turn on module in PM */
@@ -245,29 +277,23 @@
     system_gclk_chan_enable(gclk_index);
     sercom_set_gclk_generator(GCLK_GENERATOR_0, false);
 
+    pSERIAL_S(obj)->mux_setting = muxsetting;
     /* Set configuration according to the config struct */
     usart_set_config_default(obj);
+
     struct system_pinmux_config pin_conf;
-    system_pinmux_get_config_defaults(&pin_conf);
     pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
     pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
-
-    uint32_t pad_pinmuxes[] = {
-        pSERIAL_S(obj)->pinmux_pad0, pSERIAL_S(obj)->pinmux_pad1,
-        pSERIAL_S(obj)->pinmux_pad2, pSERIAL_S(obj)->pinmux_pad3
-    };
+    pin_conf.powersave    = false;
 
     /* Configure the SERCOM pins according to the user configuration */
     for (uint8_t pad = 0; pad < 4; pad++) {
-        uint32_t current_pinmux = pad_pinmuxes[pad];
-
-        if (current_pinmux == PINMUX_DEFAULT) {
-            current_pinmux = _sercom_get_default_pad(pUSART_S(obj), pad);
-        }
-
-        if (current_pinmux != PINMUX_UNUSED) {
-            pin_conf.mux_position = current_pinmux & 0xFFFF;
-            system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf);
+        uint32_t current_pin = pSERIAL_S(obj)->pins[pad];
+        if (current_pin != (uint32_t)NC) {
+            pin_conf.mux_position = pinmap_function_sercom(current_pin, sercom_index);
+            if ((uint8_t)NC != pin_conf.mux_position) {
+                system_pinmux_pin_set_config(current_pin, &pin_conf);
+            }
         }
     }
 
@@ -275,23 +301,25 @@
         stdio_uart_inited = 1;
         memcpy(&stdio_uart, obj, sizeof(serial_t));
     }
-
     /* Wait until synchronization is complete */
     usart_syncing(obj);
 
     /* Enable USART module */
     enable_usart(obj);
-
 }
 
 void serial_free(serial_t *obj)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     serial_irq_ids[serial_get_index(obj)] = 0;
     disable_usart(obj);
 }
 
 void serial_baud(serial_t *obj, int baudrate)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     MBED_ASSERT((baudrate == 110) || (baudrate == 150) || (baudrate == 300) || (baudrate == 1200) ||
                 (baudrate == 2400) || (baudrate == 4800) || (baudrate == 9600) || (baudrate == 19200) || (baudrate == 38400) ||
                 (baudrate == 57600) || (baudrate == 115200) || (baudrate == 230400) || (baudrate == 460800) || (baudrate == 921600) );
@@ -330,6 +358,8 @@
 
 void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     MBED_ASSERT((stop_bits == 1) || (stop_bits == 2));
     MBED_ASSERT((parity == ParityNone) || (parity == ParityOdd) || (parity == ParityEven));
     MBED_ASSERT((data_bits == 5) || (data_bits == 6) || (data_bits == 7) || (data_bits == 8) /*|| (data_bits == 9)*/);
@@ -418,117 +448,114 @@
 }
 
 #ifdef DEVICE_SERIAL_FC
-void uart0_irq();
-void uart1_irq();
-void uart2_irq();
-void uart3_irq();
-void uart4_irq();
-void uart5_irq();
 
 void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     uint32_t muxsetting = 0;
     uint32_t sercom_index = 0;
-    uint32_t padsetting[4] = {0};
-
     IRQn_Type irq_n = (IRQn_Type)0;
     uint32_t vector = 0;
 
-    switch ((int)pUSART_S(obj)) {
-        case UART_0:
-            vector = (uint32_t)uart0_irq;
-            break;
-        case UART_1:
-            vector = (uint32_t)uart1_irq;
-            break;
-        case UART_2:
-            vector = (uint32_t)uart2_irq;
-            break;
-        case UART_3:
-            vector = (uint32_t)uart3_irq;
-            break;
-        case UART_4:
-            vector = (uint32_t)uart4_irq;
-            break;
-        case UART_5:
-            vector = (uint32_t)uart5_irq;
-            break;
+    pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] = rxflow;
+    pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] = txflow;
+    muxsetting = serial_find_mux_settings(obj);  // getting mux setting from pins
+    sercom_index = pinmap_merge_sercom(pSERIAL_S(obj)->pins[USART_TX_INDEX], pSERIAL_S(obj)->pins[USART_RX_INDEX]);  // same variable sercom_index reused for optimization
+    if (sercom_index == (uint32_t)NC) {
+        /*expecting a valid value for sercom index*/
+        return;
     }
+
+    vector = get_serial_vector(obj);
     irq_n = get_serial_irq_num(obj);
 
     disable_usart(obj);
-    //TODO : assert for rxflow and txflow pis to be added
-    find_pin_settings(pSERIAL_S(obj)->txpin, pSERIAL_S(obj)->rxpin, rxflow, txflow, &padsetting[0]);  // tx, rx, clk(rts), chipsel(cts) pad array  // getting pads from pins
-    muxsetting = find_mux_setting(pSERIAL_S(obj)->txpin, pSERIAL_S(obj)->rxpin, rxflow, txflow);  // getting mux setting from pins
-
-    pSERIAL_S(obj)->mux_setting = muxsetting;//EDBG_CDC_SERCOM_MUX_SETTING;
-    pSERIAL_S(obj)->pinmux_pad0 = padsetting[0];//EDBG_CDC_SERCOM_PINMUX_PAD0;
-    pSERIAL_S(obj)->pinmux_pad1 = padsetting[1];//EDBG_CDC_SERCOM_PINMUX_PAD1;
-    pSERIAL_S(obj)->pinmux_pad2 = padsetting[2];//EDBG_CDC_SERCOM_PINMUX_PAD2;
-    pSERIAL_S(obj)->pinmux_pad3 = padsetting[3];//EDBG_CDC_SERCOM_PINMUX_PAD3;
 
     /* Set configuration according to the config struct */
+    pSERIAL_S(obj)->mux_setting = muxsetting;  // mux setting to be changed for configuring hardware control
     usart_set_config_default(obj);
 
     struct system_pinmux_config pin_conf;
-    system_pinmux_get_config_defaults(&pin_conf);
     pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
     pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
-
-    uint32_t pad_pinmuxes[] = {
-        pSERIAL_S(obj)->pinmux_pad0, pSERIAL_S(obj)->pinmux_pad1,
-        pSERIAL_S(obj)->pinmux_pad2, pSERIAL_S(obj)->pinmux_pad3
-    };
+    pin_conf.powersave    = false;
 
-    /* Configure the SERCOM pins according to the user configuration */
-    for (uint8_t pad = 0; pad < 3; pad++) {
-        uint32_t current_pinmux = pad_pinmuxes[pad];
-
-        if (current_pinmux == PINMUX_DEFAULT) {
-            current_pinmux = _sercom_get_default_pad(pUSART_S(obj), pad);
-        }
-
-        if (current_pinmux != PINMUX_UNUSED) {
-            pin_conf.mux_position = current_pinmux & 0xFFFF;
-            system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf);
+    for (uint8_t pad = 0; pad < 2; pad++) {  // setting for rx and tx
+        uint32_t current_pin = pSERIAL_S(obj)->pins[pad];
+        if (current_pin != (uint32_t)NC) {
+            pin_conf.mux_position = pinmap_function_sercom(current_pin, sercom_index);
+            if ((uint8_t)NC != pin_conf.mux_position) {
+                system_pinmux_pin_set_config(current_pin, &pin_conf);
+            }
         }
     }
-    if (pSERIAL_S(obj)->pinmux_pad3 != PINMUX_UNUSED) {
-        pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_UP;
-        pin_conf.mux_position = pSERIAL_S(obj)->pinmux_pad3 & 0xFFFF;
-        system_pinmux_pin_set_config(pSERIAL_S(obj)->pinmux_pad3 >> 16, &pin_conf);
+    if((FlowControlRTS == type) || (FlowControlRTSCTS== type))  {
+        if (pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] != NC) {
+            pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; // setting for rxflow
+            pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_UP;
+            pin_conf.mux_position = pinmap_function_sercom(pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] , sercom_index);
+            if ((uint8_t)NC != pin_conf.mux_position) {
+                system_pinmux_pin_set_config(pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX], &pin_conf);
+            }
+        }
     }
+    if((FlowControlCTS == type) || (FlowControlRTSCTS== type)) {
+        if (pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] != NC) {
+            pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; // setting for txflow
+            pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_UP;
+            pin_conf.mux_position = pinmap_function_sercom(pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] , sercom_index);
+            if ((uint8_t)NC != pin_conf.mux_position) {
+                system_pinmux_pin_set_config(pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX], &pin_conf);
+            }
+        }
+    }
+    enable_usart(obj);
+}
 
-    NVIC_SetVector(irq_n, vector);
-    NVIC_EnableIRQ(irq_n);
-
-    enable_usart(obj);
-    _USART(obj).INTENSET.reg = SERCOM_USART_INTENCLR_CTSIC;
-}
+#endif  //DEVICE_SERIAL_FC
 
 void serial_break_set(serial_t *obj)
 {
-    disable_usart(obj);
-    _USART(obj).CTRLB.reg &= ~SERCOM_SPI_CTRLB_RXEN;
-    usart_syncing(obj);
-    enable_usart(obj);
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    struct system_pinmux_config pin_conf;
+    pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT;
+    pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
+    pin_conf.mux_position = SYSTEM_PINMUX_GPIO;
+    pin_conf.powersave    = false;
+
+    if (pSERIAL_S(obj)->pins[USART_TX_INDEX] != NC) {
+        system_pinmux_pin_set_config(pSERIAL_S(obj)->pins[USART_TX_INDEX], &pin_conf);
+    }
 }
 
 void serial_break_clear(serial_t *obj)
 {
-    disable_usart(obj);
-    _USART(obj).CTRLB.reg |= SERCOM_SPI_CTRLB_RXEN;
-    usart_syncing(obj);
-    enable_usart(obj);
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    uint32_t sercom_index = pinmap_merge_sercom(pSERIAL_S(obj)->pins[USART_TX_INDEX], pSERIAL_S(obj)->pins[USART_RX_INDEX]);
+
+    struct system_pinmux_config pin_conf;
+    pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
+    pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
+    pin_conf.powersave    = false;
+
+    if (pSERIAL_S(obj)->pins[USART_TX_INDEX] != NC) {
+        pin_conf.mux_position = pinmap_function_sercom(pSERIAL_S(obj)->pins[USART_TX_INDEX], sercom_index);
+        if ((uint8_t)NC != pin_conf.mux_position) {
+            system_pinmux_pin_set_config(pSERIAL_S(obj)->pins[USART_TX_INDEX], &pin_conf);
+        }
+    }
 }
 
-#endif  //DEVICE_SERIAL_FC
-
 /******************************************************************************
  * INTERRUPTS HANDLING
  ******************************************************************************/
 inline uint8_t serial_get_index(serial_t *obj)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     switch ((int)pUSART_S(obj)) {
         case UART_0:
             return 0;
@@ -545,8 +572,10 @@
     }
     return 0;
 }
+
 static inline void uart_irq(SercomUsart *const usart, uint32_t index)
 {
+    MBED_ASSERT(usart != (void*)0);
     uint16_t interrupt_status;
     interrupt_status = usart->INTFLAG.reg;
     interrupt_status &= usart->INTENSET.reg;
@@ -560,10 +589,6 @@
             usart->INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
             irq_handler(serial_irq_ids[index], RxIrq);
         }
-        if (interrupt_status & SERCOM_USART_INTFLAG_CTSIC) { // hardware flow control
-            usart->INTENCLR.reg = SERCOM_USART_INTENCLR_CTSIC;
-            usart->INTFLAG.reg = SERCOM_USART_INTENCLR_CTSIC;
-        }
     }
 }
 
@@ -597,37 +622,11 @@
     uart_irq((SercomUsart *)UART_5, 5);
 }
 
-void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
-{
-    irq_handler = handler;
-    serial_irq_ids[serial_get_index(obj)] = id;
-}
-
-IRQn_Type get_serial_irq_num (serial_t *obj)
+uint32_t get_serial_vector (serial_t *obj)
 {
-    switch ((int)pUSART_S(obj)) {
-        case UART_0:
-            return SERCOM0_IRQn;
-        case UART_1:
-            return SERCOM1_IRQn;
-        case UART_2:
-            return SERCOM2_IRQn;
-        case UART_3:
-            return SERCOM3_IRQn;
-        case UART_4:
-            return SERCOM4_IRQn;
-        case UART_5:
-            return SERCOM5_IRQn;
-        default:
-            MBED_ASSERT(0);
-    }
-}
-
-void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
-{
-    IRQn_Type irq_n = (IRQn_Type)0;
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     uint32_t vector = 0;
-
     switch ((int)pUSART_S(obj)) {
         case UART_0:
             vector = (uint32_t)uart0_irq;
@@ -648,6 +647,48 @@
             vector = (uint32_t)uart5_irq;
             break;
     }
+    return vector;
+}
+
+void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    irq_handler = handler;
+    serial_irq_ids[serial_get_index(obj)] = id;
+}
+
+IRQn_Type get_serial_irq_num (serial_t *obj)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    switch ((int)pUSART_S(obj)) {
+        case UART_0:
+            return SERCOM0_IRQn;
+        case UART_1:
+            return SERCOM1_IRQn;
+        case UART_2:
+            return SERCOM2_IRQn;
+        case UART_3:
+            return SERCOM3_IRQn;
+        case UART_4:
+            return SERCOM4_IRQn;
+        case UART_5:
+            return SERCOM5_IRQn;
+        default:
+            MBED_ASSERT(0);
+    }
+    return SERCOM0_IRQn; // to avoid warning
+}
+
+void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
+{
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    IRQn_Type irq_n = (IRQn_Type)0;
+    uint32_t vector = 0;
+
+    vector = get_serial_vector(obj);
     irq_n = get_serial_irq_num(obj);
 
     if (enable) {
@@ -680,12 +721,16 @@
  ******************************************************************************/
 int serial_getc(serial_t *obj)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     while (!serial_readable(obj));
     return _USART(obj).DATA.reg ;
 }
 
 void serial_putc(serial_t *obj, int c)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     uint16_t q = (c & SERCOM_USART_DATA_MASK);
     while (!serial_writable(obj));
     _USART(obj).DATA.reg = q;
@@ -694,6 +739,8 @@
 
 int serial_readable(serial_t *obj)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     uint32_t status = 1;
     if (!(_USART(obj).INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)) {
         status = 0;
@@ -705,6 +752,8 @@
 
 int serial_writable(serial_t *obj)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     uint32_t status = 1;
     if (!(_USART(obj).INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {
         status = 0;
@@ -725,6 +774,8 @@
  ***********************************/
 void serial_tx_enable_event(serial_t *obj, int event, uint8_t enable)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     if(enable) {
         pSERIAL_S(obj)->events |= event;
     } else {
@@ -734,6 +785,8 @@
 
 void serial_rx_enable_event(serial_t *obj, int event, uint8_t enable)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     if(enable) {
         pSERIAL_S(obj)->events |= event;
     } else {
@@ -743,6 +796,9 @@
 
 void serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    MBED_ASSERT(tx != (void*)0);
     // We only support byte buffers for now
     MBED_ASSERT(width == 8);
 
@@ -757,6 +813,9 @@
 
 void serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    MBED_ASSERT(rx != (void*)0);
     // We only support byte buffers for now
     MBED_ASSERT(width == 8);
 
@@ -771,6 +830,8 @@
 
 void serial_set_char_match(serial_t *obj, uint8_t char_match)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     if (char_match != SERIAL_RESERVED_CHAR_MATCH) {
         obj->char_match = char_match;
     }
@@ -781,6 +842,8 @@
  ***********************************/
 int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     MBED_ASSERT(tx != (void*)0);
     if(tx_length == 0) return 0;
 
@@ -790,7 +853,6 @@
 //    if( hint == DMA_USAGE_NEVER) {  //TODO: DMA to be implemented later
     NVIC_ClearPendingIRQ(get_serial_irq_num(obj));
     NVIC_DisableIRQ(get_serial_irq_num(obj));
-    NVIC_SetPriority(get_serial_irq_num(obj), 1);
     NVIC_SetVector(get_serial_irq_num(obj), (uint32_t)handler);
     NVIC_EnableIRQ(get_serial_irq_num(obj));
 
@@ -799,20 +861,23 @@
         _USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_DRE;
     }
 //	}
+    return 0;
 }
 
 void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     MBED_ASSERT(rx != (void*)0);
 
     serial_rx_enable_event(obj, SERIAL_EVENT_RX_ALL, false);
     serial_rx_enable_event(obj, event, true);
     serial_set_char_match(obj, char_match);
-
     serial_rx_buffer_set(obj, rx, rx_length, rx_width);
 
 //    if( hint == DMA_USAGE_NEVER) {  //TODO: DMA to be implemented later
     NVIC_ClearPendingIRQ(get_serial_irq_num(obj));
+    NVIC_DisableIRQ(get_serial_irq_num(obj));
     NVIC_SetVector(get_serial_irq_num(obj), (uint32_t)handler);
     NVIC_EnableIRQ(get_serial_irq_num(obj));
 
@@ -820,35 +885,43 @@
         _USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_RXC;
     }
 //	}
+    return;
 }
 
 uint8_t serial_tx_active(serial_t *obj)
 {
-    return ((_USART(obj).INTENSET.reg & SERCOM_USART_INTFLAG_DRE) ? true : false);
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    return ((obj->tx_buff.length > 0) ? true : false);
 }
 
 uint8_t serial_rx_active(serial_t *obj)
 {
-    return ((_USART(obj).INTENSET.reg & SERCOM_USART_INTFLAG_RXC) ? true : false);
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    return ((obj->rx_buff.length > 0) ? true : false);
 }
 
 int serial_tx_irq_handler_asynch(serial_t *obj)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     _USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_TXC;
+    serial_tx_abort_asynch(obj);
     return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
 }
 
 int serial_rx_irq_handler_asynch(serial_t *obj)
 {
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     int event = 0;
     /* This interrupt handler is called from USART irq */
     uint8_t *buf = (uint8_t*)obj->rx_buff.buffer;
     uint8_t error_code = 0;
     uint16_t received_data = 0;
 
-
     error_code = (uint8_t)(_USART(obj).STATUS.reg & SERCOM_USART_STATUS_MASK);
-
     /* Check if an error has occurred during the receiving */
     if (error_code) {
         /* Check which error occurred */
@@ -882,6 +955,7 @@
         if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) {
             event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
         }
+        _USART(obj).INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
         serial_rx_abort_asynch(obj);
         return event & obj->serial.events;
     }
@@ -891,20 +965,19 @@
         event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
     }
 
-    /* check for final char event */
-    if((obj->rx_buff.length) == 0) {
-        event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
-    }
-
+    /* Return to the call back if character match occured */
     if(event != 0) {
         serial_rx_abort_asynch(obj);
         return event & obj->serial.events;
     }
+    return 0;
 }
 
 int serial_irq_handler_asynch(serial_t *obj)
 {
 //TODO: DMA to be implemented
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
     uint16_t interrupt_status;
     uint8_t *buf = obj->tx_buff.buffer;
 
@@ -915,12 +988,9 @@
         if (interrupt_status & SERCOM_USART_INTFLAG_DRE) {
             /* Interrupt has another TX source */
             if(obj->tx_buff.pos >= obj->tx_buff.length) {
-
                 /* Transfer complete. Switch off interrupt and return event. */
                 _USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
-                serial_tx_abort_asynch(obj);
-
-                return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
+                _USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_TXC;
             } else {
                 while((serial_writable(obj)) && (obj->tx_buff.pos <= (obj->tx_buff.length - 1))) {
                     _USART(obj).DATA.reg = buf[obj->tx_buff.pos];
@@ -929,29 +999,34 @@
             }
         }
         if (interrupt_status & SERCOM_USART_INTFLAG_TXC) {
-            serial_tx_irq_handler_asynch(obj);
+            return serial_tx_irq_handler_asynch(obj);
         }
         if (interrupt_status & SERCOM_USART_INTFLAG_RXC) {
-            serial_rx_irq_handler_asynch(obj);
+            return serial_rx_irq_handler_asynch(obj);
         }
     }
-
+    return 0;
 }
 
 void serial_tx_abort_asynch(serial_t *obj)
 {
 //TODO: DMA to be implemented
-    _USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_TXC;
-    obj->tx_buff.pos = 0;
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    _USART(obj).INTFLAG.reg = SERCOM_USART_INTFLAG_TXC;
     obj->tx_buff.length = 0;
+    obj->rx_buff.pos = 0;
+
 }
 
 void serial_rx_abort_asynch(serial_t *obj)
 {
 //TODO: DMA to be implemented
-    _USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
+    /* Sanity check arguments */
+    MBED_ASSERT(obj);
+    _USART(obj).INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
+    obj->rx_buff.length = 0;
     obj->rx_buff.pos = 0;
-    obj->rx_buff.length = 0;
 }
 
 #endif
\ No newline at end of file