void configure_gclock_channel(void)
{
//! [setup_6]
	struct system_gclk_chan_config gclk_chan_conf;
//! [setup_6]
//! [setup_7]
	system_gclk_chan_get_config_defaults(&gclk_chan_conf);
//! [setup_7]

//! [setup_8]
	gclk_chan_conf.source_generator = GCLK_GENERATOR_1;
//! [setup_8]
#if (SAMD10) || (SAMD11)
//! [setup_9]
	system_gclk_chan_set_config(TC1_GCLK_ID, &gclk_chan_conf);
//! [setup_9]

//! [setup_10]
	system_gclk_chan_enable(TC1_GCLK_ID);
//! [setup_10]
#else
//! [setup_9]
	system_gclk_chan_set_config(TC3_GCLK_ID, &gclk_chan_conf);
//! [setup_9]

//! [setup_10]
	system_gclk_chan_enable(TC3_GCLK_ID);
//! [setup_10]
#endif
}
/**
 * \brief Set GCLK channel to generator.
 *
 * This will set the appropriate GCLK channel to the requested GCLK generator.
 * This will set the generator for all SERCOM instances, and the user will thus
 * only be able to set the same generator that has previously been set, if any.
 *
 * After the generator has been set the first time, the generator can be changed
 * using the \c force_change flag.
 *
 * \param[in]  generator_source The generator to use for SERCOM.
 * \param[in]  force_change     Force change the generator.
 *
 * \return Status code indicating the GCLK generator change operation.
 * \retval STATUS_OK                       If the generator update request was
 *                                         successful.
 * \retval STATUS_ERR_ALREADY_INITIALIZED  If a generator was already configured
 *                                         and the new configuration was not
 *                                         forced.
 */
enum status_code sercom_set_gclk_generator(
		const enum gclk_generator generator_source,
		const bool force_change)
{
	/* Check if valid option. */
	if (!_sercom_config.generator_is_set || force_change) {
		/* Create and fill a GCLK configuration structure for the new config. */
		struct system_gclk_chan_config gclk_chan_conf;
		system_gclk_chan_get_config_defaults(&gclk_chan_conf);
		gclk_chan_conf.source_generator = generator_source;
		system_gclk_chan_set_config(SERCOM_GCLK_ID, &gclk_chan_conf);
		system_gclk_chan_enable(SERCOM_GCLK_ID);

		/* Save config. */
		_sercom_config.generator_source = generator_source;
		_sercom_config.generator_is_set = true;

		return STATUS_OK;
	} else if (generator_source == _sercom_config.generator_source) {
		/* Return status OK if same config. */
		return STATUS_OK;
	}

	/* Return invalid config to already initialized GCLK. */
	return STATUS_ERR_ALREADY_INITIALIZED;
}
示例#3
0
文件: ac.c 项目: Gussy/sam0
static enum status_code _ac_set_config(
    struct ac_module *const module_inst,
    struct ac_config *const config)
{
    /* Sanity check arguments */
    Assert(module_inst);
    Assert(module_inst->hw);
    Assert(config);

    UNUSED(module_inst);

    /* Set up GCLK */
    struct system_gclk_chan_config gclk_chan_conf;
    system_gclk_chan_get_config_defaults(&gclk_chan_conf);
    gclk_chan_conf.source_generator = config->source_generator;
#if (SAMC21) || (SAMC20)
    /* The Analog Comparators and ADC1 use the same generic clock configuration.
     * GCLK_ADC1 must be used to configure the clock for AC as GCLK_AC is not
     * functional. Errata reference: 13404
     */
    system_gclk_chan_set_config(ADC1_GCLK_ID, &gclk_chan_conf);
    system_gclk_chan_enable(ADC1_GCLK_ID);
#else
    system_gclk_chan_set_config(AC_GCLK_ID, &gclk_chan_conf);
    system_gclk_chan_enable(AC_GCLK_ID);
#endif

    return STATUS_OK;
}
示例#4
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;
}
示例#5
0
文件: freqm.c 项目: csz-cmy/rt-thread
/**
 * \brief Initializes a hardware FREQM module instance.
 *
 * Enables the clock and initializes the FREQM 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 FREQM hardware module
 * \param[in]     config       Pointer to the FREQM configuration options struct
 *
 * \return Status of the initialization procedure.
 *
 * \retval STATUS_OK           The module was initialized successfully
 */
enum status_code freqm_init(
		struct freqm_module *const module_inst,
		Freqm *const hw,
		struct freqm_config *const config)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(hw);
	Assert(config);
	Assert(config->ref_clock_circles);

	/* Initialize device instance */
	module_inst->hw = hw;

	/* Turn on the digital interface clock */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, MCLK_APBAMASK_FREQM);

	/* 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->msr_clock_source;
	system_gclk_chan_set_config(FREQM_GCLK_ID_MSR, &gclk_chan_conf);
	system_gclk_chan_enable(FREQM_GCLK_ID_MSR);

	gclk_chan_conf.source_generator = config->ref_clock_source;
	system_gclk_chan_set_config(FREQM_GCLK_ID_REF, &gclk_chan_conf);
	system_gclk_chan_enable(FREQM_GCLK_ID_REF);
	
	module_inst->ref_clock_freq = system_gclk_gen_get_hz(config->ref_clock_source);

	/* Perform a software reset */
	hw->CTRLA.reg = FREQM_CTRLA_SWRST;

	while (freqm_is_syncing()) {
		/* Wait for all hardware modules to complete synchronization */
	}

	/* Initialize the FREQM with new configurations */
	hw->CFGA.reg = config->ref_clock_circles;

#if FREQM_CALLBACK_MODE == true
	/* Initialize parameters */
	for (uint8_t i = 0; i < FREQM_CALLBACK_N; i++) {
		module_inst->callback[i] = NULL;
	}
	/* Register this instance for callbacks*/
	_freqm_instance = module_inst;
#endif

	return STATUS_OK;
}
示例#6
0
void _system_extint_init(void)
{
	Eic *const eics[EIC_INST_NUM] = EIC_INSTS;

	/* Turn on the digital interface clock */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, MCLK_APBAMASK_EIC);

#if (EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK)
	/* Configure the generic clock for the module and enable it */
	struct system_gclk_chan_config gclk_chan_conf;
	system_gclk_chan_get_config_defaults(&gclk_chan_conf);
	gclk_chan_conf.source_generator = EXTINT_CLOCK_SOURCE;
	system_gclk_chan_set_config(EIC_GCLK_ID, &gclk_chan_conf);

	/* Enable the clock anyway, since when needed it will be requested
	 * by External Interrupt driver */
	system_gclk_chan_enable(EIC_GCLK_ID);
#endif

	/* Reset all EIC hardware modules. */
	for (uint32_t i = 0; i < EIC_INST_NUM; i++) {
		eics[i]->CTRLA.reg |= EIC_CTRLA_SWRST;
	}

	while (extint_is_syncing()) {
		/* Wait for all hardware modules to complete synchronization */
	}

#if (EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK)
	for (uint32_t i = 0; i < EIC_INST_NUM; i++) {
		eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_GCLK;
	}
#else
	for (uint32_t i = 0; i < EIC_INST_NUM; i++) {
		eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_ULP32K;
	}
#endif

	/* Reset the software module */
#if EXTINT_CALLBACK_MODE == true
	/* Clear callback registration table */
	for (uint8_t j = 0; j < EIC_NUMBER_OF_INTERRUPTS; j++) {
		_extint_dev.callbacks[j] = NULL;
	}
	system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_EIC);
#endif

	/* Enables the driver for further use */
	_extint_enable();
}
示例#7
0
文件: touch.c 项目: Mazetti/asf
void touch_configure_ptc_clock(void)
{
	struct system_gclk_chan_config gclk_chan_conf;

	system_gclk_chan_get_config_defaults(&gclk_chan_conf);

	gclk_chan_conf.source_generator = GCLK_GENERATOR_1;

	system_gclk_chan_set_config(PTC_GCLK_ID, &gclk_chan_conf);

	system_gclk_chan_enable(PTC_GCLK_ID);

	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PTC_APBC_BITMASK);
}
示例#8
0
void ccl_init(struct ccl_config *const config)
{
	/* Turn on the digital interface clock. */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, MCLK_APBDMASK_CCL);

	/* Reset module. */
	ccl_module_reset();

	/* 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(CCL_GCLK_ID, &gclk_chan_conf);
	system_gclk_chan_enable(CCL_GCLK_ID);

	if(config->run_in_standby) {
		ccl_gclk_runstdby_enable();
	} else {
		ccl_gclk_runstdby_disable();
	}
}
示例#9
0
/**
 * \brief Initializes the RTC module with given configurations.
 *
 * Initializes the module, setting up all given configurations to provide
 * the desired functionality of the RTC.
 *
 * \param[out] module  Pointer to the software instance struct
 * \param[in]   hw      Pointer to hardware instance
 * \param[in] config  Pointer to the configuration structure
 *
 * \return Status of the initialization procedure.
 * \retval STATUS_OK               If the initialization was run stressfully
 * \retval STATUS_ERR_INVALID_ARG  If invalid argument(s) were given
 */
enum status_code rtc_count_init(
		struct rtc_module *const module,
		Rtc *const hw,
		const struct rtc_count_config *const config)
{
	/* Sanity check arguments */
	Assert(module);
	Assert(hw);
	Assert(config);

	/* Initialize device instance */
	module->hw = hw;

	/* Turn on the digital interface clock */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, PM_APBAMASK_RTC);

	/* Set up GCLK */
	struct system_gclk_chan_config gclk_chan_conf;
	system_gclk_chan_get_config_defaults(&gclk_chan_conf);
	gclk_chan_conf.source_generator = GCLK_GENERATOR_2;
	system_gclk_chan_set_config(RTC_GCLK_ID, &gclk_chan_conf);
	system_gclk_chan_enable(RTC_GCLK_ID);

	/* Reset module to hardware defaults. */
	rtc_count_reset(module);

	/* Save conf_struct internally for continued use. */
	module->mode                = config->mode;
	module->continuously_update = config->continuously_update;

#  if (RTC_INST_NUM == 1)
	_rtc_instance[0] = module;
#  else
	/* Register this instance for callbacks*/
	_rtc_instance[_rtc_get_inst_index(hw)] = module;
#  endif

	/* Set config and return status. */
	return _rtc_count_set_config(module, config);
}
示例#10
0
文件: events.c 项目: Gussy/sam0
enum status_code events_allocate(
		struct events_resource *resource,
		struct events_config *config)
{
	uint8_t new_channel;

	Assert(resource);

	new_channel = _events_find_first_free_channel_and_allocate();

	if(new_channel == EVENTS_INVALID_CHANNEL) {
		return STATUS_ERR_NOT_FOUND;
	}

	resource->channel = new_channel;

	if (config->path != EVENTS_PATH_ASYNCHRONOUS) {
		/* Set up a GLCK channel to use with the specific channel */
		struct system_gclk_chan_config gclk_chan_conf;

		system_gclk_chan_get_config_defaults(&gclk_chan_conf);
		gclk_chan_conf.source_generator =
				(enum gclk_generator)config->clock_source;
		system_gclk_chan_set_config(EVSYS_GCLK_ID_0 + new_channel, &gclk_chan_conf);
		system_gclk_chan_enable(EVSYS_GCLK_ID_0 + new_channel);
	}

	/* Save channel setting and configure it after user multiplexer */
	resource->channel_reg = EVSYS_CHANNEL_EVGEN(config->generator)           |
			EVSYS_CHANNEL_PATH(config->path)                                 |
			((uint32_t)config->run_in_standby << EVSYS_CHANNEL_RUNSTDBY_Pos) |
			((uint32_t)config->on_demand << EVSYS_CHANNEL_ONDEMAND_Pos) |
			EVSYS_CHANNEL_EDGSEL(config->edge_detect);

	return STATUS_OK;
}
示例#11
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;
}
/**
 * \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;
}
示例#13
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);
        }
    }
示例#14
0
/**
 * \brief Initialize hardware and driver instance
 *
 * This function configures the clock system for the specified SERCOM module,
 * sets up the related pins and their MUX, initializes the SERCOM in SPI master
 * mode, and prepares the driver instance for operation.
 *
 * \pre \ref system_init() must have been called prior to this function.
 *
 * The SERCOM SPI module is left disabled after initialization, and must be
 * enabled with \ref spi_master_vec_enable() before a transfer can be done.
 *
 * \param[out] module Driver instance to initialize.
 * \param[in,out] sercom SERCOM module to initialize and associate driver
 * instance with.
 * \param[in] config Driver configuration to use.
 *
 * \return Status of initialization.
 * \retval STATUS_OK if initialization succeeded.
 * \retval STATUS_ERR_INVALID_ARG if driver has been misconfigured.
 */
enum status_code spi_master_vec_init(struct spi_master_vec_module *const module,
		Sercom *const sercom, const struct spi_master_vec_config *const config)
{
	Assert(module);
	Assert(sercom);
	Assert(config);

	enum status_code status;
	SercomSpi *const spi_hw = &(sercom->SPI);
	struct system_gclk_chan_config gclk_chan_conf;
	uint16_t tmp_baud;
	uint32_t sercom_index = _sercom_get_sercom_inst_index((Sercom *)spi_hw);
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)
	uint32_t pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
#else
	uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
#endif
	uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
	uint32_t gclk_hz;

	module->sercom = sercom;

	/* Enable clock for the module interface */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);

	/* Set up the GCLK for the module */
	system_gclk_chan_get_config_defaults(&gclk_chan_conf);
	gclk_chan_conf.source_generator = config->gclk_generator;
	system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
	system_gclk_chan_enable(gclk_index);
	sercom_set_gclk_generator(config->gclk_generator, false);

	_spi_master_vec_wait_for_sync(spi_hw);

	/* Set up the SERCOM SPI module as master */
	spi_hw->CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3);
	spi_hw->CTRLA.reg |= (uint32_t)config->mux_setting
			| config->transfer_mode
			| config->data_order
			| ((config->run_in_standby || system_is_debugger_present()) ?
					SERCOM_SPI_CTRLA_RUNSTDBY : 0);

	/* Get baud value from configured baudrate and internal clock rate */
	gclk_hz = system_gclk_chan_get_hz(gclk_index);
	status = _sercom_get_sync_baud_val(config->baudrate, gclk_hz, &tmp_baud);

	if (status != STATUS_OK) {
		/* Baud rate calculation error! */
		return STATUS_ERR_INVALID_ARG;
	}

	spi_hw->BAUD.reg = (uint8_t)tmp_baud;

	/* Configure the pin multiplexers */
	_spi_master_vec_pinmux_helper(config->pinmux_pad0, sercom, 0);
	_spi_master_vec_pinmux_helper(config->pinmux_pad3, sercom, 3);

	/* SERCOM PAD1 and PAD2 are used for slave SS.
	 * This is a SPI master driver, so control of slave SS must be left to
	 * the PORT module, i.e., peripheral MUX should not be set for that pin.
	 * DOPO controls which PAD is used for slave SS:
	 * If DOPO is odd, SERCOM_PAD1 is SS: SERCOM_PAD2 can be MUXed.
	 * If DOPO is even, SERCOM_PAD2 is SS: SERCOM_PAD1 can be MUXed.
	 */
	if (config->mux_setting & (1 << SERCOM_SPI_CTRLA_DOPO_Pos)) {
		_spi_master_vec_pinmux_helper(config->pinmux_pad2, sercom, 2);
	} else {
		_spi_master_vec_pinmux_helper(config->pinmux_pad1, sercom, 1);
	}

	/* Initialize our instance and register interrupt handler + data */
	module->rx_bufdesc_ptr = NULL;
	module->tx_bufdesc_ptr = NULL;
	module->direction = SPI_MASTER_VEC_DIRECTION_IDLE;
	module->status = STATUS_OK;
#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT
	CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE(module->busy_semaphore);
#endif

	_sercom_set_handler(sercom_index, _spi_master_vec_int_handler);
	_sercom_instances[sercom_index] = module;

	return STATUS_OK;
}
示例#15
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);
		}
	}
示例#16
0
文件: spi_api.c 项目: Wiredhome/mbed
/** Initialize the SPI peripheral
 *
 * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral
 * @param[out] obj  The SPI object to initialize
 * @param[in]  mosi The pin to use for MOSI
 * @param[in]  miso The pin to use for MISO
 * @param[in]  sclk The pin to use for SCLK
 * @param[in]  ssel The pin to use for SSEL
 */
void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
{
    uint16_t baud = 0;
    uint32_t ctrla = 0;
    uint32_t ctrlb = 0;
    enum status_code error_code;

    if (g_sys_init == 0) {
        system_init();
        g_sys_init = 1;
    }

    /* TODO: Calculate SERCOM instance from pins */
    /* TEMP: Giving external SPI module value of SAMR21 for now */
    pSPI_SERCOM(obj) = EXT1_SPI_MODULE;

    /* Disable SPI */
    spi_disable(obj);

    /* Check if reset is in progress. */
    if (_SPI(obj).CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) {
        return;
    }
    uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj));
    uint32_t pm_index, gclk_index;
#if (SAML21)
    if (sercom_index == 5) {
        pm_index     = MCLK_APBDMASK_SERCOM5_Pos;
        gclk_index   =  SERCOM5_GCLK_ID_CORE;
    } else {
        pm_index     = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
        gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
    }
#else
    pm_index     = sercom_index + PM_APBCMASK_SERCOM0_Pos;
    gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
#endif

    /* Turn on module in PM */
#if (SAML21)
    if (sercom_index == 5) {
        system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index);
    } else {
        system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
    }
#else
    system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
#endif

    /* Set up the GCLK for the module */
    struct system_gclk_chan_config gclk_chan_conf;
    system_gclk_chan_get_config_defaults(&gclk_chan_conf);
    gclk_chan_conf.source_generator = GCLK_GENERATOR_0;
    system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
    system_gclk_chan_enable(gclk_index);
    sercom_set_gclk_generator(GCLK_GENERATOR_0, false);

#if DEVICE_SPI_ASYNCH
    /* Save the object */
    _sercom_instances[sercom_index] = obj;

    /* Configure interrupt handler */
    NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)_sercom_handlers[sercom_index]);
#endif

    /* Set the SERCOM in SPI master mode */
    _SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3);
    pSPI_S(obj)->mode = SPI_MODE_MASTER;

    /* TODO: Do pin muxing here */
    struct system_pinmux_config pin_conf;
    system_pinmux_get_config_defaults(&pin_conf);
    pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;

    uint32_t pad_pinmuxes[] = {
        EXT1_SPI_SERCOM_PINMUX_PAD0, EXT1_SPI_SERCOM_PINMUX_PAD1,
        EXT1_SPI_SERCOM_PINMUX_PAD2, EXT1_SPI_SERCOM_PINMUX_PAD3
    };

    /* Configure the SERCOM pins according to the user configuration */
    for (uint8_t pad = 0; pad < 4; pad++) {
        uint32_t current_pinmux = pad_pinmuxes[pad];
        if (current_pinmux != PINMUX_UNUSED) {
            pin_conf.mux_position = current_pinmux & 0xFFFF;
            system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf);
        }
    }
示例#17
0
/**
 * \brief Initializes the requested I<SUP>2</SUP>C hardware module
 *
 * Initializes the SERCOM I<SUP>2</SUP>C master device requested and sets the provided
 * software module struct. Run this function before any further use of
 * the driver.
 *
 * \param[out] module  Pointer to software module struct
 * \param[in]  hw      Pointer to the hardware instance
 * \param[in]  config  Pointer to the configuration struct
 *
 * \return Status of initialization.
 * \retval STATUS_OK                        Module initiated correctly
 * \retval STATUS_ERR_DENIED                If module is enabled
 * \retval STATUS_BUSY                      If module is busy resetting
 * \retval STATUS_ERR_ALREADY_INITIALIZED   If setting other GCLK generator than
 *                                          previously set
 * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE  If given baudrate is not compatible
 *                                          with set GCLK frequency
 *
 */
enum status_code i2c_master_init(
		struct i2c_master_module *const module,
		Sercom *const hw,
		const struct i2c_master_config *const config)
{
	/* Sanity check arguments. */
	Assert(module);
	Assert(hw);
	Assert(config);

	/* Initialize software module */
	module->hw = hw;

	SercomI2cm *const i2c_module = &(module->hw->I2CM);

	uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
#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;

	/* 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);

	/* Check if module is enabled. */
	if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_ENABLE) {
		return STATUS_ERR_DENIED;
	}

	/* Check if reset is in progress. */
	if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST) {
		return STATUS_BUSY;
	}

#if I2C_MASTER_CALLBACK_MODE == true
	/* Get sercom instance index and register callback. */
	uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw);
	_sercom_set_handler(instance_index, _i2c_master_interrupt_handler);
	_sercom_instances[instance_index] = module;

	/* Initialize values in module. */
	module->registered_callback = 0;
	module->enabled_callback = 0;
	module->buffer_length = 0;
	module->buffer_remaining = 0;

	module->status = STATUS_OK;
	module->buffer = NULL;
#endif

	/* Set sercom module to operate in I2C master mode. */
	i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE(0x5);

	/* Set config and return status. */
	return _i2c_master_set_config(module, config);
}
示例#18
0
文件: sdadc.c 项目: Gussy/sam0
/**
 * \internal Writes an SDADC configuration to the hardware module
 *
 * Writes out a given SDADC module configuration to the hardware module.
 *
 * \param[out] module_inst  Pointer to the SDADC software instance struct
 * \param[in]  config       Pointer to configuration struct
 *
 * \return Status of the configuration procedure.
 * \retval STATUS_OK               The configuration was successful
 * \retval STATUS_ERR_INVALID_ARG  Invalid argument(s) were provided
 */
static enum status_code _sdadc_set_config(
		struct sdadc_module *const module_inst,
		struct sdadc_config *const config)
{
	/* Get the hardware module pointer */
	Sdadc *const sdadc_module = module_inst->hw;

	/* 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(SDADC_GCLK_ID, &gclk_chan_conf);
	system_gclk_chan_enable(SDADC_GCLK_ID);

	/* Setup pinmuxing for analog inputs */
	_sdadc_configure_ain_pin(config->mux_input);

	/* Configure run in standby */
	sdadc_module->CTRLA.reg = (config->run_in_standby << SDADC_CTRLA_RUNSTDBY_Pos)
			| (config->on_command << SDADC_CTRLA_ONDEMAND_Pos);

	while (sdadc_is_syncing(module_inst)) {
		/* Wait for synchronization */
	}

	/* Configure reference */
	sdadc_module->REFCTRL.reg = (config->reference.ref_sel) | (config->reference.ref_range) |
						(config->reference.on_ref_buffer << SDADC_REFCTRL_ONREFBUF_Pos);

	/* Configure CTRLB */
	sdadc_module->CTRLB.reg =
			(config->skip_count << SDADC_CTRLB_SKPCNT_Pos) |
			(config->clock_prescaler / 2 - 1) | config->osr;

	while (sdadc_is_syncing(module_inst)) {
		/* Wait for synchronization */
	}

	/* Configure CTRLC */
	sdadc_module->CTRLC.reg =
			(config->freerunning << SDADC_CTRLC_FREERUN_Pos);

	/* Configure SEQCTRL */
	sdadc_module->SEQCTRL.reg =
			(config->seq_enable[0]) | (config->seq_enable[1] << 1) | (config->seq_enable[2] << 2);

	/* Check validity of window thresholds */
	if (config->window.window_mode != SDADC_WINDOW_MODE_DISABLE) {
		if (config->window.window_lower_value > (int32_t)(SDADC_RESULT_RESULT_Msk / 2) ||
			config->window.window_lower_value < -(int32_t)(SDADC_RESULT_RESULT_Msk / 2 + 1) ||
			config->window.window_upper_value > (int32_t)(SDADC_RESULT_RESULT_Msk / 2) ||
			config->window.window_upper_value < -(int32_t)(SDADC_RESULT_RESULT_Msk / 2 + 1)) {
			/* Invalid value */
			return STATUS_ERR_INVALID_ARG;
		} else if (config->window.window_lower_value > (int32_t)SDADC_RESULT_RESULT_Msk ||
				config->window.window_upper_value > (int32_t)SDADC_RESULT_RESULT_Msk){
			/* Invalid value */
			return STATUS_ERR_INVALID_ARG;
		}
	}

	while (sdadc_is_syncing(module_inst)) {
		/* Wait for synchronization */
	}

	/* Configure window mode */
	sdadc_module->WINCTRL.reg = config->window.window_mode;

	while (sdadc_is_syncing(module_inst)) {
		/* Wait for synchronization */
	}

	/* Configure lower threshold */
	sdadc_module->WINLT.reg =
			config->window.window_lower_value << SDADC_WINLT_WINLT_Pos;

	while (sdadc_is_syncing(module_inst)) {
		/* Wait for synchronization */
	}

	/* Configure lower threshold */
	sdadc_module->WINUT.reg = config->window.window_upper_value <<
			SDADC_WINUT_WINUT_Pos;

	while (sdadc_is_syncing(module_inst)) {
		/* Wait for synchronization */
	}

	/* Configure pin scan mode and positive and negative input pins */
	sdadc_module->INPUTCTRL.reg = config->mux_input;

	/* Configure events */
	sdadc_module->EVCTRL.reg = config->event_action;

	/* Disable all interrupts */
	sdadc_module->INTENCLR.reg = (1 << SDADC_INTENCLR_WINMON_Pos) |
			(1 << SDADC_INTENCLR_OVERRUN_Pos) | (1 << SDADC_INTENCLR_RESRDY_Pos);

	/* Make sure offset correction value is valid */
	if (config->correction.offset_correction > (int32_t)(SDADC_OFFSETCORR_MASK / 2) ||
		config->correction.offset_correction < - (int32_t)(SDADC_OFFSETCORR_MASK / 2 + 1)) {
		return STATUS_ERR_INVALID_ARG;
	} else {
		while (sdadc_is_syncing(module_inst)) {
			/* Wait for synchronization */
		}

		/* Set offset correction value */
		sdadc_module->OFFSETCORR.reg = config->correction.offset_correction <<
				SDADC_OFFSETCORR_OFFSETCORR_Pos;
	}

	/* Make sure gain_correction value is valid */
	if (config->correction.gain_correction > SDADC_GAINCORR_MASK) {
		return STATUS_ERR_INVALID_ARG;
	} else {
		while (sdadc_is_syncing(module_inst)) {
			/* Wait for synchronization */
		}

		/* Set gain correction value */
		sdadc_module->GAINCORR.reg = config->correction.gain_correction <<
				SDADC_GAINCORR_GAINCORR_Pos;
	}

	/* Make sure shift_correction value is valid */
	if (config->correction.shift_correction > SDADC_SHIFTCORR_MASK) {
		return STATUS_ERR_INVALID_ARG;
	} else {
		while (sdadc_is_syncing(module_inst)) {
			/* Wait for synchronization */
		}

		/* Set shift correction value */
		sdadc_module->SHIFTCORR.reg = config->correction.shift_correction <<
				SDADC_SHIFTCORR_SHIFTCORR_Pos;
	}

	return STATUS_OK;
}
示例#19
0
文件: i2c_slave.c 项目: Gussy/sam0
/**
 * \brief Initializes the requested I<SUP>2</SUP>C hardware module
 *
 * Initializes the SERCOM I<SUP>2</SUP>C slave device requested and sets the provided
 * software module struct.  Run this function before any further use of
 * the driver.
 *
 * \param[out] module  Pointer to software module struct
 * \param[in]  hw      Pointer to the hardware instance
 * \param[in]  config  Pointer to the configuration struct
 *
 * \return Status of initialization.
 * \retval STATUS_OK                       Module initiated correctly
 * \retval STATUS_ERR_DENIED               If module is enabled
 * \retval STATUS_BUSY                     If module is busy resetting
 * \retval STATUS_ERR_ALREADY_INITIALIZED  If setting other GCLK generator than
 *                                         previously set
 */
enum status_code i2c_slave_init(
		struct i2c_slave_module *const module,
		Sercom *const hw,
		const struct i2c_slave_config *const config)
{
	/* Sanity check arguments */
	Assert(module);
	Assert(hw);
	Assert(config);

	/* Initialize software module */
	module->hw = hw;

	SercomI2cs *const i2c_hw = &(module->hw->I2CS);

	/* Check if module is enabled */
	if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_ENABLE) {
		return STATUS_ERR_DENIED;
	}

	/* Check if reset is in progress */
	if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_SWRST) {
		return STATUS_BUSY;
	}

	uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
	uint32_t pm_index, gclk_index; 
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21)
#if (SAML21)
	if (sercom_index == 5) {
		pm_index     = MCLK_APBDMASK_SERCOM5_Pos;
		gclk_index   = SERCOM5_GCLK_ID_CORE;
	} else {
		pm_index     = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
		gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
	}
#else
	pm_index     = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
	gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
#endif
#else
	pm_index     = sercom_index + PM_APBCMASK_SERCOM0_Pos;
	gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
#endif
	
	/* Turn on module in PM */
#if (SAML21)
	if (sercom_index == 5) {
		system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index);
	} else {
		system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);	
	}
#else
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
#endif

	/* Set up the GCLK for the module */
	struct system_gclk_chan_config gclk_chan_conf;
	system_gclk_chan_get_config_defaults(&gclk_chan_conf);
	gclk_chan_conf.source_generator = config->generator_source;
	system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
	system_gclk_chan_enable(gclk_index);
	sercom_set_gclk_generator(config->generator_source, false);

#if I2C_SLAVE_CALLBACK_MODE == true
	/* Get sercom instance index */
	uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw);

	/* Save software module in interrupt handler */
	_sercom_set_handler(instance_index, _i2c_slave_interrupt_handler);

	/* Save software module */
	_sercom_instances[instance_index] = module;

	/* Initialize values in module */
	module->registered_callback = 0;
	module->enabled_callback = 0;
	module->buffer_length = 0;
	module->nack_on_address = config->enable_nack_on_address;
#endif

	/* Set SERCOM module to operate in I2C slave mode */
	i2c_hw->CTRLA.reg = SERCOM_I2CS_CTRLA_MODE(0x4);

	/* Set config and return status */
	return _i2c_slave_set_config(module, config);
}
示例#20
0
文件: i2s.c 项目: Realtime-7/asf
/**
 * \brief Configure specified I2S clock unit
 *
 * Enables the clock and initialize the clock unit, based on the given
 * configurations.
 *
 * \param[in,out] module_inst  Pointer to the software module instance struct
 * \param[in]     clock_unit   I2S clock unit to initialize and configure
 * \param[in]     config       Pointer to the I2S clock unit 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
 * \retval STATUS_ERR_INVALID_ARG Invalid divider value or
 *                                MCK direction setting conflict
 */
enum status_code i2s_clock_unit_set_config(
		struct i2s_module *const module_inst,
		const enum i2s_clock_unit clock_unit,
		const struct i2s_clock_unit_config *config)
{
	Assert(module_inst);
	Assert(module_inst->hw);
	Assert(clock_unit < I2S_CLOCK_UNIT_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_CKEN0 << clock_unit)) {
		return STATUS_BUSY;
	}
	/* Already enabled ? */
	if (ctrla & (I2S_CTRLA_CKEN0 << clock_unit)) {
		return STATUS_ERR_DENIED;
	}
	/* Parameter check */
	if (config->clock.mck_src && config->clock.mck_out_enable) {
		return STATUS_ERR_INVALID_ARG;
	}

	/* Initialize Clock Unit */
	uint32_t clkctrl =
		(config->clock.mck_out_invert ? I2S_CLKCTRL_MCKOUTINV : 0) |
		(config->clock.sck_out_invert ? I2S_CLKCTRL_SCKOUTINV : 0) |
		(config->frame.frame_sync.invert_out ? I2S_CLKCTRL_FSOUTINV : 0) |
		(config->clock.mck_out_enable ? I2S_CLKCTRL_MCKEN : 0) |
		(config->clock.mck_src ? I2S_CLKCTRL_MCKSEL : 0) |
		(config->clock.sck_src ? I2S_CLKCTRL_SCKSEL : 0) |
		(config->frame.frame_sync.invert_use ? I2S_CLKCTRL_FSINV : 0) |
		(config->frame.frame_sync.source ? I2S_CLKCTRL_FSSEL : 0) |
		(config->frame.data_delay ? I2S_CLKCTRL_BITDELAY : 0);

	uint8_t div_val = config->clock.mck_out_div;
	if ((div_val > 0x21) || (div_val == 0)) {
		return STATUS_ERR_INVALID_ARG;
	} else {
		div_val --;
	}
	clkctrl |= I2S_CLKCTRL_MCKOUTDIV(div_val);

	div_val = config->clock.sck_div;
	if ((div_val > 0x21) || (div_val == 0)) {
		return STATUS_ERR_INVALID_ARG;
	} else {
		div_val --;
	}
	clkctrl |= I2S_CLKCTRL_MCKDIV(div_val);

	uint8_t number_slots = config->frame.number_slots;
	if (number_slots > 8) {
		return STATUS_ERR_INVALID_ARG;
	} else if (number_slots > 0) {
		number_slots --;
	}
	clkctrl |=
			I2S_CLKCTRL_NBSLOTS(number_slots) |
			I2S_CLKCTRL_FSWIDTH(config->frame.frame_sync.width) |
			I2S_CLKCTRL_SLOTSIZE(config->frame.slot_size);

	/* Write clock unit configurations */
	module_inst->hw->CLKCTRL[clock_unit].reg = clkctrl;

	/* Select general clock source */
	const uint8_t i2s_gclk_ids[2] = {I2S_GCLK_ID_0, I2S_GCLK_ID_1};
	struct system_gclk_chan_config gclk_chan_config;
	system_gclk_chan_get_config_defaults(&gclk_chan_config);
	gclk_chan_config.source_generator = config->clock.gclk_src;
	system_gclk_chan_set_config(i2s_gclk_ids[clock_unit], &gclk_chan_config);
	system_gclk_chan_enable(i2s_gclk_ids[clock_unit]);

	/* Initialize pins */
	struct system_pinmux_config pin_config;
	system_pinmux_get_config_defaults(&pin_config);
	if (config->mck_pin.enable) {
		pin_config.mux_position = config->mck_pin.mux;
		system_pinmux_pin_set_config(config->mck_pin.gpio, &pin_config);
	}
	if (config->sck_pin.enable) {
		pin_config.mux_position = config->sck_pin.mux;
		system_pinmux_pin_set_config(config->sck_pin.gpio, &pin_config);
	}
	if (config->fs_pin.enable) {
		pin_config.mux_position = config->fs_pin.mux;
		system_pinmux_pin_set_config(config->fs_pin.gpio, &pin_config);
	}

	return STATUS_OK;
}