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 }
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; }
/** * \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; }
/** * \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; }
/** * \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; }
void serial_baud(serial_t *obj, int baudrate) { /* Sanity check arguments */ MBED_ASSERT(obj); MBED_ASSERT((baudrate == 110) || (baudrate == 150) || (baudrate == 300) || (baudrate == 1200) || (baudrate == 2400) || (baudrate == 4800) || (baudrate == 9600) || (baudrate == 19200) || (baudrate == 38400) || (baudrate == 57600) || (baudrate == 115200) || (baudrate == 230400) || (baudrate == 460800) || (baudrate == 921600) ); struct system_gclk_chan_config gclk_chan_conf; uint32_t gclk_index; uint16_t baud = 0; uint32_t sercom_index = 0; enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; pSERIAL_S(obj)->baudrate = baudrate; disable_usart(obj); sercom_index = _sercom_get_sercom_inst_index(pUSART_S(obj)); #if (SAML21) || (SAMC20) || (SAMC21) #if (SAML21) if (sercom_index == 5) { gclk_index = SERCOM5_GCLK_ID_CORE; } else { gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; } #else gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif #else gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif gclk_chan_conf.source_generator = GCLK_GENERATOR_0; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(GCLK_GENERATOR_0, false); /* Get baud value from mode and clock */ _sercom_get_async_baud_val(pSERIAL_S(obj)->baudrate, system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num); /* Wait until synchronization is complete */ usart_syncing(obj); /*Set baud val */ _USART(obj).BAUD.reg = baud; /* Wait until synchronization is complete */ usart_syncing(obj); enable_usart(obj); }
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(); }
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); }
/** Configures and starts the DFLL in closed loop mode with the given reference * generator. * * \param[in] source_generator Reference generator to use for the DFLL */ static void init_dfll( const enum system_clock_source source_generator) { struct system_gclk_gen_config cpu_clock_conf; system_gclk_gen_get_config_defaults(&cpu_clock_conf); cpu_clock_conf.output_enable = ENABLE_CPU_CLOCK_OUT; /* Switch to OSC8M/OSC16M while the DFLL is being reconfigured */ #if SAML21 cpu_clock_conf.source_clock = SYSTEM_CLOCK_SOURCE_OSC16M; #else cpu_clock_conf.source_clock = SYSTEM_CLOCK_SOURCE_OSC8M; #endif system_gclk_gen_set_config(GCLK_GENERATOR_0, &cpu_clock_conf); /* Turn off DFLL before adjusting its configuration */ system_clock_source_disable(SYSTEM_CLOCK_SOURCE_DFLL); /* Configure DFLL reference clock, use raw register write to * force-configure the channel even if the currently selected generator * clock has failed */ #if SAML21 GCLK->PCHCTRL[SYSCTRL_GCLK_ID_DFLL48].reg = GCLK_PCHCTRL_GEN(source_generator); #else GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SYSCTRL_GCLK_ID_DFLL48) | GCLK_CLKCTRL_GEN(source_generator); #endif system_gclk_chan_enable(SYSCTRL_GCLK_ID_DFLL48); /* Configure DFLL */ struct system_clock_source_dfll_config config_dfll; system_clock_source_dfll_get_config_defaults(&config_dfll); config_dfll.on_demand = false; config_dfll.loop_mode = SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED; config_dfll.multiply_factor = (48000000UL / system_gclk_chan_get_hz(SYSCTRL_GCLK_ID_DFLL48)); system_clock_source_dfll_set_config(&config_dfll); /* Restart DFLL */ system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DFLL); while (system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DFLL) == false) { /* Wait for DFLL to be stable before switch back */ } /* Switch back to the DFLL as the CPU clock source */ cpu_clock_conf.source_clock = SYSTEM_CLOCK_SOURCE_DFLL; system_gclk_gen_set_config(GCLK_GENERATOR_0, &cpu_clock_conf); };
/** * \brief Writes an External Interrupt NMI channel configuration to the hardware module. * * Writes out a given configuration of an External Interrupt NMI channel * configuration to the hardware module. If the channel is already configured, * the new configuration will replace the existing one. * * \param[in] nmi_channel External Interrupt NMI channel to configure * \param[in] config Configuration settings for the channel * * \returns Status code indicating the success or failure of the request. * \retval STATUS_OK Configuration succeeded * \retval STATUS_ERR_PIN_MUX_INVALID An invalid pinmux value was supplied * \retval STATUS_ERR_BAD_FORMAT An invalid detection mode was requested */ enum status_code extint_nmi_set_config( const uint8_t nmi_channel, const struct extint_nmi_conf *const config) { /* Sanity check arguments */ Assert(config); /* Sanity check clock requirements */ Assert(!(!system_gclk_gen_is_enabled(EXTINT_CLOCK_SOURCE) && _extint_is_gclk_required(config->filter_input_signal, config->detection_criteria))); struct system_pinmux_config pinmux_config; system_pinmux_get_config_defaults(&pinmux_config); pinmux_config.mux_position = config->gpio_pin_mux; pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pinmux_config.input_pull = SYSTEM_PINMUX_PIN_PULL_UP; pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->gpio_pin_pull; system_pinmux_pin_set_config(config->gpio_pin, &pinmux_config); /* Get a pointer to the module hardware instance */ Eic *const EIC_module = _extint_get_eic_from_channel(nmi_channel); uint32_t new_config; /* Determine the NMI's new edge detection configuration */ new_config = (config->detection_criteria << EIC_NMICTRL_NMISENSE_Pos); /* Enable the hardware signal filter if requested in the config */ if (config->filter_input_signal) { new_config |= EIC_NMICTRL_NMIFILTEN; } /* Disable EIC and general clock to configure NMI */ _extint_disable(); system_gclk_chan_disable(EIC_GCLK_ID); EIC_module->NMICTRL.reg = new_config; /* Enable the general clock and EIC after configure NMI */ system_gclk_chan_enable(EIC_GCLK_ID); _extint_enable(); return STATUS_OK; }
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(); } }
/** * \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); }
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; }
/** 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); } }
/** * \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; }
/** * \brief Initializes the device * * Initializes the USART device based on the setting specified in the * configuration struct. * * \param[out] module Pointer to USART device * \param[in] hw Pointer to USART hardware instance * \param[in] config Pointer to configuration struct * * \return Status of the initialization. * * \retval STATUS_OK The initialization was successful * \retval STATUS_BUSY The USART module is busy * resetting * \retval STATUS_ERR_DENIED The USART have not been disabled in * advance of initialization * \retval STATUS_ERR_INVALID_ARG The configuration struct contains * invalid configuration * \retval STATUS_ERR_ALREADY_INITIALIZED The SERCOM instance has already been * initialized with different clock * configuration * \retval STATUS_ERR_BAUD_UNAVAILABLE The BAUD rate given by the * configuration * struct cannot be reached with * the current clock configuration */ enum status_code usart_init( struct usart_module *const module, Sercom *const hw, const struct usart_config *const config) { /* Sanity check arguments */ Assert(module); Assert(hw); Assert(config); enum status_code status_code = STATUS_OK; /* Assign module pointer to software instance struct */ module->hw = hw; /* Get a pointer to the hardware module instance */ SercomUsart *const usart_hw = &(module->hw->USART); uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); #if (SAML21) uint32_t pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; #else uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; #endif uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) { /* The module is busy resetting itself */ return STATUS_BUSY; } if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) { /* Check the module is enabled */ return STATUS_ERR_DENIED; } /* Turn on module in PM */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); /* Set up the GCLK for the module */ struct system_gclk_chan_config gclk_chan_conf; system_gclk_chan_get_config_defaults(&gclk_chan_conf); gclk_chan_conf.source_generator = config->generator_source; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(config->generator_source, false); /* Set character size */ module->character_size = config->character_size; /* Set transmitter and receiver status */ module->receiver_enabled = config->receiver_enable; module->transmitter_enabled = config->transmitter_enable; #ifdef FEATURE_USART_LIN_SLAVE module->lin_slave_enabled = config->lin_slave_enable; #endif #ifdef FEATURE_USART_START_FRAME_DECTION module->start_frame_detection_enabled = config->start_frame_detection_enable; #endif /* Set configuration according to the config struct */ status_code = _usart_set_config(module, config); if(status_code != STATUS_OK) { return status_code; } struct system_pinmux_config pin_conf; system_pinmux_get_config_defaults(&pin_conf); pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; uint32_t pad_pinmuxes[] = { config->pinmux_pad0, config->pinmux_pad1, config->pinmux_pad2, config->pinmux_pad3 }; /* Configure the SERCOM pins according to the user configuration */ for (uint8_t pad = 0; pad < 4; pad++) { uint32_t current_pinmux = pad_pinmuxes[pad]; if (current_pinmux == PINMUX_DEFAULT) { current_pinmux = _sercom_get_default_pad(hw, pad); } if (current_pinmux != PINMUX_UNUSED) { pin_conf.mux_position = current_pinmux & 0xFFFF; system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); } }
/** * \brief 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; }
/** * \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); }
/** * \brief Writes an External Interrupt NMI channel configuration to the hardware module. * * Writes out a given configuration of an External Interrupt NMI channel * configuration to the hardware module. If the channel is already configured, * the new configuration will replace the existing one. * * \param[in] nmi_channel External Interrupt NMI channel to configure * \param[in] config Configuration settings for the channel * * \returns Status code indicating the success or failure of the request. * \retval STATUS_OK Configuration succeeded * \retval STATUS_ERR_PIN_MUX_INVALID An invalid pin mux value was supplied * \retval STATUS_ERR_BAD_FORMAT An invalid detection mode was requested */ enum status_code extint_nmi_set_config( const uint8_t nmi_channel, const struct extint_nmi_conf *const config) { /* Sanity check arguments */ Assert(config); /* Sanity check clock requirements */ Assert(!(!system_gclk_gen_is_enabled(EXTINT_CLOCK_SOURCE) && _extint_is_gclk_required(config->filter_input_signal, config->detection_criteria))); struct system_pinmux_config pinmux_config; system_pinmux_get_config_defaults(&pinmux_config); pinmux_config.mux_position = config->gpio_pin_mux; pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; pinmux_config.input_pull = SYSTEM_PINMUX_PIN_PULL_UP; pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->gpio_pin_pull; system_pinmux_pin_set_config(config->gpio_pin, &pinmux_config); /* Get a pointer to the module hardware instance */ Eic *const EIC_module = _extint_get_eic_from_channel(nmi_channel); uint32_t new_config; /* Determine the NMI's new edge detection configuration */ new_config = (config->detection_criteria << EIC_NMICTRL_NMISENSE_Pos); /* Enable the hardware signal filter if requested in the config */ if (config->filter_input_signal) { new_config |= EIC_NMICTRL_NMIFILTEN; } #if (SAML21XXXB) || (SAML22) || (SAMC21) || (SAMR30) /* Enable asynchronous edge detection if requested in the config */ if (config->enable_async_edge_detection) { new_config |= EIC_NMICTRL_NMIASYNCH; } #endif /* Disable EIC and general clock to configure NMI */ _extint_disable(); #if(EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) system_gclk_chan_disable(EIC_GCLK_ID); #else Eic *const eics[EIC_INST_NUM] = EIC_INSTS; for (uint32_t i = 0; i < EIC_INST_NUM; i++){ eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_GCLK; system_gclk_chan_disable(EIC_GCLK_ID); } #endif EIC_module->NMICTRL.reg = new_config; /* Enable the EIC clock and EIC after configure NMI */ #if(EXTINT_CLOCK_SELECTION == EXTINT_CLK_GCLK) system_gclk_chan_enable(EIC_GCLK_ID); #else for (uint32_t i = 0; i < EIC_INST_NUM; i++){ eics[i]->CTRLA.bit.CKSEL = EXTINT_CLK_ULP32K; } #endif _extint_enable(); return STATUS_OK; }
/** * \brief 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; }
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); }
/** * \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); } }
/** * \brief Initialize hardware and driver instance * * This function configures the clock system for the specified SERCOM module, * sets up the related pins and their MUX, initializes the SERCOM in SPI master * mode, and prepares the driver instance for operation. * * \pre \ref system_init() must have been called prior to this function. * * The SERCOM SPI module is left disabled after initialization, and must be * enabled with \ref spi_master_vec_enable() before a transfer can be done. * * \param[out] module Driver instance to initialize. * \param[in,out] sercom SERCOM module to initialize and associate driver * instance with. * \param[in] config Driver configuration to use. * * \return Status of initialization. * \retval STATUS_OK if initialization succeeded. * \retval STATUS_ERR_INVALID_ARG if driver has been misconfigured. */ enum status_code spi_master_vec_init(struct spi_master_vec_module *const module, Sercom *const sercom, const struct spi_master_vec_config *const config) { Assert(module); Assert(sercom); Assert(config); enum status_code status; SercomSpi *const spi_hw = &(sercom->SPI); struct system_gclk_chan_config gclk_chan_conf; uint16_t tmp_baud; uint32_t sercom_index = _sercom_get_sercom_inst_index((Sercom *)spi_hw); #if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) uint32_t pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; #else uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; #endif uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; uint32_t gclk_hz; module->sercom = sercom; /* Enable clock for the module interface */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); /* Set up the GCLK for the module */ system_gclk_chan_get_config_defaults(&gclk_chan_conf); gclk_chan_conf.source_generator = config->gclk_generator; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(config->gclk_generator, false); _spi_master_vec_wait_for_sync(spi_hw); /* Set up the SERCOM SPI module as master */ spi_hw->CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3); spi_hw->CTRLA.reg |= (uint32_t)config->mux_setting | config->transfer_mode | config->data_order | ((config->run_in_standby || system_is_debugger_present()) ? SERCOM_SPI_CTRLA_RUNSTDBY : 0); /* Get baud value from configured baudrate and internal clock rate */ gclk_hz = system_gclk_chan_get_hz(gclk_index); status = _sercom_get_sync_baud_val(config->baudrate, gclk_hz, &tmp_baud); if (status != STATUS_OK) { /* Baud rate calculation error! */ return STATUS_ERR_INVALID_ARG; } spi_hw->BAUD.reg = (uint8_t)tmp_baud; /* Configure the pin multiplexers */ _spi_master_vec_pinmux_helper(config->pinmux_pad0, sercom, 0); _spi_master_vec_pinmux_helper(config->pinmux_pad3, sercom, 3); /* SERCOM PAD1 and PAD2 are used for slave SS. * This is a SPI master driver, so control of slave SS must be left to * the PORT module, i.e., peripheral MUX should not be set for that pin. * DOPO controls which PAD is used for slave SS: * If DOPO is odd, SERCOM_PAD1 is SS: SERCOM_PAD2 can be MUXed. * If DOPO is even, SERCOM_PAD2 is SS: SERCOM_PAD1 can be MUXed. */ if (config->mux_setting & (1 << SERCOM_SPI_CTRLA_DOPO_Pos)) { _spi_master_vec_pinmux_helper(config->pinmux_pad2, sercom, 2); } else { _spi_master_vec_pinmux_helper(config->pinmux_pad1, sercom, 1); } /* Initialize our instance and register interrupt handler + data */ module->rx_bufdesc_ptr = NULL; module->tx_bufdesc_ptr = NULL; module->direction = SPI_MASTER_VEC_DIRECTION_IDLE; module->status = STATUS_OK; #ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE(module->busy_semaphore); #endif _sercom_set_handler(sercom_index, _spi_master_vec_int_handler); _sercom_instances[sercom_index] = module; return STATUS_OK; }
/** * \brief Initializes the requested I<SUP>2</SUP>C hardware module * * Initializes the SERCOM I<SUP>2</SUP>C slave device requested and sets the provided * software module struct. Run this function before any further use of * the driver. * * \param[out] module Pointer to software module struct * \param[in] hw Pointer to the hardware instance * \param[in] config Pointer to the configuration struct * * \return Status of initialization. * \retval STATUS_OK Module initiated correctly * \retval STATUS_ERR_DENIED If module is enabled * \retval STATUS_BUSY If module is busy resetting * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than * previously set */ enum status_code i2c_slave_init( struct i2c_slave_module *const module, Sercom *const hw, const struct i2c_slave_config *const config) { /* Sanity check arguments */ Assert(module); Assert(hw); Assert(config); /* Initialize software module */ module->hw = hw; SercomI2cs *const i2c_hw = &(module->hw->I2CS); /* Check if module is enabled */ if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_ENABLE) { return STATUS_ERR_DENIED; } /* Check if reset is in progress */ if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_SWRST) { return STATUS_BUSY; } uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); uint32_t pm_index, gclk_index; #if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) #if (SAML21) if (sercom_index == 5) { pm_index = MCLK_APBDMASK_SERCOM5_Pos; gclk_index = SERCOM5_GCLK_ID_CORE; } else { pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; } #else pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif #else pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif /* Turn on module in PM */ #if (SAML21) if (sercom_index == 5) { system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index); } else { system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); } #else system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); #endif /* Set up the GCLK for the module */ struct system_gclk_chan_config gclk_chan_conf; system_gclk_chan_get_config_defaults(&gclk_chan_conf); gclk_chan_conf.source_generator = config->generator_source; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(config->generator_source, false); #if I2C_SLAVE_CALLBACK_MODE == true /* Get sercom instance index */ uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw); /* Save software module in interrupt handler */ _sercom_set_handler(instance_index, _i2c_slave_interrupt_handler); /* Save software module */ _sercom_instances[instance_index] = module; /* Initialize values in module */ module->registered_callback = 0; module->enabled_callback = 0; module->buffer_length = 0; module->nack_on_address = config->enable_nack_on_address; #endif /* Set SERCOM module to operate in I2C slave mode */ i2c_hw->CTRLA.reg = SERCOM_I2CS_CTRLA_MODE(0x4); /* Set config and return status */ return _i2c_slave_set_config(module, config); }
/** * \internal 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; }