Ejemplo n.º 1
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, MCLK_APBAMASK_RTC);

	/* Select RTC clock */
	OSC32KCTRL->RTCCTRL.reg = RTC_CLOCK_SOURCE;

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

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

#  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);
}
Ejemplo n.º 2
0
Archivo: events.c Proyecto: Gussy/sam0
void _system_events_init(void)
{
#if (SAML22) || (SAMC20) || (SAMC21)
	/* Enable EVSYS register interface */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_EVSYS);
#else
	/* Enable EVSYS register interface */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, MCLK_APBDMASK_EVSYS);
#endif

	/* Make sure the EVSYS module is properly reset */
	EVSYS->CTRLA.reg = EVSYS_CTRLA_SWRST;

	while (EVSYS->CTRLA.reg & EVSYS_CTRLA_SWRST) {
	}
}
Ejemplo n.º 3
0
Archivo: dac.c Proyecto: 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;
}
Ejemplo n.º 4
0
Archivo: ac.c Proyecto: Gussy/sam0
/** \brief Initializes and configures the Analog Comparator driver.
 *
 *  Initializes the Analog Comparator driver, configuring it to the user
 *  supplied configuration parameters, ready for use. This function should be
 *  called before enabling the Analog Comparator.
 *
 *  \note Once called the Analog Comparator will not be running; to start the
 *        Analog Comparator call \ref ac_enable() after configuring the module.
 *
 * \param[out] module_inst  Pointer to the AC software instance struct
 * \param[in]  hw           Pointer to the AC module instance
 * \param[in]  config       Pointer to the config struct, created by the user
 *                          application
 */
enum status_code ac_init(
    struct ac_module *const module_inst,
    Ac *const hw,
    struct ac_config *const config)
{
    /* Sanity check arguments */
    Assert(module_inst);
    Assert(hw);
    Assert(config);

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

#if (SAML21)
    /* Turn on the digital interface clock */
    system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, MCLK_APBDMASK_AC);
#else
    /* Turn on the digital interface clock */
    system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_AC);
#endif

#if AC_CALLBACK_MODE == true
    /* Initialize parameters */
    for (uint8_t i = 0; i < AC_CALLBACK_N; i++) {
        module_inst->callback[i]        = NULL;
    }

    /* Initialize software flags*/
    module_inst->register_callback_mask = 0x00;
    module_inst->enable_callback_mask   = 0x00;

#  if (AC_INST_NUM == 1)
    _ac_instance[0] = module_inst;
#  else
    /* Register this instance for callbacks*/
    _ac_instance[_ac_get_inst_index(hw)] = module_inst;
#  endif
#endif

    /* Write configuration to module */
    return _ac_set_config(module_inst, config);
}
Ejemplo n.º 5
0
/**
 * \brief Initializes the GCLK driver.
 *
 * Initializes the Generic Clock module, disabling and resetting all active
 * Generic Clock Generators and Channels to their power-on default values.
 */
void system_gclk_init(void)
{
	/* Turn on the digital interface clock */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBA, PM_APBAMASK_GCLK);

	/* Software reset the module to ensure it is re-initialized correctly */
	GCLK->CTRL.reg = GCLK_CTRL_SWRST;
	while (GCLK->CTRL.reg & GCLK_CTRL_SWRST) {
		/* Wait for reset to complete */
	}
}
Ejemplo n.º 6
0
Archivo: sdadc.c Proyecto: Gussy/sam0
/**
 * \brief Initializes the SDADC.
 *
 * Initializes the SDADC device struct and the hardware module based on the
 * given configuration struct values.
 *
 * \param[out] module_inst Pointer to the SDADC software instance struct
 * \param[in]  hw          Pointer to the SDADC module instance
 * \param[in]  config      Pointer to the configuration struct
 *
 * \return Status of the initialization procedure.
 * \retval STATUS_OK                The initialization was successful
 * \retval STATUS_ERR_INVALID_ARG   Invalid argument(s) were provided
 * \retval STATUS_BUSY          The module is busy with a reset operation
 * \retval STATUS_ERR_DENIED        The module is enabled
 */
enum status_code sdadc_init(
		struct sdadc_module *const module_inst,
		Sdadc *hw,
		struct sdadc_config *config)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(hw);
	Assert(config);

	/* Associate the software module instance with the hardware module */
	module_inst->hw = hw;

	/* Turn on the digital interface clock */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_SDADC);

	if (hw->CTRLA.reg & SDADC_CTRLA_SWRST) {
		/* We are in the middle of a reset. Abort. */
		return STATUS_BUSY;
	}

	if (hw->CTRLA.reg & SDADC_CTRLA_ENABLE) {
		/* Module must be disabled before initialization. Abort. */
		return STATUS_ERR_DENIED;
	}

	/* Store the selected reference for later use */
	module_inst->reference = config->reference;

#if SDADC_CALLBACK_MODE == true
	for (uint8_t i = 0; i < SDADC_CALLBACK_N; i++) {
		module_inst->callback[i] = NULL;
	};

	module_inst->registered_callback_mask = 0;
	module_inst->enabled_callback_mask = 0;
	module_inst->remaining_conversions = 0;
	module_inst->job_status = STATUS_OK;

	_sdadc_instances[0] = module_inst;

	if (config->event_action == SDADC_EVENT_ACTION_DISABLED &&
			!config->freerunning) {
		module_inst->software_trigger = true;
	} else {
		module_inst->software_trigger = false;
	}
#endif

	/* Write configuration to module */
	return _sdadc_set_config(module_inst, config);
}
Ejemplo n.º 7
0
/**
 * \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;
}
Ejemplo n.º 8
0
Archivo: i2s.c Proyecto: Realtime-7/asf
/**
 * \brief Initializes a hardware I2S module instance
 *
 * Enables the clock and initialize the I2S module.
 *
 * \param[in,out] module_inst  Pointer to the software module instance struct
 * \param[in]     hw           Pointer to the TCC hardware module
 *
 * \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_ERR_DENIED   Hardware module was already enabled
 */
enum status_code i2s_init(
		struct i2s_module *const module_inst,
		I2s *hw)
{
	Assert(module_inst);
	Assert(hw);

	/* Enable the user interface clock in the PM */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_I2S);

	/* Status check */
	uint32_t ctrla;
	ctrla = module_inst->hw->CTRLA.reg;
	if (ctrla & I2S_CTRLA_ENABLE) {
		if (ctrla & (I2S_CTRLA_SEREN1 |
				I2S_CTRLA_SEREN0 | I2S_CTRLA_CKEN1 | I2S_CTRLA_CKEN0)) {
			return STATUS_BUSY;
		} else {
			return STATUS_ERR_DENIED;
		}
	}

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

	/* Initialize serializers */
#if I2S_CALLBACK_MODE == true
	int i, j;
	for (i = 0; i < 2; i ++) {
		for (j = 0; j < I2S_SERIALIZER_CALLBACK_N; j ++) {
			module_inst->serializer[i].callback[j] = NULL;
		}
		module_inst->serializer[i].registered_callback_mask = 0;
		module_inst->serializer[i].enabled_callback_mask = 0;

		module_inst->serializer[i].job_buffer = NULL;
		module_inst->serializer[i].job_status = STATUS_OK;
		module_inst->serializer[i].requested_words = 0;
		module_inst->serializer[i].transferred_words = 0;

		module_inst->serializer[i].mode = I2S_SERIALIZER_RECEIVE;
		module_inst->serializer[i].data_size = I2S_DATA_SIZE_32BIT;
	}

	_i2s_instances[0] = module_inst;

	system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_I2S);
#endif

	return STATUS_OK;
}
Ejemplo n.º 9
0
Archivo: touch.c Proyecto: 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);
}
Ejemplo n.º 10
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();
}
Ejemplo n.º 11
0
Archivo: pac.c Proyecto: Realtime-7/asf
/**
 * \brief Lock a given peripheral's control registers.
 *
 * Locks a given peripheral's control registers, to deny write access to the
 * peripheral to prevent accidental changes to the module's configuration.
 *
 * \warning Locking an already locked peripheral will cause a hard fault
 *          exception, and terminate program execution.
 *
 * \param[in] peripheral_id  ID for the peripheral to be locked, sourced via the
 *                           \ref SYSTEM_PERIPHERAL_ID macro.
 * \param[in] key  Bitwise inverse of peripheral ID, used as key to
 *                 reduce the chance of accidental locking. See
 *                 \ref asfdoc_sam0_pac_bitwise_code.
 *
 * \return Status of the peripheral lock procedure.
 * \retval STATUS_OK                If the peripheral was successfully locked.
 * \retval STATUS_ERR_INVALID_ARG	If invalid argument(s) were supplied.
 */
__no_inline enum status_code system_peripheral_lock(
    const uint32_t peripheral_id,
    const uint32_t key)
{
    /* Bit to be set in desired register is given by bit 5:0 */
    uint8_t register_bit_pos = peripheral_id % 32;
    UNUSED(register_bit_pos);

    /* Value of which PAC register to use is given by bit 31:6 */
    uint8_t register_pos = peripheral_id / 32;

    /* Check if key is correct. */
    if (~peripheral_id != key) {
        Assert(false);
        return STATUS_ERR_INVALID_ARG;
    }

    switch (register_pos) {
#ifdef PAC0
    case 0:
        PAC0->WPSET.reg = (1 << register_bit_pos);
        break;
#endif
#ifdef PAC1
    case 1:
        PAC1->WPSET.reg = (1 << register_bit_pos);
        break;
#endif
#ifdef PAC2
    case 2:
        /* Turn on the digital interface clock */
        system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_PAC2);
        PAC2->WPSET.reg = (1 << register_bit_pos);
        break;
#endif
    default:
        Assert(false);
        return STATUS_ERR_INVALID_ARG;
    }

    return STATUS_OK;
}
Ejemplo n.º 12
0
/**
 * \brief Sets the up the NVM hardware module based on the configuration.
 *
 * Writes a given configuration of a NVM controller configuration to the
 * hardware module, and initializes the internal device struct
 *
 * \param[in] config    Configuration settings for the NVM controller
 *
 * \note The security bit must be cleared in order successfully use this
 *       function. This can only be done by a chip erase.
 *
 * \return Status of the configuration procedure.
 *
 * \retval STATUS_OK      If the initialization was a success
 * \retval STATUS_BUSY    If the module was busy when the operation was attempted
 * \retval STATUS_ERR_IO  If the security bit has been set, preventing the
 *                        EEPROM and/or auxiliary space configuration from being
 *                        altered
 */
enum status_code nvm_set_config(
		const struct nvm_config *const config)
{
	/* Sanity check argument */
	Assert(config);

	/* Get a pointer to the module hardware instance */
	Nvmctrl *const nvm_module = NVMCTRL;

	/* Turn on the digital interface clock */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBB, PM_APBBMASK_NVMCTRL);

	/* Clear error flags */
	nvm_module->STATUS.reg |= NVMCTRL_STATUS_MASK;

	/* Check if the module is busy */
	if (!nvm_is_ready()) {
		return STATUS_BUSY;
	}

	/* Writing configuration to the CTRLB register */
	nvm_module->CTRLB.reg =
			NVMCTRL_CTRLB_SLEEPPRM(config->sleep_power_mode) |
			((config->manual_page_write & 0x01) << NVMCTRL_CTRLB_MANW_Pos) |
			NVMCTRL_CTRLB_RWS(config->wait_states) |
			((config->disable_cache & 0x01) << NVMCTRL_CTRLB_CACHEDIS_Pos) |
			NVMCTRL_CTRLB_READMODE(config->cache_readmode);


	/* Initialize the internal device struct */
	_nvm_dev.page_size         = (8 << nvm_module->PARAM.bit.PSZ);
	_nvm_dev.number_of_pages   = nvm_module->PARAM.bit.NVMP;
	_nvm_dev.manual_page_write = config->manual_page_write;

	/* If the security bit is set, the auxiliary space cannot be written */
	if (nvm_module->STATUS.reg & NVMCTRL_STATUS_SB) {
		return STATUS_ERR_IO;
	}

	return STATUS_OK;
}
Ejemplo n.º 13
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();
	}
}
Ejemplo n.º 14
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);
}
Ejemplo n.º 15
0
/**
 * \brief Initializes a hardware TRNG module instance.
 *
 * Enables the clock and initializes the TRNG 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 TRNG hardware module
 * \param[in]     config       Pointer to the TRNG configuration options struct
 *
 * \return Status of the initialization procedure.
 *
 * \retval STATUS_OK           The module was initialized successfully
 */
enum status_code trng_init(
		struct trng_module *const module_inst,
		Trng *const hw,
		struct trng_config *const config)
{
	/* Sanity check arguments */
	Assert(module_inst);
	Assert(hw);
	Assert(config);

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

	/* Turn on the digital interface clock */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, MCLK_APBCMASK_TRNG);

#if TRNG_CALLBACK_MODE == true
	/* Initialize parameters */
	for (uint8_t i = 0; i < TRNG_CALLBACK_N; i++) {
		module_inst->callback[i] = NULL;
	}

	/* Initialize software flags*/
	module_inst->register_callback_mask = 0x00;
	module_inst->enable_callback_mask   = 0x00;
	module_inst->job_buffer             = NULL;
	module_inst->remaining_number       = 0;
	module_inst->job_status             = STATUS_OK;

	/* Register this instance for callbacks*/
	_trng_instance = module_inst;
#endif

	/* Write configuration to module */
	hw->CTRLA.reg = ((uint32_t)config->run_in_standby << TRNG_CTRLA_RUNSTDBY_Pos);

	return STATUS_OK;
}
Ejemplo n.º 16
0
/**
 * \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);
}
Ejemplo n.º 17
0
void serial_init(serial_t *obj, PinName tx, PinName rx)
{
    /* Sanity check arguments */
    MBED_ASSERT(obj);
    if (g_sys_init == 0) {
        system_init();
        g_sys_init = 1;
    }
    struct system_gclk_chan_config gclk_chan_conf;
    UARTName uart;
    uint32_t gclk_index;
    uint32_t pm_index;
    uint32_t sercom_index = 0;
    uint32_t muxsetting = 0;

    get_default_serial_values(obj);

    pSERIAL_S(obj)->pins[USART_TX_INDEX] = tx;
    pSERIAL_S(obj)->pins[USART_RX_INDEX] = rx;
    pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] = NC;
    pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] = NC;

    muxsetting = serial_find_mux_settings(obj);  // getting mux setting from pins
    sercom_index = pinmap_merge_sercom(tx, rx);  // same variable sercom_index reused for optimization
    if (sercom_index == (uint32_t)NC) {
        /*expecting a valid value for sercom index*/
        return;
    }
    sercom_index &= 0x0F;
    uart = (UARTName)pinmap_peripheral_sercom(NC, sercom_index);
    pUSART_S(obj) = (Sercom *)uart;

    /* Disable USART module */
    disable_usart(obj);

#if (SAML21) || (SAMC20) || (SAMC21)
#if (SAML21)
    if (sercom_index == 5) {
        pm_index     = MCLK_APBDMASK_SERCOM5_Pos;
        gclk_index   = SERCOM5_GCLK_ID_CORE;
    } else {
        pm_index     = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
        gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
    }
#else
    pm_index     = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
    gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
#endif
#else
    pm_index     = sercom_index + PM_APBCMASK_SERCOM0_Pos;
    gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;
#endif

    if (_USART(obj).CTRLA.reg & SERCOM_USART_CTRLA_SWRST) {
        return;  /* The module is busy resetting itself */
    }

    if (_USART(obj).CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) {
        return;    /* Check the module is enabled */
    }

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

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

    pSERIAL_S(obj)->mux_setting = muxsetting;
    /* Set configuration according to the config struct */
    usart_set_config_default(obj);

    struct system_pinmux_config pin_conf;
    pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
    pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
    pin_conf.powersave    = false;

    /* Configure the SERCOM pins according to the user configuration */
    for (uint8_t pad = 0; pad < 4; pad++) {
        uint32_t current_pin = pSERIAL_S(obj)->pins[pad];
        if (current_pin != (uint32_t)NC) {
            pin_conf.mux_position = pinmap_function_sercom((PinName)current_pin, sercom_index);
            if ((uint8_t)NC != pin_conf.mux_position) {
                system_pinmux_pin_set_config(current_pin, &pin_conf);
            }
        }
    }

    if (uart == STDIO_UART) {
        stdio_uart_inited = 1;
        memcpy(&stdio_uart, obj, sizeof(serial_t));
    }
    /* Wait until synchronization is complete */
    usart_syncing(obj);

    /* Enable USART module */
    enable_usart(obj);
}
Ejemplo n.º 18
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);
	uint32_t pm_index     = sercom_index + PM_APBCMASK_SERCOM0_Pos;
	uint32_t gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;

	/* Turn on module in PM */
	system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);

	/* Set up the GCLK for the module */



	system_gclk_chan_set_config(gclk_index, config->generator_source);
	system_gclk_chan_enable(gclk_index);
	_sercom_set_gclk_generator(config->generator_source);

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

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

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

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

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

	/* Set sercom module to operate in I2C master mode. */
	i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE_I2C_MASTER;

	/* Set config and return status. */
	return _i2c_master_set_config(module, config);
}
Ejemplo n.º 19
0
/** 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);
        }
    }
Ejemplo n.º 20
0
/**
 * \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;
}
Ejemplo n.º 21
0
/**
 * \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;
}
Ejemplo n.º 22
0
/**
 * \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);
        }
    }
Ejemplo n.º 23
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;
}
Ejemplo n.º 24
0
/**
 * \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);
		}
	}
Ejemplo n.º 25
0
/**
 * \brief Sets up the WDT hardware module based on the configuration.
 *
 * Writes a given configuration of a WDT configuration to the
 * hardware module, and initializes the internal device struct
 *
 * \param[in]  config  Pointer to the configuration struct
 *
 * \return Status of the configuration procedure.
 *
 * \retval STATUS_OK     If the module was configured correctly
 * \retval STATUS_ERR_INVALID_ARG   If invalid argument(s) were supplied
 * \retval STATUS_ERR_IO  If the Watchdog module is locked to be always on
 */
enum status_code wdt_set_config(
		const struct wdt_conf *const config)
{
	/* Sanity check arguments */
	Assert(config);

	Wdt *const WDT_module = WDT;

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

	/* Check of the Watchdog has been locked to be always on, if so, abort */
	if (wdt_is_locked()) {
		return STATUS_ERR_IO;
	}

	/* Check for an invalid timeout period, abort if found */
	if (config->timeout_period == WDT_PERIOD_NONE) {
		return STATUS_ERR_INVALID_ARG;
	}

	/* Make sure the Window and Early Warning periods are not more than the
	 * reset period, abort if either is invalid */
	if ((config->timeout_period < config->window_period) ||
			(config->timeout_period < config->early_warning_period)) {
		return STATUS_ERR_INVALID_ARG;
	}

	/* Disable the Watchdog module */
	WDT_module->CTRL.reg &= ~WDT_CTRL_ENABLE;

	if(config->enable == false) {
		return STATUS_OK;
	}

	/* Configure GCLK channel and enable clock */
	struct system_gclk_chan_config gclk_chan_conf;
	gclk_chan_conf.source_generator = config->clock_source;
	system_gclk_chan_set_config(WDT_GCLK_ID, &gclk_chan_conf);
	system_gclk_chan_enable(WDT_GCLK_ID);
	if (config->always_on) {
		system_gclk_chan_lock(WDT_GCLK_ID);
	}

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

	uint32_t new_config = 0;

	/* Update the timeout period value with the requested period */
	new_config |= (config->timeout_period - 1) << WDT_CONFIG_PER_Pos;

	/* Check if the user has requested a reset window period */
	if (config->window_period != WDT_PERIOD_NONE) {
		WDT_module->CTRL.reg |= WDT_CTRL_WEN;

		/* Update and enable the timeout period value */
		new_config |= (config->window_period - 1) << WDT_CONFIG_WINDOW_Pos;
	} else {
		/* Ensure the window enable control flag is cleared */
		WDT_module->CTRL.reg &= ~WDT_CTRL_WEN;
	}

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

	/* Write the new Watchdog configuration */
	WDT_module->CONFIG.reg = new_config;

	/* Check if the user has requested an early warning period */
	if (config->early_warning_period != WDT_PERIOD_NONE) {
		while (wdt_is_syncing()) {
			/* Wait for all hardware modules to complete synchronization */
		}

		/* Set the Early Warning period */
		WDT_module->EWCTRL.reg
			= (config->early_warning_period - 1) << WDT_EWCTRL_EWOFFSET_Pos;
	}

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

	/* Either enable or lock-enable the Watchdog timer depending on the user
	 * settings */
	if (config->always_on) {
		WDT_module->CTRL.reg |= WDT_CTRL_ALWAYSON;
	} else {
		WDT_module->CTRL.reg |= WDT_CTRL_ENABLE;
	}

	return STATUS_OK;
}