//! [setup] void configure_non_inverting_pga_opamp0(void) { /** Creates a new configuration structure for the OPAMP0. */ //! [setup_1] struct opamp0_config conf; //! [setup_1] /** Initializes OPAMP module. */ //! [setup_2] opamp_module_init(); //! [setup_2] /** Settings and fill with the default settings. */ //! [setup_3] opamp0_get_config_defaults(&conf); //! [setup_3] /* Set the the OPAMP0 as "Non-Inverting PGA" mode. */ //! [setup_4] conf.negative_input = OPAMP0_NEG_MUX_TAP0; conf.positive_input = OPAMP0_POS_MUX_PIN0; conf.r1_connection = OPAMP0_RES1_MUX_GND; conf.config_common.r1_enable = true; conf.config_common.r2_out = true; //! [setup_4] /* Set up OA0NEG pin and OA0OUT pin. */ //! [setup_5] struct system_pinmux_config opamp0_neg_pin_conf; system_pinmux_get_config_defaults(&opamp0_neg_pin_conf); opamp0_neg_pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; opamp0_neg_pin_conf.mux_position = MUX_PA06B_OPAMP_OAPOS0; system_pinmux_pin_set_config(PIN_PA06B_OPAMP_OAPOS0, &opamp0_neg_pin_conf); struct system_pinmux_config opamp0_out_pin_conf; system_pinmux_get_config_defaults(&opamp0_out_pin_conf); opamp0_out_pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; opamp0_out_pin_conf.mux_position = MUX_PA07B_OPAMP_OAOUT0; system_pinmux_pin_set_config(PIN_PA07B_OPAMP_OAOUT0, &opamp0_out_pin_conf); //! [setup_5] /** Initialize and enable the OPAMP0 with the user settings. */ //! [setup_6] opamp0_set_config(&conf); //! [setup_6] //! [setup_7] opamp_enable(OPAMP_0); //! [setup_7] /* Wait for the output ready. */ //! [setup_8] while(!opamp_is_ready(OPAMP_0)); //! [setup_8] }
/** * \internal Configure MUX settings for the analog pins * * This function will set the given SDADC input pins * to the analog function in the pinmux, giving * the SDADC access to the analog signal * * \param [in] pin AINxx pin to configure */ static inline void _sdadc_configure_ain_pin(uint32_t pin) { /* Pinmapping table for AINxx -> GPIO pin number */ const uint32_t pinmapping[] = { #if (SAMC21E) PIN_PA06B_SDADC_INN0, PIN_PA07B_SDADC_INP0, #elif (SAMC21G) PIN_PA06B_SDADC_INN0, PIN_PA07B_SDADC_INP0, PIN_PB08B_SDADC_INN1, PIN_PB09B_SDADC_INP1, #elif (SAMC21J) PIN_PA06B_SDADC_INN0, PIN_PA07B_SDADC_INP0, PIN_PB08B_SDADC_INN1, PIN_PB09B_SDADC_INP1, PIN_PB06B_SDADC_INN2, PIN_PB07B_SDADC_INP2, #else # error SDADC pin mappings are not defined for this device. #endif }; uint32_t pin_map_result; struct system_pinmux_config config; system_pinmux_get_config_defaults(&config); config.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; config.mux_position = 1; pin_map_result = pinmapping[pin * 2]; system_pinmux_pin_set_config(pin_map_result, &config); pin_map_result = pinmapping[pin * 2 + 1]; system_pinmux_pin_set_config(pin_map_result, &config); }
int main(void) { system_init(); //! [setup] //! [pinmux_config] struct system_pinmux_config config_pinmux; //! [pinmux_config] //! [pinmux_config_defaults] system_pinmux_get_config_defaults(&config_pinmux); //! [pinmux_config_defaults] //! [pinmux_update_config_values] config_pinmux.mux_position = SYSTEM_PINMUX_GPIO; config_pinmux.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; config_pinmux.input_pull = SYSTEM_PINMUX_PIN_PULL_UP; //! [pinmux_update_config_values] //! [pinmux_set_config] system_pinmux_pin_set_config(10, &config_pinmux); //! [pinmux_set_config] //! [setup] //! [main] //! [pinmux_change_input_sampling] system_pinmux_pin_set_input_sample_mode(10, SYSTEM_PINMUX_PIN_SAMPLE_ONDEMAND); //! [pinmux_change_input_sampling] while (true) { /* Infinite loop */ } //! [main] }
/** * \internal Writes an SPI SERCOM configuration to the hardware module. * * This function will write out a given configuration to the hardware module. * Can only be done when the module is disabled. * * \param[in] module Pointer to the software instance struct * \param[in] config Pointer to the configuration struct * * \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 */ static enum status_code _spi_set_config( struct spi_module *const module, const struct spi_config *const config) { /* Sanity check arguments */ Assert(module); Assert(config); Assert(module->hw); SercomSpi *const spi_module = &(module->hw->SPI); Sercom *const hw = module->hw; 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[] = { 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); } }
/** * \internal Sets configuration 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 Module was configured correctly * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than * previously set */ static enum status_code _i2c_slave_set_config( struct i2c_slave_module *const module, const struct i2c_slave_config *const config) { uint32_t tmp_ctrla; /* Sanity check arguments. */ Assert(module); Assert(module->hw); Assert(config); SercomI2cs *const i2c_hw = &(module->hw->I2CS); Sercom *const sercom_hw = module->hw; module->buffer_timeout = config->buffer_timeout; 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); /* Prepare config to write to register CTRLA */ if (config->run_in_standby || system_is_debugger_present()) { tmp_ctrla = SERCOM_I2CS_CTRLA_RUNSTDBY; } else { tmp_ctrla = 0; } tmp_ctrla |= config->sda_hold_time | (config->scl_low_timeout << SERCOM_I2CS_CTRLA_LOWTOUT_Pos); i2c_hw->CTRLA.reg |= tmp_ctrla; /* Set CTRLB configuration */ i2c_hw->CTRLB.reg = SERCOM_I2CS_CTRLB_SMEN | config->address_mode; i2c_hw->ADDR.reg = config->address << SERCOM_I2CS_ADDR_ADDR_Pos | config->address_mask << SERCOM_I2CS_ADDR_ADDRMASK_Pos | config->enable_general_call_address << SERCOM_I2CS_ADDR_GENCEN_Pos; return STATUS_OK; }
/** * \brief Initialize the DAC device struct. * * Use this function to initialize the Digital to Analog Converter. Resets the * underlying hardware module and configures it. * * \note The DAC channel must be configured separately. * * \param[out] module_inst Pointer to the DAC software instance struct * \param[in] module Pointer to the DAC module instance * \param[in] config Pointer to the config struct, created by the user * application * * \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 */ enum status_code dac_init( struct dac_module *const module_inst, Dac *const module, struct dac_config *const config) { /* Sanity check arguments */ Assert(module_inst); Assert(module); Assert(config); /* Initialize device instance */ module_inst->hw = module; /* Turn on the digital interface clock */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_DAC); /* Check if module is enabled. */ if (module->CTRLA.reg & DAC_CTRLA_ENABLE) { return STATUS_ERR_DENIED; } /* Check if reset is in progress. */ if (module->CTRLA.reg & DAC_CTRLA_SWRST) { return STATUS_BUSY; } /* Configure GCLK channel and enable clock */ struct system_gclk_chan_config gclk_chan_conf; system_gclk_chan_get_config_defaults(&gclk_chan_conf); gclk_chan_conf.source_generator = config->clock_source; system_gclk_chan_set_config(DAC_GCLK_ID, &gclk_chan_conf); system_gclk_chan_enable(DAC_GCLK_ID); /* MUX the DAC VOUT pin */ struct system_pinmux_config pin_conf; system_pinmux_get_config_defaults(&pin_conf); /* Set up the DAC VOUT pin */ pin_conf.mux_position = MUX_PA02B_DAC_VOUT; pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; system_pinmux_pin_set_config(PIN_PA02B_DAC_VOUT, &pin_conf); /* Write configuration to module */ _dac_set_config(module_inst, config); /* Store reference selection for later use */ module_inst->reference = config->reference; #if DAC_CALLBACK_MODE == true for (uint8_t i = 0; i < DAC_CALLBACK_N; i++) { module_inst->callback[i] = NULL; }; _dac_instances[0] = module_inst; #endif return STATUS_OK; }
/** * \brief Writes an External Interrupt channel configuration to the hardware module. * * Writes out a given configuration of an External Interrupt channel * configuration to the hardware module. If the channel is already configured, * the new configuration will replace the existing one. * * \param[in] channel External Interrupt channel to configure * \param[in] config Configuration settings for the channel */ void extint_chan_set_config( const uint8_t channel, const struct extint_chan_conf *const config) { /* Sanity check arguments */ Assert(config); _extint_disable(); #if(EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) /* Sanity check clock requirements */ Assert(!(!system_gclk_gen_is_enabled(EXTINT_CLOCK_SOURCE) && _extint_is_gclk_required(config->filter_input_signal, config->detection_criteria))); #endif struct system_pinmux_config pinmux_config; system_pinmux_get_config_defaults(&pinmux_config); pinmux_config.mux_position = config->gpio_pin_mux; pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->gpio_pin_pull; system_pinmux_pin_set_config(config->gpio_pin, &pinmux_config); /* Get a pointer to the module hardware instance */ Eic *const EIC_module = _extint_get_eic_from_channel(channel); uint32_t config_pos = (4 * (channel % 8)); uint32_t new_config; /* Determine the channel's new edge detection configuration */ new_config = (config->detection_criteria << EIC_CONFIG_SENSE0_Pos); /* Enable the hardware signal filter if requested in the config */ if (config->filter_input_signal) { new_config |= EIC_CONFIG_FILTEN0; } /* Clear the existing and set the new channel configuration */ EIC_module->CONFIG[channel / 8].reg = (EIC_module->CONFIG[channel / 8].reg & ~((EIC_CONFIG_SENSE0_Msk | EIC_CONFIG_FILTEN0) << config_pos)) | (new_config << config_pos); #if (SAML22) || (SAML21XXXB) || (SAMC20) || (SAMR30) /* Config asynchronous edge detection */ if (config->enable_async_edge_detection) { EIC_module->ASYNCH.reg |= (1UL << channel); } else { EIC_module->ASYNCH.reg &= (EIC_ASYNCH_MASK & (~(1UL << channel))); } #endif #if (SAMC21) /* Config asynchronous edge detection */ if (config->enable_async_edge_detection) { EIC_module->EIC_ASYNCH.reg |= (1UL << channel); } else { EIC_module->EIC_ASYNCH.reg &= (EIC_EIC_ASYNCH_MASK & (~(1UL << channel))); } #endif _extint_enable(); }
static void clock_output(void) { /* Configure a GPIO pin as the CPU clock output */ struct system_pinmux_config clk_out_pin; system_pinmux_get_config_defaults(&clk_out_pin); clk_out_pin.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; clk_out_pin.mux_position = MUX_PA22H_GCLK_IO6; system_pinmux_pin_set_config(PIN_PA22H_GCLK_IO6, &clk_out_pin); }
/** * \internal * \brief Setup Function: AC callback mode test. * * This function initializes the AC to generate interrupt when the AC * output toggles. * * \param test Current test case. */ static void setup_ac_callback_mode_test(const struct test_case *test) { enum status_code status = STATUS_ERR_IO; /* Structure for AC configuration */ struct ac_config config; struct ac_chan_config channel_config; /* Set the flag to false */ ac_init_success = false; ac_reset(&ac_inst); ac_get_config_defaults(&config); /* Initialize the AC */ status = ac_init(&ac_inst, AC, &config); /* Check for successful initialization */ test_assert_true(test, status == STATUS_OK, "AC initialization failed"); /* Configure the AC input pin */ struct system_pinmux_config ac0_pin_conf; system_pinmux_get_config_defaults(&ac0_pin_conf); ac0_pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; ac0_pin_conf.mux_position = MUX_PA04B_AC_AIN0; system_pinmux_pin_set_config(PIN_PA04B_AC_AIN0, &ac0_pin_conf); /* Channel configuration */ status = STATUS_ERR_IO; ac_chan_get_config_defaults(&channel_config); channel_config.sample_mode = AC_CHAN_MODE_CONTINUOUS; channel_config.positive_input = AC_CHAN_POS_MUX_PIN0; channel_config.negative_input = AC_CHAN_NEG_MUX_SCALED_VCC; channel_config.vcc_scale_factor = AC_SCALER_0_50_VOLT; status = ac_chan_set_config(&ac_inst, AC_CHAN_CHANNEL_0, &channel_config); /* Check for successful initialization */ test_assert_true(test, status == STATUS_OK, "AC channel initialization failed"); /* Callback configuration */ status = ac_register_callback(&ac_inst, ac_user_callback, AC_CALLBACK_COMPARATOR_0); test_assert_true(test, status == STATUS_OK, "AC callback registration failed"); /* Enable the AC channel & the module */ ac_chan_enable(&ac_inst, AC_CHAN_CHANNEL_0); ac_enable(&ac_inst); ac_enable_callback(&ac_inst, AC_CALLBACK_COMPARATOR_0); if (status == STATUS_OK) { ac_init_success = true; } }
/** * \brief Writes a DAC channel configuration to the hardware module. * * Writes out a given channel configuration to the hardware module. * * \note The DAC device instance structure must be initialized before calling * this function. * * \param[in] module_inst Pointer to the DAC software instance struct * \param[in] channel Channel to configure * \param[in] config Pointer to the configuration struct * */ void dac_chan_set_config( struct dac_module *const module_inst, const enum dac_channel channel, struct dac_chan_config *const config) { /* Sanity check arguments */ Assert(module_inst); Assert(module_inst->hw); Assert(config); /* MUX the DAC VOUT pin */ 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; if(channel == DAC_CHANNEL_0) { /* Set up the DAC VOUT0 pin */ pin_conf.mux_position = MUX_PA02B_DAC_VOUT0; system_pinmux_pin_set_config(PIN_PA02B_DAC_VOUT0, &pin_conf); } else if(channel == DAC_CHANNEL_1) { /* Set up the DAC VOUT1 pin */ pin_conf.mux_position = MUX_PA05B_DAC_VOUT1; system_pinmux_pin_set_config(PIN_PA05B_DAC_VOUT1, &pin_conf); } Dac *const dac_module = module_inst->hw; uint32_t new_dacctrl = 0; /* Left adjust data if configured */ if (config->left_adjust) { new_dacctrl |= DAC_DACCTRL_LEFTADJ; } /* Set current control */ new_dacctrl |= config->current; /* Enable DAC in standby sleep mode if configured */ if (config->run_in_standby) { new_dacctrl |= DAC_DACCTRL_RUNSTDBY; } /* Voltage pump disable if configured */ if (config->dither_mode) { new_dacctrl |= DAC_DACCTRL_DITHER; } new_dacctrl |= DAC_DACCTRL_REFRESH(config->refresh_period); /* Apply the new configuration to the hardware module */ dac_module->DACCTRL[channel].reg = new_dacctrl; }
/** * \internal Sets configuration 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 Module was configured correctly * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than * previously set */ static enum status_code _i2c_slave_set_config( struct i2c_slave_module *const module, const struct i2c_slave_config *const config) { /* Sanity check arguments. */ Assert(module); Assert(module->hw); Assert(config); SercomI2cs *const i2c_hw = &(module->hw->I2CS); Sercom *const sercom_hw = module->hw; module->buffer_timeout = config->buffer_timeout; 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); /* Write config to register CTRLA */ i2c_hw->CTRLA.reg |= (uint32_t)(config->sda_hold_time | config->transfer_speed | (config->scl_low_timeout << SERCOM_I2CS_CTRLA_LOWTOUTEN_Pos) | (config->scl_stretch_only_after_ack_bit << SERCOM_I2CS_CTRLA_SCLSM_Pos) | (config->slave_scl_low_extend_timeout << SERCOM_I2CS_CTRLA_SEXTTOEN_Pos) | (config->run_in_standby << SERCOM_I2CS_CTRLA_RUNSTDBY_Pos)); /* Set CTRLB configuration */ i2c_hw->CTRLB.reg = SERCOM_I2CS_CTRLB_SMEN | config->address_mode; i2c_hw->ADDR.reg = config->address << SERCOM_I2CS_ADDR_ADDR_Pos | config->address_mask << SERCOM_I2CS_ADDR_ADDRMASK_Pos | config->enable_general_call_address << SERCOM_I2CS_ADDR_GENCEN_Pos; return STATUS_OK; }
static void configure_ac(void) { static struct ac_module ac_instance; struct ac_config config_ac; ac_get_config_defaults(&config_ac); config_ac.ana_source_generator = GCLK_GENERATOR_1; config_ac.dig_source_generator = GCLK_GENERATOR_1; /* Initialize and enable the Analog Comparator with the user settings */ ac_init(&ac_instance, AC1, &config_ac); /* Create a new configuration structure for the Analog Comparator channel * settings and fill with the default module channel settings. */ struct ac_chan_config ac_chan_conf; ac_chan_get_config_defaults(&ac_chan_conf); /* Set the Analog Comparator channel configuration settings */ ac_chan_conf.sample_mode = AC_CHAN_MODE_CONTINUOUS; ac_chan_conf.filter = AC_CHAN_FILTER_NONE; ac_chan_conf.positive_input = AC_CHAN_POS_MUX_PIN3; ac_chan_conf.negative_input = AC_CHAN_NEG_MUX_SCALED_VCC; ac_chan_conf.vcc_scale_factor = AC_SCALING_FACTOR; ac_chan_conf.output_mode = AC_CHAN_OUTPUT_INTERNAL; /* Initialize and enable the Analog Comparator channel with the user * settings */ ac_chan_set_config(&ac_instance, 0, &ac_chan_conf); /* Set up a pin as an AC channel input */ struct system_pinmux_config ac0_pin_conf; system_pinmux_get_config_defaults(&ac0_pin_conf); ac0_pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; ac0_pin_conf.mux_position = MUX_PB03B_AC1_AIN3; system_pinmux_pin_set_config(PIN_PB03B_AC1_AIN3, &ac0_pin_conf); /* Setup event output from AC */ struct ac_events ac_event_conf; memset(&ac_event_conf, 0, sizeof(struct ac_events)); ac_event_conf.generate_event_on_state[0] = true; ac_enable_events(&ac_instance, &ac_event_conf); /* enable AC channel */ ac_chan_enable(&ac_instance, 0); ac_enable(&ac_instance); }
/** * \brief Pin MUX configuration helper * * \param[in] pinmux Pin MUX setting to apply. Special values: * \arg \c PINMUX_UNUSED to do nothing. * \arg \c PINMUX_DEFAULT to use default pin MUX for the SERCOM pad. * \param[in] sercom,padnum SERCOM pad specification, for \ref PINMUX_DEFAULT. */ static inline void _spi_master_vec_pinmux_helper(uint32_t pinmux, Sercom *const sercom, uint8_t padnum) { struct system_pinmux_config pin_conf; if (pinmux == PINMUX_DEFAULT) { pinmux = _sercom_get_default_pad(sercom, padnum); } if (pinmux == PINMUX_UNUSED) { return; } system_pinmux_get_config_defaults(&pin_conf); pin_conf.mux_position = pinmux & 0xFFFF; system_pinmux_pin_set_config(pinmux >> 16, &pin_conf); };
/** * \brief Writes an External Interrupt channel configuration to the hardware module. * * Writes out a given configuration of an External Interrupt channel * configuration to the hardware module. If the channel is already configured, * the new configuration will replace the existing one. * * \param[in] channel External Interrupt channel to configure * \param[in] config Configuration settings for the channel */ void extint_chan_set_config( const uint8_t channel, const struct extint_chan_conf *const config) { /* Sanity check arguments */ Assert(config); /* Sanity check clock requirements */ Assert(!(!system_gclk_gen_is_enabled(EXTINT_CLOCK_SOURCE) && _extint_is_gclk_required(config->filter_input_signal, config->detection_criteria))); struct system_pinmux_config pinmux_config; system_pinmux_get_config_defaults(&pinmux_config); pinmux_config.mux_position = config->gpio_pin_mux; pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->gpio_pin_pull; system_pinmux_pin_set_config(config->gpio_pin, &pinmux_config); /* Get a pointer to the module hardware instance */ Eic *const EIC_module = _extint_get_eic_from_channel(channel); uint32_t config_pos = (4 * (channel % 8)); uint32_t new_config; /* Determine the channel's new edge detection configuration */ new_config = (config->detection_criteria << EIC_CONFIG_SENSE0_Pos); /* Enable the hardware signal filter if requested in the config */ if (config->filter_input_signal) { new_config |= EIC_CONFIG_FILTEN0; } /* Clear the existing and set the new channel configuration */ EIC_module->CONFIG[channel / 8].reg = (EIC_module->CONFIG[channel / 8].reg & ~((EIC_CONFIG_SENSE0_Msk | EIC_CONFIG_FILTEN0) << config_pos)) | (new_config << config_pos); /* Set the channel's new wake up mode setting */ if (config->wake_if_sleeping) { EIC_module->WAKEUP.reg |= (1UL << channel); } else { EIC_module->WAKEUP.reg &= ~(1UL << channel); } }
/** * \brief Writes a Port pin configuration to the hardware module. * * Writes out a given configuration of a Port pin configuration to the hardware * module. * * \note If the pin direction is set as an output, the pull-up/pull-down input * configuration setting is ignored. * * \param[in] gpio_pin Index of the GPIO pin to configure. * \param[in] config Configuration settings for the pin. */ void port_pin_set_config( const uint8_t gpio_pin, const struct port_config *const config) { /* Sanity check arguments */ Assert(config); struct system_pinmux_config pinmux_config; system_pinmux_get_config_defaults(&pinmux_config); pinmux_config.mux_position = SYSTEM_PINMUX_GPIO; pinmux_config.direction = (enum system_pinmux_pin_dir)config->direction; pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->input_pull; pinmux_config.powersave = config->powersave; system_pinmux_pin_set_config(gpio_pin, &pinmux_config); }
/** * \brief Writes an External Interrupt NMI channel configuration to the hardware module. * * Writes out a given configuration of an External Interrupt NMI channel * configuration to the hardware module. If the channel is already configured, * the new configuration will replace the existing one. * * \param[in] nmi_channel External Interrupt NMI channel to configure * \param[in] config Configuration settings for the channel * * \returns Status code indicating the success or failure of the request. * \retval STATUS_OK Configuration succeeded * \retval STATUS_ERR_PIN_MUX_INVALID An invalid pinmux value was supplied * \retval STATUS_ERR_BAD_FORMAT An invalid detection mode was requested */ enum status_code extint_nmi_set_config( const uint8_t nmi_channel, const struct extint_nmi_conf *const config) { /* Sanity check arguments */ Assert(config); /* Sanity check clock requirements */ Assert(!(!system_gclk_gen_is_enabled(EXTINT_CLOCK_SOURCE) && _extint_is_gclk_required(config->filter_input_signal, config->detection_criteria))); struct system_pinmux_config pinmux_config; system_pinmux_get_config_defaults(&pinmux_config); pinmux_config.mux_position = config->gpio_pin_mux; pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pinmux_config.input_pull = SYSTEM_PINMUX_PIN_PULL_UP; pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->gpio_pin_pull; system_pinmux_pin_set_config(config->gpio_pin, &pinmux_config); /* Get a pointer to the module hardware instance */ Eic *const EIC_module = _extint_get_eic_from_channel(nmi_channel); uint32_t new_config; /* Determine the NMI's new edge detection configuration */ new_config = (config->detection_criteria << EIC_NMICTRL_NMISENSE_Pos); /* Enable the hardware signal filter if requested in the config */ if (config->filter_input_signal) { new_config |= EIC_NMICTRL_NMIFILTEN; } /* Disable EIC and general clock to configure NMI */ _extint_disable(); system_gclk_chan_disable(EIC_GCLK_ID); EIC_module->NMICTRL.reg = new_config; /* Enable the general clock and EIC after configure NMI */ system_gclk_chan_enable(EIC_GCLK_ID); _extint_enable(); return STATUS_OK; }
/** * \internal * \brief Test for AC initialization. * * This test initializes the AC module and checks whether the * initialization is successful or not. * * If this test fails no other tests will run. * * \param test Current test case. */ static void run_ac_init_test(const struct test_case *test) { enum status_code status = STATUS_ERR_IO; /* Structure for AC configuration */ struct ac_config config; struct ac_chan_config channel_config; ac_get_config_defaults(&config); /* Initialize the AC */ status = ac_init(&ac_inst, AC, &config); /* Check for successful initialization */ test_assert_true(test, status == STATUS_OK, "AC initialization failed"); status = STATUS_ERR_IO; ac_chan_get_config_defaults(&channel_config); channel_config.sample_mode = AC_CHAN_MODE_SINGLE_SHOT; channel_config.positive_input = AC_CHAN_POS_MUX_PIN0; channel_config.negative_input = AC_CHAN_NEG_MUX_SCALED_VCC; channel_config.vcc_scale_factor = AC_SCALER_0_50_VOLT; struct system_pinmux_config ac0_pin_conf; system_pinmux_get_config_defaults(&ac0_pin_conf); ac0_pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; ac0_pin_conf.mux_position = MUX_PA04B_AC_AIN0; system_pinmux_pin_set_config(PIN_PA04B_AC_AIN0, &ac0_pin_conf); /* Set the channel configuration */ status = ac_chan_set_config(&ac_inst, AC_CHAN_CHANNEL_0, &channel_config); /* Check for successful configuration */ test_assert_true(test, status == STATUS_OK, "AC channel configuration failed"); /* Enable the AC channel & AC module */ ac_chan_enable(&ac_inst, AC_CHAN_CHANNEL_0); ac_enable(&ac_inst); if (status == STATUS_OK) { ac_init_success = true; } }
/*---------------------------------------------------------------------------*/ static void configure_miso(bool as_output) { if (as_output) { /* Configure MISO as output */ struct port_config gp_pin_conf; port_get_config_defaults(&gp_pin_conf); gp_pin_conf.direction = PORT_PIN_DIR_OUTPUT; port_pin_set_config(DISPLAY_CMD_DATA_PIN, &gp_pin_conf); } else { /* Configure MISO as SPI pin */ struct system_pinmux_config mux_pin_conf; system_pinmux_get_config_defaults(&mux_pin_conf); mux_pin_conf.mux_position = ESD_SPI_SERCOM_PINMUX_PAD0 & 0xFFFF; mux_pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; mux_pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_UP; system_pinmux_pin_set_config(ESD_SPI_SERCOM_PINMUX_PAD0 >> 16, &mux_pin_conf); } }
/** * \brief Writes a Port group configuration group to the hardware module. * * Writes out a given configuration of a Port group configuration to the * hardware module. * * \note If the pin direction is set as an output, the pull-up/pull-down input * configuration setting is ignored. * * \param[out] port Base of the PORT module to write to. * \param[in] mask Mask of the port pin(s) to configure. * \param[in] config Configuration settings for the pin group. */ void port_group_set_config( PortGroup *const port, const uint32_t mask, const struct port_config *const config) { /* Sanity check arguments */ Assert(port); Assert(config); struct system_pinmux_config pinmux_config; system_pinmux_get_config_defaults(&pinmux_config); pinmux_config.mux_position = SYSTEM_PINMUX_GPIO; pinmux_config.direction = (enum system_pinmux_pin_dir)config->direction; pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->input_pull; pinmux_config.powersave = config->powersave; system_pinmux_group_set_config(port, mask, &pinmux_config); }
void system_board_init(void) { struct port_config pin_conf; port_get_config_defaults(&pin_conf); /* Configure LEDs as outputs, turn them off */ pin_conf.direction = PORT_PIN_DIR_OUTPUT; port_pin_set_config(LED_0_PIN, &pin_conf); port_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE); /* Set buttons as inputs */ pin_conf.direction = PORT_PIN_DIR_INPUT; pin_conf.input_pull = PORT_PIN_PULL_UP; port_pin_set_config(BUTTON_0_PIN, &pin_conf); #ifdef CONF_BOARD_AT86RFX port_get_config_defaults(&pin_conf); pin_conf.direction = PORT_PIN_DIR_OUTPUT; port_pin_set_config(AT86RFX_SPI_SCK, &pin_conf); port_pin_set_config(AT86RFX_SPI_MOSI, &pin_conf); port_pin_set_config(AT86RFX_SPI_CS, &pin_conf); port_pin_set_config(AT86RFX_RST_PIN, &pin_conf); port_pin_set_config(AT86RFX_SLP_PIN, &pin_conf); port_pin_set_output_level(AT86RFX_SPI_SCK, true); port_pin_set_output_level(AT86RFX_SPI_MOSI, true); port_pin_set_output_level(AT86RFX_SPI_CS, true); port_pin_set_output_level(AT86RFX_RST_PIN, true); port_pin_set_output_level(AT86RFX_SLP_PIN, true); pin_conf.direction = PORT_PIN_DIR_INPUT; port_pin_set_config(AT86RFX_SPI_MISO, &pin_conf); PM->APBCMASK.reg |= (1<<PM_APBCMASK_RFCTRL_Pos); REG_RFCTRL_FECFG = RFCTRL_CFG_ANT_DIV; struct system_pinmux_config config_pinmux; system_pinmux_get_config_defaults(&config_pinmux); config_pinmux.mux_position = MUX_PA09F_RFCTRL_FECTRL1 ; config_pinmux.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; system_pinmux_pin_set_config(PIN_RFCTRL1, &config_pinmux); system_pinmux_pin_set_config(PIN_RFCTRL2, &config_pinmux); #endif }
//! [setup_7] void configure_ac_channel(void) { //! [setup_7] /* Create a new configuration structure for the Analog Comparator channel * settings and fill with the default module channel settings. */ //! [setup_8] struct ac_chan_config config_ac_chan; //! [setup_8] //! [setup_9] ac_chan_get_config_defaults(&config_ac_chan); //! [setup_9] /* Set the Analog Comparator channel configuration settings */ //! [setup_10] config_ac_chan.sample_mode = AC_CHAN_MODE_SINGLE_SHOT; config_ac_chan.positive_input = AC_CHAN_POS_MUX_PIN0; config_ac_chan.negative_input = AC_CHAN_NEG_MUX_SCALED_VCC; config_ac_chan.vcc_scale_factor = 32; config_ac_chan.interrupt_selection = AC_CHAN_INTERRUPT_SELECTION_END_OF_COMPARE; //! [setup_10] /* Set up a pin as an AC channel input */ //! [setup_11] struct system_pinmux_config ac0_pin_conf; system_pinmux_get_config_defaults(&ac0_pin_conf); ac0_pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; ac0_pin_conf.mux_position = MUX_PA04B_AC_AIN0; system_pinmux_pin_set_config(PIN_PA04B_AC_AIN0, &ac0_pin_conf); //! [setup_11] /* Initialize and enable the Analog Comparator channel with the user * settings */ //! [setup_12] ac_chan_set_config(&ac_instance, AC_COMPARATOR_CHANNEL, &config_ac_chan); //! [setup_12] //! [setup_13] ac_chan_enable(&ac_instance, AC_COMPARATOR_CHANNEL); //! [setup_13] }
/** Initializes the XOSC32K crystal failure detector, and starts it. * * \param[in] ok_callback Callback function to run upon XOSC32K operational * \param[in] fail_callback Callback function to run upon XOSC32K failure */ static void init_xosc32k_fail_detector( const tc_callback_t ok_callback, const tc_callback_t fail_callback) { /* TC pairs share the same clock, ensure reference and crystal timers use * different clocks */ Assert(Abs(_tc_get_inst_index(CONF_TC_OSC32K) - _tc_get_inst_index(CONF_TC_XOSC32K)) >= 2); /* The crystal detection cycle count must be less than the reference cycle * count, so that the reference timer is periodically reset before expiry */ Assert(CRYSTAL_RESET_CYCLES < CRYSTAL_FAIL_CYCLES); /* Must use different clock generators for the crystal and reference, must * not be CPU generator 0 */ Assert(GCLK_GENERATOR_XOSC32K != GCLK_GENERATOR_OSC32K); Assert(GCLK_GENERATOR_XOSC32K != GCLK_GENERATOR_0); Assert(GCLK_GENERATOR_OSC32K != GCLK_GENERATOR_0); /* Configure and enable the XOSC32K GCLK generator */ struct system_gclk_gen_config xosc32k_gen_conf; system_gclk_gen_get_config_defaults(&xosc32k_gen_conf); xosc32k_gen_conf.source_clock = SYSTEM_CLOCK_SOURCE_XOSC32K; system_gclk_gen_set_config(GCLK_GENERATOR_XOSC32K, &xosc32k_gen_conf); system_gclk_gen_enable(GCLK_GENERATOR_XOSC32K); /* Configure and enable the reference clock GCLK generator */ struct system_gclk_gen_config ref_gen_conf; system_gclk_gen_get_config_defaults(&ref_gen_conf); ref_gen_conf.source_clock = SYSTEM_CLOCK_SOURCE_OSC32K; system_gclk_gen_set_config(GCLK_GENERATOR_OSC32K, &ref_gen_conf); system_gclk_gen_enable(GCLK_GENERATOR_OSC32K); /* Set up crystal counter - when target count elapses, trigger event */ struct tc_config tc_xosc32k_conf; tc_get_config_defaults(&tc_xosc32k_conf); tc_xosc32k_conf.clock_source = GCLK_GENERATOR_XOSC32K; tc_xosc32k_conf.counter_16_bit.compare_capture_channel[0] = CRYSTAL_RESET_CYCLES; tc_xosc32k_conf.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ; tc_init(&tc_xosc32k, CONF_TC_XOSC32K, &tc_xosc32k_conf); /* Set up reference counter - when event received, restart */ struct tc_config tc_osc32k_conf; tc_get_config_defaults(&tc_osc32k_conf); tc_osc32k_conf.clock_source = GCLK_GENERATOR_OSC32K; tc_osc32k_conf.counter_16_bit.compare_capture_channel[0] = CRYSTAL_FAIL_CYCLES; tc_osc32k_conf.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ; tc_init(&tc_osc32k, CONF_TC_OSC32K, &tc_osc32k_conf); /* Configure event channel and link it to the xosc32k counter */ struct events_config config; struct events_resource event; events_get_config_defaults(&config); config.edge_detect = EVENTS_EDGE_DETECT_NONE; config.generator = CONF_EVENT_GENERATOR_ID; config.path = EVENTS_PATH_ASYNCHRONOUS; events_allocate(&event, &config); /* Configure event user and link it to the osc32k counter */ events_attach_user(&event, CONF_EVENT_USED_ID); /* Enable event generation for crystal counter */ struct tc_events tc_xosc32k_events = { .generate_event_on_overflow = true }; tc_enable_events(&tc_xosc32k, &tc_xosc32k_events); /* Enable event reception for reference counter */ struct tc_events tc_osc32k_events = { .on_event_perform_action = true }; tc_osc32k_events.event_action = TC_EVENT_ACTION_RETRIGGER; tc_enable_events(&tc_osc32k, &tc_osc32k_events); /* Enable overflow callback for the crystal counter - if crystal count * has been reached, crystal is operational */ tc_register_callback(&tc_xosc32k, ok_callback, TC_CALLBACK_CC_CHANNEL0); tc_enable_callback(&tc_xosc32k, TC_CALLBACK_CC_CHANNEL0); /* Enable compare callback for the reference counter - if reference count * has been reached, crystal has failed */ tc_register_callback(&tc_osc32k, fail_callback, TC_CALLBACK_CC_CHANNEL0); tc_enable_callback(&tc_osc32k, TC_CALLBACK_CC_CHANNEL0); /* Start both crystal and reference counters */ tc_enable(&tc_xosc32k); tc_enable(&tc_osc32k); } /** Main application entry point. */ int main(void) { system_init(); system_flash_set_waitstates(2); init_osc32k(); init_xosc32k(); init_xosc32k_fail_detector( xosc32k_ok_callback, xosc32k_fail_callback); #if ENABLE_CPU_CLOCK_OUT == true /* Configure a GPIO pin as the CPU clock output */ struct system_pinmux_config clk_out_pin; system_pinmux_get_config_defaults(&clk_out_pin); clk_out_pin.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; clk_out_pin.mux_position = CONF_CLOCK_PIN_MUX; system_pinmux_pin_set_config(CONF_CLOCK_PIN_OUT, &clk_out_pin); #endif for (;;) { static bool old_run_osc = true; bool new_run_osc = (port_pin_get_input_level(BUTTON_0_PIN) == BUTTON_0_INACTIVE); /* Check if the XOSC32K needs to be started or stopped when the board * button is pressed or released */ if (new_run_osc != old_run_osc) { if (new_run_osc) { system_clock_source_enable(SYSTEM_CLOCK_SOURCE_XOSC32K); while(!system_clock_source_is_ready( SYSTEM_CLOCK_SOURCE_XOSC32K)); } else { system_clock_source_disable(SYSTEM_CLOCK_SOURCE_XOSC32K); } old_run_osc = new_run_osc; } } }
/** * \brief Initializes a hardware TC module instance. * * Enables the clock and initializes the TC module, based on the given * configuration values. * * \param[in,out] module_inst Pointer to the software module instance struct * \param[in] hw Pointer to the TC hardware module * \param[in] config Pointer to the TC configuration options struct * * \return Status of the initialization procedure. * * \retval STATUS_OK The module was initialized successfully * \retval STATUS_BUSY Hardware module was busy when the * initialization procedure was attempted * \retval STATUS_INVALID_ARG An invalid configuration option or argument * was supplied * \retval STATUS_ERR_DENIED Hardware module was already enabled, or the * hardware module is configured in 32-bit * slave mode */ enum status_code tc_init( struct tc_module *const module_inst, Tc *const hw, const struct tc_config *const config) { /* Sanity check arguments */ Assert(hw); Assert(module_inst); Assert(config); /* Temporary variable to hold all updates to the CTRLA * register before they are written to it */ uint16_t ctrla_tmp = 0; /* Temporary variable to hold all updates to the CTRLBSET * register before they are written to it */ uint8_t ctrlbset_tmp = 0; /* Temporary variable to hold all updates to the CTRLC * register before they are written to it */ uint8_t ctrlc_tmp = 0; /* Temporary variable to hold TC instance number */ uint8_t instance = _tc_get_inst_index(hw); /* Array of GLCK ID for different TC instances */ uint8_t inst_gclk_id[] = TC_INST_GCLK_ID; /* Array of PM APBC mask bit position for different TC instances */ uint16_t inst_pm_apbmask[] = TC_INST_PM_APBCMASK; struct system_pinmux_config pin_config; struct system_gclk_chan_config gclk_chan_config; #if TC_ASYNC == true /* Initialize parameters */ for (uint8_t i = 0; i < TC_CALLBACK_N; i++) { module_inst->callback[i] = NULL; } module_inst->register_callback_mask = 0x00; module_inst->enable_callback_mask = 0x00; /* Register this instance for callbacks*/ _tc_instances[instance] = module_inst; #endif /* Associate the given device instance with the hardware module */ module_inst->hw = hw; #if SAMD10 || SAMD11 /* Check if even numbered TC modules are being configured in 32-bit * counter size. Only odd numbered counters are allowed to be * configured in 32-bit counter size. */ if ((config->counter_size == TC_COUNTER_SIZE_32BIT) && !((instance + TC_INSTANCE_OFFSET) & 0x01)) { Assert(false); return STATUS_ERR_INVALID_ARG; } #else /* Check if odd numbered TC modules are being configured in 32-bit * counter size. Only even numbered counters are allowed to be * configured in 32-bit counter size. */ if ((config->counter_size == TC_COUNTER_SIZE_32BIT) && ((instance + TC_INSTANCE_OFFSET) & 0x01)) { Assert(false); return STATUS_ERR_INVALID_ARG; } #endif /* Make the counter size variable in the module_inst struct reflect * the counter size in the module */ module_inst->counter_size = config->counter_size; if (hw->COUNT8.CTRLA.reg & TC_CTRLA_SWRST) { /* We are in the middle of a reset. Abort. */ return STATUS_BUSY; } if (hw->COUNT8.STATUS.reg & TC_STATUS_SLAVE) { /* Module is used as a slave */ return STATUS_ERR_DENIED; } if (hw->COUNT8.CTRLA.reg & TC_CTRLA_ENABLE) { /* Module must be disabled before initialization. Abort. */ return STATUS_ERR_DENIED; } /* Set up the TC PWM out pin for channel 0 */ if (config->pwm_channel[0].enabled) { system_pinmux_get_config_defaults(&pin_config); pin_config.mux_position = config->pwm_channel[0].pin_mux; pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; system_pinmux_pin_set_config( config->pwm_channel[0].pin_out, &pin_config); } /* Set up the TC PWM out pin for channel 1 */ if (config->pwm_channel[1].enabled) { system_pinmux_get_config_defaults(&pin_config); pin_config.mux_position = config->pwm_channel[1].pin_mux; pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; system_pinmux_pin_set_config( config->pwm_channel[1].pin_out, &pin_config); } /* Enable the user interface clock in the PM */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, inst_pm_apbmask[instance]); /* Enable the slave counter if counter_size is 32-bit */ if ((config->counter_size == TC_COUNTER_SIZE_32BIT)) { /* Enable the user interface clock in the PM */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, inst_pm_apbmask[instance + 1]); } /* Setup clock for module */ system_gclk_chan_get_config_defaults(&gclk_chan_config); gclk_chan_config.source_generator = config->clock_source; system_gclk_chan_set_config(inst_gclk_id[instance], &gclk_chan_config); system_gclk_chan_enable(inst_gclk_id[instance]); /* Set ctrla register */ ctrla_tmp = (uint32_t)config->counter_size | (uint32_t)config->wave_generation | (uint32_t)config->reload_action | (uint32_t)config->clock_prescaler; if (config->run_in_standby) { ctrla_tmp |= TC_CTRLA_RUNSTDBY; } /* Write configuration to register */ while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT8.CTRLA.reg = ctrla_tmp; /* Set ctrlb register */ if (config->oneshot) { ctrlbset_tmp = TC_CTRLBSET_ONESHOT; } if (config->count_direction) { ctrlbset_tmp |= TC_CTRLBSET_DIR; } /* Clear old ctrlb configuration */ while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT8.CTRLBCLR.reg = 0xFF; /* Check if we actually need to go into a wait state. */ if (ctrlbset_tmp) { while (tc_is_syncing(module_inst)) { /* Wait for sync */ } /* Write configuration to register */ hw->COUNT8.CTRLBSET.reg = ctrlbset_tmp; } /* Set ctrlc register*/ ctrlc_tmp = config->waveform_invert_output; for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) { if (config->enable_capture_on_channel[i] == true) { ctrlc_tmp |= (TC_CTRLC_CPTEN(1) << i); } } /* Write configuration to register */ while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT8.CTRLC.reg = ctrlc_tmp; /* Write configuration to register */ while (tc_is_syncing(module_inst)) { /* Wait for sync */ } /* Switch for TC counter size */ switch (module_inst->counter_size) { case TC_COUNTER_SIZE_8BIT: while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT8.COUNT.reg = config->counter_8_bit.value; while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT8.PER.reg = config->counter_8_bit.period; while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT8.CC[0].reg = config->counter_8_bit.compare_capture_channel[0]; while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT8.CC[1].reg = config->counter_8_bit.compare_capture_channel[1]; return STATUS_OK; case TC_COUNTER_SIZE_16BIT: while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT16.COUNT.reg = config->counter_16_bit.value; while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT16.CC[0].reg = config->counter_16_bit.compare_capture_channel[0]; while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT16.CC[1].reg = config->counter_16_bit.compare_capture_channel[1]; return STATUS_OK; case TC_COUNTER_SIZE_32BIT: while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT32.COUNT.reg = config->counter_32_bit.value; while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT32.CC[0].reg = config->counter_32_bit.compare_capture_channel[0]; while (tc_is_syncing(module_inst)) { /* Wait for sync */ } hw->COUNT32.CC[1].reg = config->counter_32_bit.compare_capture_channel[1]; return STATUS_OK; } Assert(false); return STATUS_ERR_INVALID_ARG; }
/** * \internal Configure MUX settings for the analog pins * * This function will set the given ADC input pins * to the analog function in the pinmux, giving * the ADC access to the analog signal * * \param [in] pin AINxx pin to configure */ static inline void _adc_configure_ain_pin(uint32_t pin) { #define PIN_INVALID_ADC_AIN 0xFFFFUL /* Pinmapping table for AINxx -> GPIO pin number */ const uint32_t pinmapping[] = { #if (SAMD20E | SAMD21E) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, #elif (SAMD20G | SAMD21G) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, #elif (SAMD20J | SAMD21J) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9, PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13, PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15, PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, #elif SAMR21E PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, #elif SAMR21G PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, #elif (SAMD10C | SAMD11C) PIN_PA02B_ADC_AIN0, PIN_INVALID_ADC_AIN, PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, #elif (SAMD10DS | SAMD11DS) PIN_PA02B_ADC_AIN0, PIN_INVALID_ADC_AIN, PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3, PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5, PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, #elif (SAMD10DM | SAMD11DM) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3, PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5, PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7, PIN_PA10B_ADC_AIN8, PIN_PA11B_ADC_AIN9, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, #else # error ADC pin mappings are not defined for this device. #endif }; uint32_t pin_map_result = PIN_INVALID_ADC_AIN; if (pin <= ADC_EXTCHANNEL_MSB) { pin_map_result = pinmapping[pin >> ADC_INPUTCTRL_MUXPOS_Pos]; Assert(pin_map_result != PIN_INVALID_ADC_AIN); struct system_pinmux_config config; system_pinmux_get_config_defaults(&config); /* Analog functions are all on MUX setting B */ config.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; config.mux_position = 1; system_pinmux_pin_set_config(pin_map_result, &config); }
/** * \brief Configure specified I2S serializer * * Enables the clock and initialize the serializer, based on the given * configurations. * * \param[in,out] module_inst Pointer to the software module instance struct * \param[in] serializer I2S serializer to initialize and configure * \param[in] config Pointer to the I2S serializer configuration * options struct * * \return Status of the configuration procedure. * * \retval STATUS_OK The module was initialized successfully * \retval STATUS_BUSY Hardware module was busy when the * configuration procedure was attempted * \retval STATUS_ERR_DENIED Hardware module was already enabled */ enum status_code i2s_serializer_set_config( struct i2s_module *const module_inst, const enum i2s_serializer serializer, const struct i2s_serializer_config *config) { Assert(module_inst); Assert(module_inst->hw); Assert(serializer < I2S_SERIALIZER_N); Assert(config); /* Status check */ uint32_t ctrla, syncbusy; syncbusy = module_inst->hw->SYNCBUSY.reg; ctrla = module_inst->hw->CTRLA.reg; /* Busy ? */ if (syncbusy & ((I2S_SYNCBUSY_SEREN0 | I2S_SYNCBUSY_DATA0) << serializer)) { return STATUS_BUSY; } /* Already enabled ? */ if (ctrla & (I2S_CTRLA_CKEN0 << serializer)) { return STATUS_ERR_DENIED; } /* Initialize Serializer */ uint32_t serctrl = (config->loop_back ? I2S_SERCTRL_RXLOOP : 0) | (config->dma_usage ? I2S_SERCTRL_DMA : 0) | (config->mono_mode ? I2S_SERCTRL_MONO : 0) | (config->disable_data_slot[7] ? I2S_SERCTRL_SLOTDIS7 : 0) | (config->disable_data_slot[6] ? I2S_SERCTRL_SLOTDIS6 : 0) | (config->disable_data_slot[5] ? I2S_SERCTRL_SLOTDIS5 : 0) | (config->disable_data_slot[4] ? I2S_SERCTRL_SLOTDIS4 : 0) | (config->disable_data_slot[3] ? I2S_SERCTRL_SLOTDIS3 : 0) | (config->disable_data_slot[2] ? I2S_SERCTRL_SLOTDIS2 : 0) | (config->disable_data_slot[1] ? I2S_SERCTRL_SLOTDIS1 : 0) | (config->disable_data_slot[0] ? I2S_SERCTRL_SLOTDIS0 : 0) | (config->transfer_lsb_first ? I2S_SERCTRL_BITREV : 0) | (config->data_adjust_left_in_word ? I2S_SERCTRL_WORDADJ : 0) | (config->data_adjust_left_in_slot ? I2S_SERCTRL_SLOTADJ : 0) | (config->data_padding ? I2S_SERCTRL_TXSAME : 0); if (config->clock_unit < I2S_CLOCK_UNIT_N) { serctrl |= (config->clock_unit ? I2S_SERCTRL_CLKSEL : 0); } else { return STATUS_ERR_INVALID_ARG; } serctrl |= I2S_SERCTRL_SERMODE(config->mode) | I2S_SERCTRL_TXDEFAULT(config->line_default_state) | I2S_SERCTRL_DATASIZE(config->data_size) | I2S_SERCTRL_EXTEND(config->bit_padding); /* Write Serializer configuration */ module_inst->hw->SERCTRL[serializer].reg = serctrl; /* Initialize pins */ struct system_pinmux_config pin_config; system_pinmux_get_config_defaults(&pin_config); if (config->data_pin.enable) { pin_config.mux_position = config->data_pin.mux; system_pinmux_pin_set_config(config->data_pin.gpio, &pin_config); } /* Save configure */ module_inst->serializer[serializer].mode = config->mode; module_inst->serializer[serializer].data_size = config->data_size; return STATUS_OK; }
/** * \brief Initializes a hardware TCC module instance. * * Enables the clock and initializes the given TCC module, based on the given * configuration values. * * \param[in,out] module_inst Pointer to the software module instance struct * \param[in] hw Pointer to the TCC hardware module * \param[in] config Pointer to the TCC configuration options struct * * \return Status of the initialization procedure. * * \retval STATUS_OK The module was initialized successfully * \retval STATUS_BUSY Hardware module was busy when the * initialization procedure was attempted * \retval STATUS_INVALID_ARG An invalid configuration option or argument * was supplied * \retval STATUS_ERR_DENIED Hardware module was already enabled */ enum status_code tcc_init( struct tcc_module *const module_inst, Tcc *const hw, const struct tcc_config *const config) { int i; /* Sanity check arguments */ Assert(hw); Assert(module_inst); Assert(config); /* TCC instance index */ uint8_t module_index = _tcc_get_inst_index(hw); /* Enable the user interface clock for TCC */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, _tcc_apbcmasks[module_index]); /* Check if it's enabled. */ if (hw->CTRLA.reg & TCC_CTRLA_ENABLE) { return STATUS_ERR_DENIED; } /* Check if it's resetting */ if (hw->CTRLA.reg & TCC_CTRLA_SWRST) { return STATUS_ERR_DENIED; } enum status_code status; /* Check COUNT, PER, CCx */ uint32_t count_max = _tcc_maxs[module_index]; /* Check all counter values */ if ((config->counter.count > count_max) || (config->counter.period > count_max) ) { return STATUS_ERR_INVALID_ARG; } /* Check all channel values */ for (i = 0; i < TCC_NUM_CHANNELS; i ++) { if ((config->compare.match[i] > count_max) ) { return STATUS_ERR_INVALID_ARG; } } /* Check all outputs */ for (i = 0; i < TCC_NUM_WAVE_OUTPUTS; i ++) { if (!config->pins.enable_wave_out_pin[i]) { continue; } /* Output line is not supported */ if (i >= _tcc_ow_nums[module_index]) { return STATUS_ERR_INVALID_ARG; } } /* CTRLA settings */ uint32_t ctrla = 0; status = _tcc_build_ctrla(module_index, config, &ctrla); if (STATUS_OK != status) { return status; } /* CTRLB settings */ uint8_t ctrlb; _tcc_build_ctrlb(module_index, config, &ctrlb); /* FAULTs settings */ uint32_t faults[TCC_NUM_FAULTS]; status = _tcc_build_faults(module_index, config, faults); if (STATUS_OK != status) { return status; } /* DRVCTRL */ uint32_t drvctrl = 0; status = _tcc_build_drvctrl(module_index, config, &drvctrl); if (STATUS_OK != status) { return status; } /* WAVE */ uint32_t waves[1]; status = _tcc_build_waves(module_index, config, waves); if (STATUS_OK != status) { return status; } /* Initialize module */ #if TCC_ASYNC /* Initialize parameters */ for (i = 0; i < TCC_CALLBACK_N; i ++) { module_inst->callback[i] = NULL; } module_inst->register_callback_mask = 0; module_inst->enable_callback_mask = 0; _tcc_instances[module_index] = module_inst; #endif module_inst->hw = hw; module_inst->double_buffering_enabled = config->double_buffering_enabled; /* Setup clock for module */ struct system_gclk_chan_config gclk_chan_config; system_gclk_chan_get_config_defaults(&gclk_chan_config); gclk_chan_config.source_generator = config->counter.clock_source; system_gclk_chan_set_config(_tcc_gclk_ids[module_index], &gclk_chan_config); system_gclk_chan_enable(_tcc_gclk_ids[module_index]); /* Initialize pins */ struct system_pinmux_config pin_config; for (i = 0; i < _tcc_ow_nums[module_index]; i ++) { if (!config->pins.enable_wave_out_pin[i]) { continue; } system_pinmux_get_config_defaults(&pin_config); pin_config.mux_position = config->pins.wave_out_pin_mux[i]; pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; system_pinmux_pin_set_config( config->pins.wave_out_pin[i], &pin_config); } /* Write to registers */ hw->CTRLA.reg = ctrla; while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { /* Wait for sync */ } hw->CTRLBCLR.reg = 0xFF; while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { /* Wait for sync */ } hw->CTRLBSET.reg = ctrlb; hw->FCTRLA.reg = faults[0]; hw->FCTRLB.reg = faults[1]; hw->DRVCTRL.reg = drvctrl; #if (!SAML21) && (!SAMC20) && (!SAMC21) while (hw->SYNCBUSY.reg & (TCC_SYNCBUSY_WAVE | TCC_SYNCBUSY_WAVEB)) { /* Wait for sync */ } #endif hw->WAVE.reg = waves[0]; while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_COUNT) { /* Wait for sync */ } hw->COUNT.reg = config->counter.count; #if (!SAML21) && (!SAMC20) && (!SAMC21) while (hw->SYNCBUSY.reg & (TCC_SYNCBUSY_PER | TCC_SYNCBUSY_PERB)) { /* Wait for sync */ } #endif hw->PER.reg = (config->counter.period); for (i = 0; i < _tcc_cc_nums[module_index]; i ++) { #if (!SAML21) && (!SAMC20) && (!SAMC21) while (hw->SYNCBUSY.reg & ( (TCC_SYNCBUSY_CC0 | TCC_SYNCBUSY_CCB0) << i)) { /* Wait for sync */ } #endif hw->CC[i].reg = (config->compare.match[i]); } 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); } }
/** * \internal Configure MUX settings for the analog pins. * * This function will set the given ADC input pins * to the analog function in the pin mux, giving * the ADC access to the analog signal. * * \param [in] index Index of the ADC module instance. * \param [in] pin AINxx pin to configure */ static inline void _adc_configure_ain_pin(uint8_t index, uint32_t pin) { #define PIN_INVALID_ADC_AIN 0xFFFFUL /* Pinmapping table for AINxx -> GPIO pin number */ #if (SAML21) || (SAML22) const uint32_t pinmapping[] = { # if (SAML21E) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, # elif (SAML21G) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, # elif (SAML21J) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9, PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13, PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15, PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17, PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, #elif (SAML22G) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, #elif (SAML22J) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9, PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13, PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, #elif (SAML22N) PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1, PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3, PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5, PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7, PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9, PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11, PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13, PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15, PIN_PC00B_ADC_AIN16, PIN_PC01B_ADC_AIN17, PIN_PC02B_ADC_AIN18, PIN_PC03B_ADC_AIN19, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, # else # error ADC pin mappings are not defined for this device. # endif }; #elif (SAMC20) const uint32_t pinmapping[] = { # if (SAMC20E) PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, # elif (SAMC20G) PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, PIN_PB08B_ADC0_AIN2, PIN_PB09B_ADC0_AIN3, PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, # elif (SAMC20J) PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, PIN_PB08B_ADC0_AIN2, PIN_PB09B_ADC0_AIN3, PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, # else # error ADC pin mappings are not defined for this device. # endif }; #elif (SAMC21) const uint32_t *pinmapping = NULL;; const uint32_t pinmapping0[] = { # if (SAMC21E) PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, # elif (SAMC21G) PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, PIN_PB08B_ADC0_AIN2, PIN_PB09B_ADC0_AIN3, PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, # elif (SAMC21J) PIN_PA02B_ADC0_AIN0, PIN_PA03B_ADC0_AIN1, PIN_PB08B_ADC0_AIN2, PIN_PB09B_ADC0_AIN3, PIN_PA04B_ADC0_AIN4, PIN_PA05B_ADC0_AIN5, PIN_PA06B_ADC0_AIN6, PIN_PA07B_ADC0_AIN7, PIN_PA08B_ADC0_AIN8, PIN_PA09B_ADC0_AIN9, PIN_PA10B_ADC0_AIN10, PIN_PA11B_ADC0_AIN11, # else # error ADC pin mappings are not defined for this device. # endif }; const uint32_t pinmapping1[] = { # if (SAMC21E) PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA08B_ADC1_AIN10, PIN_PA09B_ADC1_AIN11, # elif (SAMC21G) PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PB02B_ADC1_AIN2, PIN_PB03B_ADC1_AIN3, PIN_PB08B_ADC1_AIN4, PIN_PB09B_ADC1_AIN5, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN, PIN_PA08B_ADC1_AIN10, PIN_PA09B_ADC1_AIN11, # elif (SAMC21J) PIN_PB00B_ADC1_AIN0, PIN_PB01B_ADC1_AIN1, PIN_PB02B_ADC1_AIN2, PIN_PB03B_ADC1_AIN3, PIN_PB08B_ADC1_AIN4, PIN_PB09B_ADC1_AIN5, PIN_PB04B_ADC1_AIN6, PIN_PB05B_ADC1_AIN7, PIN_PB06B_ADC1_AIN8, PIN_PB07B_ADC1_AIN9, PIN_PA08B_ADC1_AIN10, PIN_PA09B_ADC1_AIN11, # else # error ADC pin mappings are not defined for this device. # endif }; switch(index) { case 0: pinmapping = pinmapping0; break; case 1: pinmapping = pinmapping1; break; default: break; } Assert(pinmapping); #endif uint32_t pin_map_result = PIN_INVALID_ADC_AIN; if (pin <= _adc_extchannel_msb[index]) { pin_map_result = pinmapping[pin >> ADC_INPUTCTRL_MUXPOS_Pos]; Assert(pin_map_result != PIN_INVALID_ADC_AIN); struct system_pinmux_config config; system_pinmux_get_config_defaults(&config); /* Analog functions are all on MUX setting B */ config.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; config.mux_position = 1; system_pinmux_pin_set_config(pin_map_result, &config); }
/** * \brief Writes an External Interrupt NMI channel configuration to the hardware module. * * Writes out a given configuration of an External Interrupt NMI channel * configuration to the hardware module. If the channel is already configured, * the new configuration will replace the existing one. * * \param[in] nmi_channel External Interrupt NMI channel to configure * \param[in] config Configuration settings for the channel * * \returns Status code indicating the success or failure of the request. * \retval STATUS_OK Configuration succeeded * \retval STATUS_ERR_PIN_MUX_INVALID An invalid pin mux value was supplied * \retval STATUS_ERR_BAD_FORMAT An invalid detection mode was requested */ enum status_code extint_nmi_set_config( const uint8_t nmi_channel, const struct extint_nmi_conf *const config) { /* Sanity check arguments */ Assert(config); /* Sanity check clock requirements */ Assert(!(!system_gclk_gen_is_enabled(EXTINT_CLOCK_SOURCE) && _extint_is_gclk_required(config->filter_input_signal, config->detection_criteria))); struct system_pinmux_config pinmux_config; system_pinmux_get_config_defaults(&pinmux_config); pinmux_config.mux_position = config->gpio_pin_mux; pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pinmux_config.input_pull = SYSTEM_PINMUX_PIN_PULL_UP; pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->gpio_pin_pull; system_pinmux_pin_set_config(config->gpio_pin, &pinmux_config); /* Get a pointer to the module hardware instance */ Eic *const EIC_module = _extint_get_eic_from_channel(nmi_channel); uint32_t new_config; /* Determine the NMI's new edge detection configuration */ new_config = (config->detection_criteria << EIC_NMICTRL_NMISENSE_Pos); /* Enable the hardware signal filter if requested in the config */ if (config->filter_input_signal) { new_config |= EIC_NMICTRL_NMIFILTEN; } #if (SAML21XXXB) || (SAML22) || (SAMC21) || (SAMR30) /* Enable asynchronous edge detection if requested in the config */ if (config->enable_async_edge_detection) { new_config |= EIC_NMICTRL_NMIASYNCH; } #endif /* Disable EIC and general clock to configure NMI */ _extint_disable(); #if(EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) system_gclk_chan_disable(EIC_GCLK_ID); #else Eic *const eics[EIC_INST_NUM] = EIC_INSTS; for (uint32_t i = 0; i < EIC_INST_NUM; i++){ eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_GCLK; system_gclk_chan_disable(EIC_GCLK_ID); } #endif EIC_module->NMICTRL.reg = new_config; /* Enable the EIC clock and EIC after configure NMI */ #if(EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) system_gclk_chan_enable(EIC_GCLK_ID); #else for (uint32_t i = 0; i < EIC_INST_NUM; i++){ eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_ULP32K; } #endif _extint_enable(); 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); } }