Modified version of the mbed library for use with the Nucleo boards.
Dependents: EEPROMWrite Full-Project
Fork of mbed-src by
Diff: targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/extint/extint_sam_d_r/extint.c
- Revision:
- 613:bc40b8d2aec4
- Parent:
- 612:fba1c7dc54c0
- Child:
- 614:9d86c2ae5de0
--- a/targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/extint/extint_sam_d_r/extint.c Tue Aug 18 15:00:09 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,381 +0,0 @@ -#include <system.h> -#include <system_interrupt.h> -#include <extint.h> -#include <conf_extint.h> - -#if !defined(EXTINT_CLOCK_SOURCE) || defined(__DOXYGEN__) -# warning EXTINT_CLOCK_SOURCE is not defined, assuming GCLK_GENERATOR_0. - -/** Configuration option, setting the EIC clock source which can be used for - * EIC edge detection or filtering. This option may be overridden in the module - * configuration header file \c conf_extint.h. - */ -# define EXTINT_CLOCK_SOURCE GCLK_GENERATOR_0 -#endif - -/** - * \internal - * Internal driver device instance struct. - */ -struct _extint_module _extint_dev; - -/** - * \brief Determin if the general clock is required - * - * \param[in] filter_input_signal Filter the raw input signal to prevent noise - * \param[in] detection_criteria Edge detection mode to use (\ref extint_detect) - */ -#define _extint_is_gclk_required(filter_input_signal, detection_criteria) \ - ((filter_input_signal) ? true : (\ - (EXTINT_DETECT_RISING == (detection_criteria)) ? true : (\ - (EXTINT_DETECT_FALLING == (detection_criteria)) ? true : (\ - (EXTINT_DETECT_BOTH == (detection_criteria)) ? true : false)))) - -static void _extint_enable(void); -static void _extint_disable(void); - -/** - * \brief Determines if the hardware module(s) are currently synchronizing to the bus. - * - * Checks to see if the underlying hardware peripheral module(s) are currently - * synchronizing across multiple clock domains to the hardware bus, This - * function can be used to delay further operations on a module until such time - * that it is ready, to prevent blocking delays for synchronization in the - * user application. - * - * \return Synchronization status of the underlying hardware module(s). - * - * \retval true If the module synchronization is ongoing - * \retval false If the module has completed synchronization - */ -static inline bool extint_is_syncing(void) -{ - Eic *const eics[EIC_INST_NUM] = EIC_INSTS; - - for (uint32_t i = 0; i < EIC_INST_NUM; i++) { - if (eics[i]->STATUS.reg & EIC_STATUS_SYNCBUSY) { - return true; - } - } - return false; -} -/** - * \internal - * \brief Initializes and enables the External Interrupt driver. - * - * Enable the clocks used by External Interrupt driver. - * - * Resets the External Interrupt driver, resetting all hardware - * module registers to their power-on defaults, then enable it for further use. - * - * Reset the callback list if callback mode is used. - * - * This function must be called before attempting to use any NMI or standard - * external interrupt channel functions. - * - * \note When SYSTEM module is used, this function will be invoked by - * \ref system_init() automatically if the module is included. - */ -void _system_extint_init(void); -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, PM_APBAMASK_EIC); - - /* 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); - - /* Reset all EIC hardware modules. */ - for (uint32_t i = 0; i < EIC_INST_NUM; i++) { - eics[i]->CTRL.reg |= EIC_CTRL_SWRST; - } - - while (extint_is_syncing()) { - /* Wait for all hardware modules to complete synchronization */ - } - - /* Reset the software module */ -// TEMP: Commented by V -//#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(); -} - -/** - * \internal - * \brief Enables the External Interrupt driver. - * - * Enables EIC modules. - * Registered callback list will not be affected if callback mode is used. - */ -void _extint_enable(void) -{ - Eic *const eics[EIC_INST_NUM] = EIC_INSTS; - - /* Enable all EIC hardware modules. */ - for (uint32_t i = 0; i < EIC_INST_NUM; i++) { - eics[i]->CTRL.reg |= EIC_CTRL_ENABLE; - } - - while (extint_is_syncing()) { - /* Wait for all hardware modules to complete synchronization */ - } -} - -/** - * \internal - * \brief Disables the External Interrupt driver. - * - * Disables EIC modules that were previously started via a call to - * \ref _extint_enable(). - * Registered callback list will not be affected if callback mode is used. - */ -void _extint_disable(void) -{ - Eic *const eics[EIC_INST_NUM] = EIC_INSTS; - - /* Disable all EIC hardware modules. */ - for (uint32_t i = 0; i < EIC_INST_NUM; i++) { - eics[i]->CTRL.reg &= ~EIC_CTRL_ENABLE; - } - - while (extint_is_syncing()) { - /* Wait for all hardware modules to complete synchronization */ - } -} - -/** - * \brief Initializes an External Interrupt channel configuration structure to defaults. - * - * Initializes a given External Interrupt channel configuration structure to a - * set of known default values. This function should be called on all new - * instances of these configuration structures before being modified by the - * user application. - * - * The default configuration is as follows: - * \li Wake the device if an edge detection occurs whilst in sleep - * \li Input filtering disabled - * \li Internal pull-up enabled - * \li Detect falling edges of a signal - * - * \param[out] config Configuration structure to initialize to default values - */ -void extint_chan_get_config_defaults( - struct extint_chan_conf *const config) -{ - /* Sanity check arguments */ - Assert(config); - - /* Default configuration values */ - config->gpio_pin = 0; - config->gpio_pin_mux = 0; - config->gpio_pin_pull = EXTINT_PULL_UP; - config->wake_if_sleeping = true; - config->filter_input_signal = false; - config->detection_criteria = EXTINT_DETECT_FALLING; -} - -/** - * \brief Writes an External Interrupt channel configuration to the hardware module. - * - * Writes out a given configuration of an External Interrupt channel - * configuration to the hardware module. If the channel is already configured, - * the new configuration will replace the existing one. - * - * \param[in] channel External Interrupt channel to configure - * \param[in] config Configuration settings for the channel - - */ -void extint_chan_set_config( - const uint8_t channel, - const struct extint_chan_conf *const config) -{ - /* Sanity check arguments */ - Assert(config); - /* Sanity check clock requirements */ - Assert(!(!system_gclk_gen_is_enabled(EXTINT_CLOCK_SOURCE) && - _extint_is_gclk_required(config->filter_input_signal, - config->detection_criteria))); - - struct system_pinmux_config pinmux_config; - system_pinmux_get_config_defaults(&pinmux_config); - - pinmux_config.mux_position = config->gpio_pin_mux; - pinmux_config.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; - pinmux_config.input_pull = (enum system_pinmux_pin_pull)config->gpio_pin_pull; - system_pinmux_pin_set_config(config->gpio_pin, &pinmux_config); - - /* Get a pointer to the module hardware instance */ - Eic *const EIC_module = _extint_get_eic_from_channel(channel); - - uint32_t config_pos = (4 * (channel % 8)); - uint32_t new_config; - - /* Determine the channel's new edge detection configuration */ - new_config = (config->detection_criteria << EIC_CONFIG_SENSE0_Pos); - - /* Enable the hardware signal filter if requested in the config */ - if (config->filter_input_signal) { - new_config |= EIC_CONFIG_FILTEN0; - } - - /* Clear the existing and set the new channel configuration */ - EIC_module->CONFIG[channel / 8].reg - = (EIC_module->CONFIG[channel / 8].reg & - ~((EIC_CONFIG_SENSE0_Msk | EIC_CONFIG_FILTEN0) << config_pos)) | - (new_config << config_pos); - - /* Set the channel's new wake up mode setting */ - if (config->wake_if_sleeping) { - EIC_module->WAKEUP.reg |= (1UL << channel); - } else { - EIC_module->WAKEUP.reg &= ~(1UL << channel); - } -} - -/** - * \brief Writes 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; -} - -/** - * \brief Enables an External Interrupt event output. - * - * Enables one or more output events from the External Interrupt module. See - * \ref extint_events "here" for a list of events this module supports. - * - * \note Events cannot be altered while the module is enabled. - * - * \param[in] events Struct containing flags of events to enable - */ -void extint_enable_events( - struct extint_events *const events) -{ - /* Sanity check arguments */ - Assert(events); - - /* Array of available EICs. */ - Eic *const eics[EIC_INST_NUM] = EIC_INSTS; - - /* Update the event control register for each physical EIC instance */ - for (uint32_t i = 0; i < EIC_INST_NUM; i++) { - uint32_t event_mask = 0; - - /* Create an enable mask for the current EIC module */ - for (uint32_t j = 0; j < 32; j++) { - if (events->generate_event_on_detect[(32 * i) + j]) { - event_mask |= (1UL << j); - } - } - - /* Enable the masked events */ - eics[i]->EVCTRL.reg |= event_mask; - } -} - -/** - * \brief Disables an External Interrupt event output. - * - * Disables one or more output events from the External Interrupt module. See - * \ref extint_events "here" for a list of events this module supports. - * - * \note Events cannot be altered while the module is enabled. - * - * \param[in] events Struct containing flags of events to disable - */ -void extint_disable_events( - struct extint_events *const events) -{ - /* Sanity check arguments */ - Assert(events); - - /* Array of available EICs. */ - Eic *const eics[EIC_INST_NUM] = EIC_INSTS; - - /* Update the event control register for each physical EIC instance */ - for (uint32_t i = 0; i < EIC_INST_NUM; i++) { - uint32_t event_mask = 0; - - /* Create a disable mask for the current EIC module */ - for (uint32_t j = 0; j < 32; j++) { - if (events->generate_event_on_detect[(32 * i) + j]) { - event_mask |= (1UL << j); - } - } - - /* Disable the masked events */ - eics[i]->EVCTRL.reg &= ~event_mask; - } -}