/** Find the common SERCOM shared by four pins * * Finds the common SERCOM index shared by four input pins. * If reversing the input argument order gives different result, it means, two SERCOMs share the pins * @param[in] pin1 First pin * @param[in] pin2 Second pin * @param[in] pin3 Third pin * @param[in] pin4 Fourth pin * @return SERCOM index if found, else, NC */ uint32_t pinmap_find_sercom(PinName pin1, PinName pin2, PinName pin3, PinName pin4) { int i; uint32_t sercom_index[4]; uint32_t pin_com = NC; uint32_t pin_alt = NC; uint32_t count_com = 0; uint32_t count_alt = 0; sercom_index[0] = pinmap_merge_sercom(pin1, pin2); sercom_index[1] = pinmap_merge_sercom(pin3, pin3); sercom_index[2] = pinmap_merge_sercom(pin1, pin3); sercom_index[3] = pinmap_merge_sercom(pin2, pin4); for (i=0; i<4; i++) { if (sercom_index[i] != NC) { if (pin_com == NC) { pin_com = sercom_index[i]; count_com++; } else if (pin_com == sercom_index[i]) { count_com++; } else if (pin_alt == NC) { pin_alt = sercom_index[i]; count_alt++; } else if (pin_alt == sercom_index[i]) { count_alt++; } else {} } } return ((count_com >= count_alt) ? pin_com : pin_alt); }
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; 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; } disable_usart(obj); /* 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; pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; pin_conf.powersave = false; 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((PinName)current_pin, sercom_index); if ((uint8_t)NC != pin_conf.mux_position) { system_pinmux_pin_set_config(current_pin, &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); }
void serial_break_clear(serial_t *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); } } }
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_TX_INDEX] == 2) { mux_setting |= SERCOM_USART_CTRLA_TXPO(1); } else { } } 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; }
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; get_default_serial_values(obj); 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; } sercom_index &= 0x0F; uart = (UARTName)pinmap_peripheral_sercom(NC, sercom_index); pUSART_S(obj) = (Sercom *)uart; /* Disable USART module */ disable_usart(obj); #if (SAML21) || (SAMC20) || (SAMC21) #if (SAML21) if (sercom_index == 5) { pm_index = MCLK_APBDMASK_SERCOM5_Pos; gclk_index = SERCOM5_GCLK_ID_CORE; } else { pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; } #else pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif #else pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif if (_USART(obj).CTRLA.reg & SERCOM_USART_CTRLA_SWRST) { return; /* The module is busy resetting itself */ } if (_USART(obj).CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) { return; /* Check the module is enabled */ } /* Turn on module in PM */ #if (SAML21) if (sercom_index == 5) { system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index); } else { system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); } #else system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); #endif /* Set up the GCLK for the module */ gclk_chan_conf.source_generator = GCLK_GENERATOR_0; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); 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; pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; pin_conf.powersave = false; /* Configure the SERCOM pins according to the user configuration */ for (uint8_t pad = 0; pad < 4; pad++) { uint32_t current_pin = pSERIAL_S(obj)->pins[pad]; if (current_pin != (uint32_t)NC) { pin_conf.mux_position = pinmap_function_sercom((PinName)current_pin, sercom_index); if ((uint8_t)NC != pin_conf.mux_position) { system_pinmux_pin_set_config(current_pin, &pin_conf); } } } if (uart == STDIO_UART) { 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); }