示例#1
0
//! [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]
}
示例#2
0
文件: sdadc.c 项目: Gussy/sam0
/**
* \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);
}
示例#3
0
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]
}
示例#4
0
文件: spi.c 项目: AndreyMostovov/asf
/**
 * \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);
		}
	}
示例#5
0
/**
 * \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;
}
示例#6
0
文件: dac.c 项目: avrxml/sam0
/**
 * \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;
}
示例#7
0
/**
 * \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();
}
示例#8
0
文件: main.c 项目: rmnsfx/DVA141
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);	
	
}
示例#9
0
/**
 * \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;
	}
}
示例#10
0
文件: dac.c 项目: InSoonPark/asf
/**
 * \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;
}
示例#11
0
/**
 * \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;
}
示例#12
0
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);
}
示例#13
0
/**
 * \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);
};
示例#14
0
/**
 * \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);
	}
}
示例#15
0
文件: port.c 项目: AWGES/StormSAMR21
/**
 *  \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);
}
示例#16
0
/**
 * \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;
}
示例#17
0
/**
 * \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;
	}
}
示例#18
0
/*---------------------------------------------------------------------------*/
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);
  }
}
示例#19
0
文件: port.c 项目: AWGES/StormSAMR21
/**
 *  \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);
}
示例#20
0
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

}
示例#21
0
//! [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]
}
示例#22
0
/** 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;
		}
	}
}
示例#23
0
文件: tc.c 项目: AlessandroA/mbed
/**
 * \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;
}
示例#24
0
文件: adc.c 项目: AWGES/StormSAMR21
/**
* \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);
	}
示例#25
0
文件: i2s.c 项目: Realtime-7/asf
/**
 * \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;
}
示例#27
0
文件: usart.c 项目: Wiredhome/mbed
/**
 * \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);
        }
    }
示例#28
0
文件: adc.c 项目: Gussy/sam0
/**
* \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);
	}
示例#29
0
/**
 * \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;
}
示例#30
0
文件: dbg_print.c 项目: marekr/asf
/**
 * \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);
		}
	}