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) ); struct system_gclk_chan_config gclk_chan_conf; uint32_t gclk_index; uint16_t baud = 0; uint32_t sercom_index = 0; enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; pSERIAL_S(obj)->baudrate = baudrate; disable_usart(obj); sercom_index = _sercom_get_sercom_inst_index(pUSART_S(obj)); #if (SAML21) || (SAMC20) || (SAMC21) #if (SAML21) if (sercom_index == 5) { gclk_index = SERCOM5_GCLK_ID_CORE; } else { gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; } #else gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif #else gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif 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); /* Get baud value from mode and clock */ _sercom_get_async_baud_val(pSERIAL_S(obj)->baudrate, system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num); /* Wait until synchronization is complete */ usart_syncing(obj); /*Set baud val */ _USART(obj).BAUD.reg = baud; /* Wait until synchronization is complete */ usart_syncing(obj); enable_usart(obj); }
/** * \brief Set the baudrate of the SPI module * * This function will set the baudrate of the SPI module. * * \param[in] module Pointer to the software instance struct * \param[in] baudrate The baudrate wanted * * \return The status of the configuration. * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided * \retval STATUS_OK If the configuration was written */ enum status_code spi_set_baudrate( struct spi_module *const module, uint32_t baudrate) { /* Sanity check arguments */ Assert(module); Assert(baudrate); Assert(module->hw); /* Value to write to BAUD register */ uint16_t baud = 0; SercomSpi *const spi_module = &(module->hw->SPI); /* Disable the module */ spi_disable(module); while (spi_is_syncing(module)) { /* Wait until the synchronization is complete */ } /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index); /* Get baud value, based on baudrate and the internal clock frequency */ enum status_code error_code = _sercom_get_sync_baud_val( baudrate, internal_clock, &baud); if (error_code != STATUS_OK) { /* Baud rate calculation error, return status code */ return STATUS_ERR_INVALID_ARG; } spi_module->BAUD.reg = (uint8_t)baud; while (spi_is_syncing(module)) { /* Wait until the synchronization is complete */ } /* Enable the module */ spi_enable(module); while (spi_is_syncing(module)) { /* Wait until the synchronization is complete */ } return STATUS_OK; }
static inline void spi_disable(spi_t *obj) { /* Sanity check arguments */ MBED_ASSERT(obj); #if DEVICE_SPI_ASYNCH /* Disable interrupt */ NVIC_DisableIRQ(SERCOM0_IRQn + _sercom_get_sercom_inst_index(pSPI_SERCOM(obj))); #endif /* Wait until the synchronization is complete */ while (spi_is_syncing(obj)); /* Disable SPI */ _SPI(obj).CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE; }
/** * \brief Initializes the requested I<SUP>2</SUP>C hardware module * * Initializes the SERCOM I<SUP>2</SUP>C slave device requested and sets the provided * software module struct. Run this function before any further use of * the driver. * * \param[out] module Pointer to software module struct * \param[in] hw Pointer to the hardware instance * \param[in] config Pointer to the configuration struct * * \return Status of initialization. * \retval STATUS_OK Module initiated correctly * \retval STATUS_ERR_DENIED If module is enabled * \retval STATUS_BUSY If module is busy resetting * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than * previously set */ enum status_code i2c_slave_init( struct i2c_slave_module *const module, Sercom *const hw, const struct i2c_slave_config *const config) { /* Sanity check arguments */ Assert(module); Assert(hw); Assert(config); /* Initialize software module */ module->hw = hw; SercomI2cs *const i2c_hw = &(module->hw->I2CS); /* Check if module is enabled */ if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_ENABLE) { return STATUS_ERR_DENIED; } /* Check if reset is in progress */ if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_SWRST) { return STATUS_BUSY; } uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); uint32_t pm_index, gclk_index; #if (SAML21) || (SAML22) || (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 /* 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 */ struct system_gclk_chan_config gclk_chan_conf; system_gclk_chan_get_config_defaults(&gclk_chan_conf); gclk_chan_conf.source_generator = config->generator_source; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(config->generator_source, false); #if I2C_SLAVE_CALLBACK_MODE == true /* Get sercom instance index */ uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw); /* Save software module in interrupt handler */ _sercom_set_handler(instance_index, _i2c_slave_interrupt_handler); /* Save software module */ _sercom_instances[instance_index] = module; /* Initialize values in module */ module->registered_callback = 0; module->enabled_callback = 0; module->buffer_length = 0; module->nack_on_address = config->enable_nack_on_address; #endif /* Set SERCOM module to operate in I2C slave mode */ i2c_hw->CTRLA.reg = SERCOM_I2CS_CTRLA_MODE(0x4); /* Set config and return status */ return _i2c_slave_set_config(module, config); }
/** * \internal Sets configurations to module * * \param[out] module Pointer to software module structure. * \param[in] config Configuration structure with configurations to set. * * \return Status of setting configuration. * \retval STATUS_OK If module was configured correctly * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than * previously set * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baud rate is not compatible * with set GCLK frequency */ static enum status_code _i2c_master_set_config( struct i2c_master_module *const module, const struct i2c_master_config *const config) { /* Sanity check arguments. */ Assert(module); Assert(module->hw); Assert(config); /* Temporary variables. */ uint32_t tmp_ctrla; int32_t tmp_baud; enum status_code tmp_status_code = STATUS_OK; SercomI2cm *const i2c_module = &(module->hw->I2CM); Sercom *const sercom_hw = module->hw; uint8_t sercom_index = _sercom_get_sercom_inst_index(sercom_hw); /* Pin configuration */ uint32_t pad0 = config->pinmux_pad0; uint32_t pad1 = config->pinmux_pad1; /* SERCOM PAD0 - SDA */ if (pad0 == PINMUX_DEFAULT) { pad0 = _sercom_get_default_pad(sercom_hw, 0); } system_pinmux_pin_set_config(pad0 >> 16, pad0 & 0xFFFF, SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK, SYSTEM_PINMUX_PIN_PULL_UP, false); /* SERCOM PAD1 - SCL */ if (pad1 == PINMUX_DEFAULT) { pad1 = _sercom_get_default_pad(sercom_hw, 1); } system_pinmux_pin_set_config(pad1 >> 16, pad1 & 0xFFFF, SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK, SYSTEM_PINMUX_PIN_PULL_UP, false); /* Save timeout on unknown bus state in software module. */ module->unknown_bus_state_timeout = config->unknown_bus_state_timeout; /* Save timeout on buffer write. */ module->buffer_timeout = config->buffer_timeout; /* Set whether module should run in standby. */ if (config->run_in_standby || system_is_debugger_present()) { tmp_ctrla = SERCOM_I2CM_CTRLA_RUNSTDBY; } else { tmp_ctrla = 0; } /* Check and set start data hold timeout. */ if (config->start_hold_time != I2C_MASTER_START_HOLD_TIME_DISABLED) { tmp_ctrla |= config->start_hold_time; } /* Check and set SCL low timeout. */ if (config->scl_low_timeout) { tmp_ctrla |= SERCOM_I2CM_CTRLA_LOWTOUT; } /* Check and set inactive bus timeout. */ if (config->inactive_timeout != I2C_MASTER_INACTIVE_TIMEOUT_DISABLED) { tmp_ctrla |= config->inactive_timeout; } /* Write config to register CTRLA. */ i2c_module->CTRLA.reg |= tmp_ctrla; /* Set configurations in CTRLB. */ i2c_module->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; /* Find and set baudrate. */ tmp_baud = (int32_t)(system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index) / (2000*(config->baud_rate)) - 5); /* Check that baud rate is supported at current speed. */ if (tmp_baud > 255 || tmp_baud < 0) { /* Baud rate not supported. */ tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE; } else { /* Baud rate acceptable. */ i2c_module->BAUD.reg = (uint8_t)tmp_baud; } return tmp_status_code; }
/** * \brief Initializes the requested I<SUP>2</SUP>C hardware module * * Initializes the SERCOM I<SUP>2</SUP>C master device requested and sets the provided * software module struct. Run this function before any further use of * the driver. * * \param[out] module Pointer to software module struct * \param[in] hw Pointer to the hardware instance * \param[in] config Pointer to the configuration struct * * \return Status of initialization. * \retval STATUS_OK Module initiated correctly * \retval STATUS_ERR_DENIED If module is enabled * \retval STATUS_BUSY If module is busy resetting * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than * previously set * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible * with set GCLK frequency * */ enum status_code i2c_master_init( struct i2c_master_module *const module, Sercom *const hw, const struct i2c_master_config *const config) { /* Sanity check arguments. */ Assert(module); Assert(hw); Assert(config); /* Initialize software module */ module->hw = hw; SercomI2cm *const i2c_module = &(module->hw->I2CM); uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; /* Turn on module in PM */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); /* Set up the GCLK for the module */ system_gclk_chan_set_config(gclk_index, config->generator_source); system_gclk_chan_enable(gclk_index); _sercom_set_gclk_generator(config->generator_source); /* Check if module is enabled. */ if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_ENABLE) { return STATUS_ERR_DENIED; } /* Check if reset is in progress. */ if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST) { return STATUS_BUSY; } #if I2C_MASTER_CALLBACK_MODE == true /* Get sercom instance index and register callback. */ uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw); _sercom_set_handler(instance_index, _i2c_master_interrupt_handler); _sercom_instances[instance_index] = module; /* Initialize values in module. */ module->registered_callback = 0; module->enabled_callback = 0; module->buffer_length = 0; module->buffer_remaining = 0; module->status = STATUS_OK; module->buffer = NULL; #endif /* Set sercom module to operate in I2C master mode. */ i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE_I2C_MASTER; /* Set config and return status. */ return _i2c_master_set_config(module, config); }
* * \param[in] sercom_instance Instance pointer * * \return Enum of system interrupt vector * \retval SYSTEM_INTERRUPT_MODULE_SERCOM0 * \retval SYSTEM_INTERRUPT_MODULE_SERCOM1 * \retval SYSTEM_INTERRUPT_MODULE_SERCOM2 * \retval SYSTEM_INTERRUPT_MODULE_SERCOM3 * \retval SYSTEM_INTERRUPT_MODULE_SERCOM4 * \retval SYSTEM_INTERRUPT_MODULE_SERCOM5 * \retval SYSTEM_INTERRUPT_MODULE_SERCOM6 * \retval SYSTEM_INTERRUPT_MODULE_SERCOM7 */ enum system_interrupt_vector _sercom_get_interrupt_vector( Sercom *const sercom_instance) { const uint8_t sercom_int_vectors[SERCOM_INST_NUM] = { MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_VECT_NUM, ~) }; /* Retrieve the index of the SERCOM being requested */ uint8_t instance_index = _sercom_get_sercom_inst_index(sercom_instance); /* Get the vector number from the lookup table for the requested SERCOM */ return (enum system_interrupt_vector)sercom_int_vectors[instance_index]; } /** Auto-generate a set of interrupt handlers for each SERCOM in the device */ MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_HANDLER, ~)
/** * \internal * Set Configuration of the USART module */ static enum status_code _usart_set_config( struct usart_module *const module, const struct usart_config *const config) { /* Sanity check arguments */ Assert(module); Assert(module->hw); /* Get a pointer to the hardware module instance */ SercomUsart *const usart_hw = &(module->hw->USART); /* Index for generic clock */ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; /* Cache new register values to minimize the number of register writes */ uint32_t ctrla = 0; uint32_t ctrlb = 0; uint16_t baud = 0; enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; #ifdef FEATURE_USART_OVER_SAMPLE switch (config->sample_rate) { case USART_SAMPLE_RATE_16X_ARITHMETIC: mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; break; case USART_SAMPLE_RATE_8X_ARITHMETIC: mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; sample_num = SERCOM_ASYNC_SAMPLE_NUM_8; break; case USART_SAMPLE_RATE_3X_ARITHMETIC: mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; sample_num = SERCOM_ASYNC_SAMPLE_NUM_3; break; case USART_SAMPLE_RATE_16X_FRACTIONAL: mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL; sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; break; case USART_SAMPLE_RATE_8X_FRACTIONAL: mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL; sample_num = SERCOM_ASYNC_SAMPLE_NUM_8; break; } #endif /* Set data order, internal muxing, and clock polarity */ ctrla = (uint32_t)config->data_order | (uint32_t)config->mux_setting | #ifdef FEATURE_USART_OVER_SAMPLE config->sample_adjustment | config->sample_rate | #endif #ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION (config->immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) | #endif (config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos); enum status_code status_code = STATUS_OK; /* Get baud value from mode and clock */ switch (config->transfer_mode) { case USART_TRANSFER_SYNCHRONOUSLY: if (!config->use_external_clock) { status_code = _sercom_get_sync_baud_val(config->baudrate, system_gclk_chan_get_hz(gclk_index), &baud); } break; case USART_TRANSFER_ASYNCHRONOUSLY: if (config->use_external_clock) { status_code = _sercom_get_async_baud_val(config->baudrate, config->ext_clock_freq, &baud, mode, sample_num); } else { status_code = _sercom_get_async_baud_val(config->baudrate, system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num); } break; } /* Check if calculating the baudrate failed */ if (status_code != STATUS_OK) { /* Abort */ return status_code; } #ifdef FEATURE_USART_IRDA if(config->encoding_format_enable) { usart_hw->RXPL.reg = config->receive_pulse_length; } #endif /* Wait until synchronization is complete */ _usart_wait_for_sync(module); /*Set baud val */ usart_hw->BAUD.reg = baud; /* Set sample mode */ ctrla |= config->transfer_mode; if (config->use_external_clock == false) { ctrla |= SERCOM_USART_CTRLA_MODE(0x1); } else { ctrla |= SERCOM_USART_CTRLA_MODE(0x0); } /* Set stopbits, character size and enable transceivers */ ctrlb = (uint32_t)config->stopbits | (uint32_t)config->character_size | #ifdef FEATURE_USART_IRDA (config->encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) | #endif #ifdef FEATURE_USART_START_FRAME_DECTION (config->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) | #endif #ifdef FEATURE_USART_COLLISION_DECTION (config->collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) | #endif (config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) | (config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos); /* Check parity mode bits */ if (config->parity != USART_PARITY_NONE) { #ifdef FEATURE_USART_LIN_SLAVE if(config->lin_slave_enable) { ctrla |= SERCOM_USART_CTRLA_FORM(0x5); } else { ctrla |= SERCOM_USART_CTRLA_FORM(1); } #else ctrla |= SERCOM_USART_CTRLA_FORM(1); #endif ctrlb |= config->parity; } else { #ifdef FEATURE_USART_LIN_SLAVE if(config->lin_slave_enable) { ctrla |= SERCOM_USART_CTRLA_FORM(0x4); } else { ctrla |= SERCOM_USART_CTRLA_FORM(0); } #else ctrla |= SERCOM_USART_CTRLA_FORM(0); #endif } /* Set whether module should run in standby. */ if (config->run_in_standby || system_is_debugger_present()) { ctrla |= SERCOM_USART_CTRLA_RUNSTDBY; } /* Wait until synchronization is complete */ _usart_wait_for_sync(module); /* Write configuration to CTRLB */ usart_hw->CTRLB.reg = ctrlb; /* Wait until synchronization is complete */ _usart_wait_for_sync(module); /* Write configuration to CTRLA */ usart_hw->CTRLA.reg = ctrla; return STATUS_OK; }
/** * \brief Initializes the device * * Initializes the USART device based on the setting specified in the * configuration struct. * * \param[out] module Pointer to USART device * \param[in] hw Pointer to USART hardware instance * \param[in] config Pointer to configuration struct * * \return Status of the initialization. * * \retval STATUS_OK The initialization was successful * \retval STATUS_BUSY The USART module is busy * resetting * \retval STATUS_ERR_DENIED The USART have not been disabled in * advance of initialization * \retval STATUS_ERR_INVALID_ARG The configuration struct contains * invalid configuration * \retval STATUS_ERR_ALREADY_INITIALIZED The SERCOM instance has already been * initialized with different clock * configuration * \retval STATUS_ERR_BAUD_UNAVAILABLE The BAUD rate given by the * configuration * struct cannot be reached with * the current clock configuration */ enum status_code usart_init( struct usart_module *const module, Sercom *const hw, const struct usart_config *const config) { /* Sanity check arguments */ Assert(module); Assert(hw); Assert(config); enum status_code status_code = STATUS_OK; /* Assign module pointer to software instance struct */ module->hw = hw; /* Get a pointer to the hardware module instance */ SercomUsart *const usart_hw = &(module->hw->USART); uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); #if (SAML21) uint32_t pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; #else uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; #endif uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) { /* The module is busy resetting itself */ return STATUS_BUSY; } if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) { /* Check the module is enabled */ return STATUS_ERR_DENIED; } /* Turn on module in PM */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); /* Set up the GCLK for the module */ struct system_gclk_chan_config gclk_chan_conf; system_gclk_chan_get_config_defaults(&gclk_chan_conf); gclk_chan_conf.source_generator = config->generator_source; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(config->generator_source, false); /* Set character size */ module->character_size = config->character_size; /* Set transmitter and receiver status */ module->receiver_enabled = config->receiver_enable; module->transmitter_enabled = config->transmitter_enable; #ifdef FEATURE_USART_LIN_SLAVE module->lin_slave_enabled = config->lin_slave_enable; #endif #ifdef FEATURE_USART_START_FRAME_DECTION module->start_frame_detection_enabled = config->start_frame_detection_enable; #endif /* Set configuration according to the config struct */ status_code = _usart_set_config(module, config); if(status_code != STATUS_OK) { return status_code; } 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[] = { config->pinmux_pad0, config->pinmux_pad1, config->pinmux_pad2, config->pinmux_pad3 }; /* 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(hw, pad); } if (current_pinmux != PINMUX_UNUSED) { pin_conf.mux_position = current_pinmux & 0xFFFF; system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); } }
/** * \brief Initialize hardware and driver instance * * This function configures the clock system for the specified SERCOM module, * sets up the related pins and their MUX, initializes the SERCOM in SPI master * mode, and prepares the driver instance for operation. * * \pre \ref system_init() must have been called prior to this function. * * The SERCOM SPI module is left disabled after initialization, and must be * enabled with \ref spi_master_vec_enable() before a transfer can be done. * * \param[out] module Driver instance to initialize. * \param[in,out] sercom SERCOM module to initialize and associate driver * instance with. * \param[in] config Driver configuration to use. * * \return Status of initialization. * \retval STATUS_OK if initialization succeeded. * \retval STATUS_ERR_INVALID_ARG if driver has been misconfigured. */ enum status_code spi_master_vec_init(struct spi_master_vec_module *const module, Sercom *const sercom, const struct spi_master_vec_config *const config) { Assert(module); Assert(sercom); Assert(config); enum status_code status; SercomSpi *const spi_hw = &(sercom->SPI); struct system_gclk_chan_config gclk_chan_conf; uint16_t tmp_baud; uint32_t sercom_index = _sercom_get_sercom_inst_index((Sercom *)spi_hw); #if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) uint32_t pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; #else uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; #endif uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; uint32_t gclk_hz; module->sercom = sercom; /* Enable clock for the module interface */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); /* Set up the GCLK for the module */ system_gclk_chan_get_config_defaults(&gclk_chan_conf); gclk_chan_conf.source_generator = config->gclk_generator; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(config->gclk_generator, false); _spi_master_vec_wait_for_sync(spi_hw); /* Set up the SERCOM SPI module as master */ spi_hw->CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3); spi_hw->CTRLA.reg |= (uint32_t)config->mux_setting | config->transfer_mode | config->data_order | ((config->run_in_standby || system_is_debugger_present()) ? SERCOM_SPI_CTRLA_RUNSTDBY : 0); /* Get baud value from configured baudrate and internal clock rate */ gclk_hz = system_gclk_chan_get_hz(gclk_index); status = _sercom_get_sync_baud_val(config->baudrate, gclk_hz, &tmp_baud); if (status != STATUS_OK) { /* Baud rate calculation error! */ return STATUS_ERR_INVALID_ARG; } spi_hw->BAUD.reg = (uint8_t)tmp_baud; /* Configure the pin multiplexers */ _spi_master_vec_pinmux_helper(config->pinmux_pad0, sercom, 0); _spi_master_vec_pinmux_helper(config->pinmux_pad3, sercom, 3); /* SERCOM PAD1 and PAD2 are used for slave SS. * This is a SPI master driver, so control of slave SS must be left to * the PORT module, i.e., peripheral MUX should not be set for that pin. * DOPO controls which PAD is used for slave SS: * If DOPO is odd, SERCOM_PAD1 is SS: SERCOM_PAD2 can be MUXed. * If DOPO is even, SERCOM_PAD2 is SS: SERCOM_PAD1 can be MUXed. */ if (config->mux_setting & (1 << SERCOM_SPI_CTRLA_DOPO_Pos)) { _spi_master_vec_pinmux_helper(config->pinmux_pad2, sercom, 2); } else { _spi_master_vec_pinmux_helper(config->pinmux_pad1, sercom, 1); } /* Initialize our instance and register interrupt handler + data */ module->rx_bufdesc_ptr = NULL; module->tx_bufdesc_ptr = NULL; module->direction = SPI_MASTER_VEC_DIRECTION_IDLE; module->status = STATUS_OK; #ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE(module->busy_semaphore); #endif _sercom_set_handler(sercom_index, _spi_master_vec_int_handler); _sercom_instances[sercom_index] = module; return STATUS_OK; }
/** * \brief Initialize and enable debug UART * * This function sets up the configured SERCOM with the following static * features: * - asynchronous, internally clocked (UART) * - TX only * - 1 stop bit * - 8-bit data * - LSB first * - no parity bit * * The baud rate, SERCOM signal MUX and pin MUX are set up as configured in * \ref conf_debug_print.h, which also contains the configuration of which * SERCOM to use. * * The SERCOM UART is left enabled after this function call. * * \return Indication whether or not initialization succeeded. * \retval STATUS_OK if initialization was successful. * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE if configured baud rate is too high. * * \note This function is based on \ref usart_init() from ASF, but is modified * to use a single instance in order to reduce code size. */ enum status_code dbg_init(void) { enum status_code status = STATUS_OK; Sercom *const sercom = CONF_DBG_PRINT_SERCOM; struct system_gclk_chan_config gclk_chan_conf; struct system_pinmux_config pin_conf; uint16_t baud; uint32_t sercom_index, pm_index, gclk_index; #if defined(__FREERTOS__) || defined(__DOXYGEN__) dbg_is_free = xSemaphoreCreateMutex(); vSemaphoreCreateBinary(requested_space_is_free); xSemaphoreTake(requested_space_is_free, 0); #else requested_space_is_free = false; #endif // Get required indexes sercom_index = _sercom_get_sercom_inst_index(sercom); pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; // Turn on module in PM system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); // Set up the GCLK for the module system_gclk_chan_get_config_defaults(&gclk_chan_conf); gclk_chan_conf.source_generator = CONF_DBG_PRINT_GCLK_SOURCE; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(CONF_DBG_PRINT_GCLK_SOURCE, false); #if defined(CONF_DBG_PRINT_BAUD_VALUE) baud = CONF_DBG_PRINT_BAUD_VALUE; #else // Compute baud rate, if it is achievable status = _sercom_get_async_baud_val(CONF_DBG_PRINT_BAUD_RATE, system_gclk_chan_get_hz(gclk_index), &baud); if (status != STATUS_OK) { return status; } #endif sercom_uart->BAUD.reg = baud; sercom_uart->CTRLB.reg = SERCOM_USART_CTRLB_TXEN; sercom_uart->CTRLA.reg = SERCOM_USART_CTRLA_MODE_USART_INT_CLK | SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_ENABLE | CONF_DBG_PRINT_SERCOM_MUX | (system_is_debugger_present() ? SERCOM_USART_CTRLA_RUNSTDBY : 0); // Set up the pin MUXes system_pinmux_get_config_defaults(&pin_conf); pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; uint32_t pad_pinmuxes[] = { CONF_DBG_PRINT_PINMUX_PAD0, CONF_DBG_PRINT_PINMUX_PAD1, CONF_DBG_PRINT_PINMUX_PAD2, CONF_DBG_PRINT_PINMUX_PAD3, }; 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(sercom, pad); } if (current_pinmux != PINMUX_UNUSED) { pin_conf.mux_position = current_pinmux & 0xFFFF; system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); } }
/** * \internal Sets configurations to module * * \param[out] module Pointer to software module structure * \param[in] config Configuration structure with configurations to set * * \return Status of setting configuration. * \retval STATUS_OK If module was configured correctly * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than * previously set * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible * with set GCLK frequency */ static enum status_code _i2c_master_set_config( struct i2c_master_module *const module, const struct i2c_master_config *const config) { /* Sanity check arguments. */ Assert(module); Assert(module->hw); Assert(config); /* Temporary variables. */ uint32_t tmp_ctrla; int32_t tmp_baud; int32_t tmp_baud_hs; enum status_code tmp_status_code = STATUS_OK; SercomI2cm *const i2c_module = &(module->hw->I2CM); Sercom *const sercom_hw = module->hw; uint8_t sercom_index = _sercom_get_sercom_inst_index(sercom_hw); /* Pin configuration */ struct system_pinmux_config pin_conf; system_pinmux_get_config_defaults(&pin_conf); uint32_t pad0 = config->pinmux_pad0; uint32_t pad1 = config->pinmux_pad1; /* SERCOM PAD0 - SDA */ if (pad0 == PINMUX_DEFAULT) { pad0 = _sercom_get_default_pad(sercom_hw, 0); } pin_conf.mux_position = pad0 & 0xFFFF; pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK; system_pinmux_pin_set_config(pad0 >> 16, &pin_conf); /* SERCOM PAD1 - SCL */ if (pad1 == PINMUX_DEFAULT) { pad1 = _sercom_get_default_pad(sercom_hw, 1); } pin_conf.mux_position = pad1 & 0xFFFF; pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK; system_pinmux_pin_set_config(pad1 >> 16, &pin_conf); /* Save timeout on unknown bus state in software module. */ module->unknown_bus_state_timeout = config->unknown_bus_state_timeout; /* Save timeout on buffer write. */ module->buffer_timeout = config->buffer_timeout; /* Set whether module should run in standby. */ if (config->run_in_standby || system_is_debugger_present()) { tmp_ctrla = SERCOM_I2CM_CTRLA_RUNSTDBY; } else { tmp_ctrla = 0; } /* Check and set start data hold timeout. */ if (config->start_hold_time != I2C_MASTER_START_HOLD_TIME_DISABLED) { tmp_ctrla |= config->start_hold_time; } /* Check and set transfer speed */ tmp_ctrla |= config->transfer_speed; /* Check and set SCL low timeout. */ if (config->scl_low_timeout) { tmp_ctrla |= SERCOM_I2CM_CTRLA_LOWTOUTEN; } /* Check and set inactive bus timeout. */ if (config->inactive_timeout != I2C_MASTER_INACTIVE_TIMEOUT_DISABLED) { tmp_ctrla |= config->inactive_timeout; } /* Check and set SCL clock stretch mode. */ if (config->scl_stretch_only_after_ack_bit) { tmp_ctrla |= SERCOM_I2CM_CTRLA_SCLSM; } /* Check and set slave SCL low extend timeout. */ if (config->slave_scl_low_extend_timeout) { tmp_ctrla |= SERCOM_I2CM_CTRLA_SEXTTOEN; } /* Check and set master SCL low extend timeout. */ if (config->master_scl_low_extend_timeout) { tmp_ctrla |= SERCOM_I2CM_CTRLA_MEXTTOEN; } /* Write config to register CTRLA. */ i2c_module->CTRLA.reg |= tmp_ctrla; /* Set configurations in CTRLB. */ i2c_module->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; /* Find and set baudrate. */ tmp_baud = (int32_t)(div_ceil( system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index), (2000*(config->baud_rate))) - 5); /* Check that baudrate is supported at current speed. */ if (tmp_baud > 255 || tmp_baud < 0) { /* Baud rate not supported. */ tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE; } else { /* Find baudrate for high speed */ tmp_baud_hs = (int32_t)(div_ceil( system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index), (2000*(config->baud_rate_high_speed))) - 1); /* Check that baudrate is supported at current speed. */ if (tmp_baud_hs > 255 || tmp_baud_hs < 0) { /* Baud rate not supported. */ tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE; } } if (tmp_status_code != STATUS_ERR_BAUDRATE_UNAVAILABLE) { /* Baud rate acceptable. */ i2c_module->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud) | SERCOM_I2CM_BAUD_HSBAUD(tmp_baud_hs); } return tmp_status_code; }
/** * \internal * Set Configuration of the USART module */ static enum status_code _usart_set_config( struct usart_module *const module, const struct usart_config *const config) { /* Sanity check arguments */ Assert(module); Assert(module->hw); /* Get a pointer to the hardware module instance */ SercomUsart *const usart_hw = &(module->hw->USART); /* Index for generic clock */ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; /* Cache new register values to minimize the number of register writes */ uint32_t ctrla = 0; uint32_t ctrlb = 0; #ifdef FEATURE_USART_ISO7816 uint32_t ctrlc = 0; #endif uint16_t baud = 0; uint32_t transfer_mode; enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; #ifdef FEATURE_USART_OVER_SAMPLE switch (config->sample_rate) { case USART_SAMPLE_RATE_16X_ARITHMETIC: mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; break; case USART_SAMPLE_RATE_8X_ARITHMETIC: mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; sample_num = SERCOM_ASYNC_SAMPLE_NUM_8; break; case USART_SAMPLE_RATE_3X_ARITHMETIC: mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; sample_num = SERCOM_ASYNC_SAMPLE_NUM_3; break; case USART_SAMPLE_RATE_16X_FRACTIONAL: mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL; sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; break; case USART_SAMPLE_RATE_8X_FRACTIONAL: mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL; sample_num = SERCOM_ASYNC_SAMPLE_NUM_8; break; } #endif /* Set data order, internal muxing, and clock polarity */ ctrla = (uint32_t)config->data_order | (uint32_t)config->mux_setting | #ifdef FEATURE_USART_OVER_SAMPLE config->sample_adjustment | config->sample_rate | #endif #ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION (config->immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) | #endif (config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos); enum status_code status_code = STATUS_OK; transfer_mode = (uint32_t)config->transfer_mode; #ifdef FEATURE_USART_ISO7816 if(config->iso7816_config.enabled) { transfer_mode = config->iso7816_config.protocol_t; } #endif /* Get baud value from mode and clock */ #ifdef FEATURE_USART_ISO7816 if(config->iso7816_config.enabled) { baud = config->baudrate; } else { #endif switch (transfer_mode) { case USART_TRANSFER_SYNCHRONOUSLY: if (!config->use_external_clock) { status_code = _sercom_get_sync_baud_val(config->baudrate, system_gclk_chan_get_hz(gclk_index), &baud); } break; case USART_TRANSFER_ASYNCHRONOUSLY: if (config->use_external_clock) { status_code = _sercom_get_async_baud_val(config->baudrate, config->ext_clock_freq, &baud, mode, sample_num); } else { status_code = _sercom_get_async_baud_val(config->baudrate, system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num); } break; } /* Check if calculating the baudrate failed */ if (status_code != STATUS_OK) { /* Abort */ return status_code; } #ifdef FEATURE_USART_ISO7816 } #endif #ifdef FEATURE_USART_IRDA if(config->encoding_format_enable) { usart_hw->RXPL.reg = config->receive_pulse_length; } #endif /* Wait until synchronization is complete */ _usart_wait_for_sync(module); /*Set baud val */ usart_hw->BAUD.reg = baud; /* Set sample mode */ ctrla |= transfer_mode; if (config->use_external_clock == false) { ctrla |= SERCOM_USART_CTRLA_MODE(0x1); } else { ctrla |= SERCOM_USART_CTRLA_MODE(0x0); } /* Set stopbits and enable transceivers */ ctrlb = #ifdef FEATURE_USART_IRDA (config->encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) | #endif #ifdef FEATURE_USART_START_FRAME_DECTION (config->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) | #endif #ifdef FEATURE_USART_COLLISION_DECTION (config->collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) | #endif (config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) | (config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos); #ifdef FEATURE_USART_ISO7816 if(config->iso7816_config.enabled) { ctrla |= SERCOM_USART_CTRLA_FORM(0x07); if (config->iso7816_config.enable_inverse) { ctrla |= SERCOM_USART_CTRLA_TXINV | SERCOM_USART_CTRLA_RXINV; } ctrlb |= USART_CHARACTER_SIZE_8BIT; switch(config->iso7816_config.protocol_t) { case ISO7816_PROTOCOL_T_0: ctrlb |= (uint32_t)config->stopbits; ctrlc |= SERCOM_USART_CTRLC_GTIME(config->iso7816_config.guard_time) | \ (config->iso7816_config.inhibit_nack) | \ (config->iso7816_config.successive_recv_nack) | \ SERCOM_USART_CTRLC_MAXITER(config->iso7816_config.max_iterations); break; case ISO7816_PROTOCOL_T_1: ctrlb |= USART_STOPBITS_1; break; } } else { #endif ctrlb |= (uint32_t)config->character_size; /* Check parity mode bits */ if (config->parity != USART_PARITY_NONE) { ctrla |= SERCOM_USART_CTRLA_FORM(1); ctrlb |= config->parity; } else { #ifdef FEATURE_USART_LIN_SLAVE if(config->lin_slave_enable) { ctrla |= SERCOM_USART_CTRLA_FORM(0x4); } else { ctrla |= SERCOM_USART_CTRLA_FORM(0); } #else ctrla |= SERCOM_USART_CTRLA_FORM(0); #endif } #ifdef FEATURE_USART_ISO7816 } #endif #ifdef FEATURE_USART_LIN_MASTER usart_hw->CTRLC.reg = ((usart_hw->CTRLC.reg) & SERCOM_USART_CTRLC_GTIME_Msk) | config->lin_header_delay | config->lin_break_length; if (config->lin_node != LIN_INVALID_MODE) { ctrla &= ~(SERCOM_USART_CTRLA_FORM(0xf)); ctrla |= config->lin_node; } #endif /* Set whether module should run in standby. */ if (config->run_in_standby || system_is_debugger_present()) { ctrla |= SERCOM_USART_CTRLA_RUNSTDBY; } /* Wait until synchronization is complete */ _usart_wait_for_sync(module); /* Write configuration to CTRLB */ usart_hw->CTRLB.reg = ctrlb; /* Wait until synchronization is complete */ _usart_wait_for_sync(module); /* Write configuration to CTRLA */ usart_hw->CTRLA.reg = ctrla; #ifdef FEATURE_USART_RS485 if ((usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_FORM_Msk) != \ SERCOM_USART_CTRLA_FORM(0x07)) { usart_hw->CTRLC.reg &= ~(SERCOM_USART_CTRLC_GTIME(0x7)); usart_hw->CTRLC.reg |= SERCOM_USART_CTRLC_GTIME(config->rs485_guard_time); } #endif #ifdef FEATURE_USART_ISO7816 if(config->iso7816_config.enabled) { _usart_wait_for_sync(module); usart_hw->CTRLC.reg = ctrlc; } #endif return STATUS_OK; }
/** Initialize the SPI peripheral * * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral * @param[out] obj The SPI object to initialize * @param[in] mosi The pin to use for MOSI * @param[in] miso The pin to use for MISO * @param[in] sclk The pin to use for SCLK * @param[in] ssel The pin to use for SSEL */ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) { uint16_t baud = 0; uint32_t ctrla = 0; uint32_t ctrlb = 0; enum status_code error_code; if (g_sys_init == 0) { system_init(); g_sys_init = 1; } /* TODO: Calculate SERCOM instance from pins */ /* TEMP: Giving external SPI module value of SAMR21 for now */ pSPI_SERCOM(obj) = EXT1_SPI_MODULE; /* Disable SPI */ spi_disable(obj); /* Check if reset is in progress. */ if (_SPI(obj).CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) { return; } uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj)); uint32_t pm_index, gclk_index; #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 + PM_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif /* 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 */ struct system_gclk_chan_config gclk_chan_conf; system_gclk_chan_get_config_defaults(&gclk_chan_conf); 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); #if DEVICE_SPI_ASYNCH /* Save the object */ _sercom_instances[sercom_index] = obj; /* Configure interrupt handler */ NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)_sercom_handlers[sercom_index]); #endif /* Set the SERCOM in SPI master mode */ _SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3); pSPI_S(obj)->mode = SPI_MODE_MASTER; /* TODO: Do pin muxing here */ struct system_pinmux_config pin_conf; system_pinmux_get_config_defaults(&pin_conf); pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; uint32_t pad_pinmuxes[] = { EXT1_SPI_SERCOM_PINMUX_PAD0, EXT1_SPI_SERCOM_PINMUX_PAD1, EXT1_SPI_SERCOM_PINMUX_PAD2, EXT1_SPI_SERCOM_PINMUX_PAD3 }; /* 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_UNUSED) { pin_conf.mux_position = current_pinmux & 0xFFFF; system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); } }
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; /* Cache new register values to minimize the number of register writes */ uint32_t ctrla = 0; uint32_t ctrlb = 0; uint16_t baud = 0; enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; /* Set data order, internal muxing, and clock polarity */ ctrla = (uint32_t)USART_DATAORDER_LSB | // data order (uint32_t)pSERIAL_S(obj)->mux_setting; // mux setting // clock polarity is not used /* Get baud value from mode and clock */ _sercom_get_async_baud_val(pSERIAL_S(obj)->baudrate,system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num); // for asynchronous transfer mode /* Wait until synchronization is complete */ usart_syncing(obj); /*Set baud val */ _USART(obj).BAUD.reg = baud; /* Set sample mode */ ctrla |= USART_TRANSFER_ASYNCHRONOUSLY; /* for disabled external clock source */ ctrla |= SERCOM_USART_CTRLA_MODE(0x1); /* Set stopbits, character size and enable transceivers */ ctrlb = (uint32_t)pSERIAL_S(obj)->stopbits | (uint32_t)pSERIAL_S(obj)->character_size | SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN; /*transmitter and receiver enable*/ if (pSERIAL_S(obj)->pins[USART_RX_INDEX] == NC) { /* if pin is NC, have to disable the corresponding transmitter/receiver part */ ctrlb &= ~SERCOM_USART_CTRLB_RXEN; /* receiver disable */ } if (pSERIAL_S(obj)->pins[USART_TX_INDEX] == NC) { ctrlb &= ~SERCOM_USART_CTRLB_TXEN; /* transmitter disable */ } /* Check parity mode bits */ if (pSERIAL_S(obj)->parity != USART_PARITY_NONE) { ctrla |= SERCOM_USART_CTRLA_FORM(1); ctrlb |= pSERIAL_S(obj)->parity; } else { ctrla |= SERCOM_USART_CTRLA_FORM(0); } /* Wait until synchronization is complete */ usart_syncing(obj); /* Write configuration to CTRLB */ _USART(obj).CTRLB.reg = ctrlb; /* Wait until synchronization is complete */ usart_syncing(obj); /* Write configuration to CTRLA */ _USART(obj).CTRLA.reg = ctrla; return STATUS_OK; }