|
@@ -0,0 +1,1802 @@
|
|
|
+/***********************************************************************************************************************
|
|
|
+ * Copyright [2020-2021] Renesas Electronics Corporation and/or its affiliates. All Rights Reserved.
|
|
|
+ *
|
|
|
+ * This software and documentation are supplied by Renesas Electronics America Inc. and may only be used with products
|
|
|
+ * of Renesas Electronics Corp. and its affiliates ("Renesas"). No other uses are authorized. Renesas products are
|
|
|
+ * sold pursuant to Renesas terms and conditions of sale. Purchasers are solely responsible for the selection and use
|
|
|
+ * of Renesas products and Renesas assumes no liability. No license, express or implied, to any intellectual property
|
|
|
+ * right is granted by Renesas. This software is protected under all applicable laws, including copyright laws. Renesas
|
|
|
+ * reserves the right to change or discontinue this software and/or this documentation. THE SOFTWARE AND DOCUMENTATION
|
|
|
+ * IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND TO THE FULLEST EXTENT
|
|
|
+ * PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY, INCLUDING WARRANTIES
|
|
|
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE SOFTWARE OR
|
|
|
+ * DOCUMENTATION. RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH. TO THE MAXIMUM
|
|
|
+ * EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR DOCUMENTATION
|
|
|
+ * (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER, INCLUDING,
|
|
|
+ * WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY LOST PROFITS,
|
|
|
+ * OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE POSSIBILITY
|
|
|
+ * OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+/***********************************************************************************************************************
|
|
|
+ * Includes <System Includes> , "Project Includes"
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+#include "bsp_api.h"
|
|
|
+
|
|
|
+/* Configuration for this package. */
|
|
|
+#include "r_adc_cfg.h"
|
|
|
+
|
|
|
+/* Private header file for this package. */
|
|
|
+#include "r_adc.h"
|
|
|
+
|
|
|
+/**********************************************************************************************************************
|
|
|
+ * Macro definitions
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+#define ADC_PRV_USEC_PER_SEC (1000000U)
|
|
|
+#define ADC_PRV_MIN_ADCLK_HZ (1000000U)
|
|
|
+#define ADC_MAX_CALIBRATION_CLOCKS_MILLISECS (780U)
|
|
|
+
|
|
|
+#define ADC_PRV_HZ_PER_KHZ (1000U)
|
|
|
+
|
|
|
+#define ADC_SHIFT_LEFT_ALIGNED_32_BIT (16U)
|
|
|
+
|
|
|
+#define ADC_OPEN (0x52414443U)
|
|
|
+
|
|
|
+#define ADC_ADADC_AVEE_BIT (0x80U)
|
|
|
+
|
|
|
+/* Sample and hold bypass applies to these channels. */
|
|
|
+#define ADC_MASK_SAMPLE_HOLD_BYPASS_CHANNELS (0x7U)
|
|
|
+
|
|
|
+/* Sample and hold bypass starts at bit 8. */
|
|
|
+#define ADC_MASK_SAMPLE_HOLD_BYPASS_SHIFT (8U)
|
|
|
+
|
|
|
+/* Value for ADPGADCR0 to disable PGA */
|
|
|
+#define ADC_ADPGADCR0_DISABLE_PGA (0x0000)
|
|
|
+
|
|
|
+/* Value for ADPGACR to disable PGA */
|
|
|
+#define ADC_ADPGACR_DISABLE_PGA (0x9999)
|
|
|
+
|
|
|
+/* Position of ADCALEXE to start calibration-CALEXE bit */
|
|
|
+#define ADC_ADCALEXE_SET_CALEXE (0x80U)
|
|
|
+
|
|
|
+/* Position of ADCALEXE calibration-CALMON bit */
|
|
|
+#define ADC_ADCALEXE_CALIBRATION_STATUS (0x40U)
|
|
|
+
|
|
|
+/* Value of ADICR with interrupt at end of calibration */
|
|
|
+#define ADC_ADICR_CALIBRATION_INTERRUPT_ENABLED (0x03U)
|
|
|
+
|
|
|
+/* Value of ADICR with no interrupt at end of calibration */
|
|
|
+#define ADC_ADICR_CALIBRATION_INTERRUPT_DISABLED (0x00U)
|
|
|
+
|
|
|
+/* Stabilization time when BGR is enabled */
|
|
|
+#define ADC_BGR_STABILIZATION_DELAY_US (150U)
|
|
|
+
|
|
|
+/* Bit set in adc_vref_control if the internal voltage reference is used for VREFH. */
|
|
|
+#define ADC_PRV_ADHVREFCNT_VREF_INTERNAL_BIT_1 (1U << 1)
|
|
|
+
|
|
|
+#define ADC_PRV_ADCSR_ADST_TRGE_MASK (R_ADC0_ADCSR_ADST_Msk | R_ADC0_ADCSR_TRGE_Msk)
|
|
|
+#define ADC_PRV_ADCSR_CLEAR_ADST_TRGE (~ADC_PRV_ADCSR_ADST_TRGE_MASK)
|
|
|
+
|
|
|
+#define ADC_PRV_TSCR_TSN_ENABLE (R_TSN_CTRL_TSCR_TSEN_Msk | R_TSN_CTRL_TSCR_TSOE_Msk)
|
|
|
+
|
|
|
+#define ADC_PRV_ADBUF_ENABLED (1U)
|
|
|
+
|
|
|
+/***********************************************************************************************************************
|
|
|
+ * Typedef definitions
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+/** Defines the registers settings for the ADC synchronous ELC trigger. */
|
|
|
+typedef enum e_adc_elc_trigger
|
|
|
+{
|
|
|
+ ADC_ELC_TRIGGER_EXTERNAL = (0x00U),
|
|
|
+ ADC_ELC_TRIGGER = (0x09U),
|
|
|
+ ADC_ELC_TRIGGER_GROUP_B = (0x0AU),
|
|
|
+ ADC_ELC_TRIGGER_BOTH = (0x0BU),
|
|
|
+ ADC_ELC_TRIGGER_DISABLED = (0x3FU)
|
|
|
+} adc_elc_trigger_t;
|
|
|
+
|
|
|
+#if defined(__ARMCC_VERSION) || defined(__ICCARM__)
|
|
|
+typedef void (BSP_CMSE_NONSECURE_CALL * adc_prv_ns_callback)(adc_callback_args_t * p_args);
|
|
|
+#elif defined(__GNUC__)
|
|
|
+typedef BSP_CMSE_NONSECURE_CALL void (*volatile adc_prv_ns_callback)(adc_callback_args_t * p_args);
|
|
|
+#endif
|
|
|
+
|
|
|
+/***********************************************************************************************************************
|
|
|
+ * Private global variables and functions
|
|
|
+ **********************************************************************************************************************/
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+static fsp_err_t r_adc_open_cfg_check(adc_cfg_t const * const p_cfg);
|
|
|
+static fsp_err_t r_adc_open_cfg_resolution_check(adc_cfg_t const * const p_cfg);
|
|
|
+static fsp_err_t r_adc_sample_state_cfg_check(adc_instance_ctrl_t * p_instance_ctrl, adc_sample_state_t * p_sample);
|
|
|
+
|
|
|
+static fsp_err_t r_adc_scan_cfg_check_sample_hold(adc_instance_ctrl_t * const p_instance_ctrl,
|
|
|
+ adc_channel_cfg_t const * const p_channel_cfg);
|
|
|
+
|
|
|
+static fsp_err_t r_adc_scan_cfg_check_sensors(adc_instance_ctrl_t * const p_instance_ctrl,
|
|
|
+ adc_channel_cfg_t const * const p_channel_cfg);
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+static void r_adc_open_sub(adc_instance_ctrl_t * const p_instance_ctrl, adc_cfg_t const * const p_cfg);
|
|
|
+
|
|
|
+static void r_adc_sensor_cfg(adc_instance_ctrl_t * const p_instance_ctrl,
|
|
|
+ adc_channel_cfg_t const * const p_channel_cfg);
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+static fsp_err_t r_adc_scan_cfg_check(adc_instance_ctrl_t * const p_instance_ctrl,
|
|
|
+ adc_channel_cfg_t const * const p_channel_cfg);
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+static void r_adc_scan_cfg(adc_instance_ctrl_t * const p_instance_ctrl,
|
|
|
+ adc_channel_cfg_t const * const p_channel_cfg);
|
|
|
+static void r_adc_sensor_sample_state_calculation(uint32_t * const p_sample_states);
|
|
|
+void adc_scan_end_b_isr(void);
|
|
|
+void adc_scan_end_isr(void);
|
|
|
+void adc_window_compare_isr(void);
|
|
|
+static void r_adc_irq_enable(IRQn_Type irq, uint8_t ipl, void * p_context);
|
|
|
+static void r_adc_irq_disable(IRQn_Type irq);
|
|
|
+static int32_t r_adc_lowest_channel_get(uint32_t adc_mask);
|
|
|
+static void r_adc_scan_end_common_isr(adc_event_t event);
|
|
|
+
|
|
|
+/** Look-up table for ADSTRGR values */
|
|
|
+static const uint32_t adc_elc_trigger_lut[] =
|
|
|
+{
|
|
|
+ [ADC_DOUBLE_TRIGGER_DISABLED] = (ADC_ELC_TRIGGER << R_ADC0_ADSTRGR_TRSA_Pos) + ADC_ELC_TRIGGER_GROUP_B,
|
|
|
+ [ADC_DOUBLE_TRIGGER_ENABLED] = (ADC_ELC_TRIGGER << R_ADC0_ADSTRGR_TRSA_Pos) + ADC_ELC_TRIGGER_GROUP_B,
|
|
|
+ [ADC_DOUBLE_TRIGGER_ENABLED_EXTENDED] = (ADC_ELC_TRIGGER_BOTH << R_ADC0_ADSTRGR_TRSA_Pos) +
|
|
|
+ ADC_ELC_TRIGGER_DISABLED,
|
|
|
+};
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+/** Mask of valid channels on this MCU. */
|
|
|
+static const uint32_t g_adc_valid_channels[] =
|
|
|
+{
|
|
|
+ BSP_FEATURE_ADC_UNIT_0_CHANNELS,
|
|
|
+ #if BSP_FEATURE_ADC_UNIT_1_CHANNELS
|
|
|
+ BSP_FEATURE_ADC_UNIT_1_CHANNELS
|
|
|
+ #endif
|
|
|
+};
|
|
|
+#endif
|
|
|
+
|
|
|
+/***********************************************************************************************************************
|
|
|
+ * Global Variables
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+/** ADC Implementation of ADC. */
|
|
|
+const adc_api_t g_adc_on_adc =
|
|
|
+{
|
|
|
+ .open = R_ADC_Open,
|
|
|
+ .scanCfg = R_ADC_ScanCfg,
|
|
|
+ .infoGet = R_ADC_InfoGet,
|
|
|
+ .scanStart = R_ADC_ScanStart,
|
|
|
+ .scanGroupStart = R_ADC_ScanGroupStart,
|
|
|
+ .scanStop = R_ADC_ScanStop,
|
|
|
+ .scanStatusGet = R_ADC_StatusGet,
|
|
|
+ .read = R_ADC_Read,
|
|
|
+ .read32 = R_ADC_Read32,
|
|
|
+ .close = R_ADC_Close,
|
|
|
+ .calibrate = R_ADC_Calibrate,
|
|
|
+ .offsetSet = R_ADC_OffsetSet,
|
|
|
+ .callbackSet = R_ADC_CallbackSet,
|
|
|
+};
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * @addtogroup ADC
|
|
|
+ * @{
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+/***********************************************************************************************************************
|
|
|
+ * Functions
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Sets the operational mode, trigger sources, interrupt priority, and configurations for the peripheral as a whole.
|
|
|
+ * If interrupt is enabled, the function registers a callback function pointer for notifying the user whenever a scan
|
|
|
+ * has completed.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Module is ready for use.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_ALREADY_OPEN The instance control structure has already been opened.
|
|
|
+ * @retval FSP_ERR_IRQ_BSP_DISABLED A callback is provided, but the interrupt is not enabled.
|
|
|
+ * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT The requested unit does not exist on this MCU.
|
|
|
+ * @retval FSP_ERR_INVALID_HW_CONDITION The ADC clock must be at least 1 MHz
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_Open (adc_ctrl_t * p_ctrl, adc_cfg_t const * const p_cfg)
|
|
|
+{
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+
|
|
|
+ /* Perform parameter checking */
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+ /* Verify the pointers are valid */
|
|
|
+ FSP_ASSERT(NULL != p_instance_ctrl);
|
|
|
+
|
|
|
+ /* Verify the configuration parameters are valid */
|
|
|
+ fsp_err_t err = r_adc_open_cfg_check(p_cfg);
|
|
|
+ FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
|
|
|
+
|
|
|
+ /* Check for valid argument values for options that are unique to the IP */
|
|
|
+ err = r_adc_open_cfg_resolution_check(p_cfg);
|
|
|
+ FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
|
|
|
+
|
|
|
+ /* Verify this unit has not already been initialized */
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN != p_instance_ctrl->opened, FSP_ERR_ALREADY_OPEN);
|
|
|
+
|
|
|
+ /* If a callback is used, then make sure an interrupt is enabled */
|
|
|
+ adc_extended_cfg_t const * p_extend = (adc_extended_cfg_t const *) p_cfg->p_extend;
|
|
|
+ if (NULL != p_cfg->p_callback)
|
|
|
+ {
|
|
|
+ FSP_ERROR_RETURN((p_cfg->scan_end_irq >= 0) || (p_extend->window_a_irq >= 0) || (p_extend->window_b_irq >= 0),
|
|
|
+ FSP_ERR_IRQ_BSP_DISABLED);
|
|
|
+
|
|
|
+ /* Group B interrupts are never required since group B can be configured in continuous scan mode when group A
|
|
|
+ * has priority over group B. */
|
|
|
+ }
|
|
|
+
|
|
|
+#else
|
|
|
+ adc_extended_cfg_t const * p_extend = (adc_extended_cfg_t const *) p_cfg->p_extend;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Save configurations. */
|
|
|
+ p_instance_ctrl->p_cfg = p_cfg;
|
|
|
+ p_instance_ctrl->p_callback = p_cfg->p_callback;
|
|
|
+ p_instance_ctrl->p_context = p_cfg->p_context;
|
|
|
+ p_instance_ctrl->p_callback_memory = NULL;
|
|
|
+
|
|
|
+ /* Calculate the register base address. */
|
|
|
+ uint32_t address_gap = (uint32_t) R_ADC1 - (uint32_t) R_ADC0;
|
|
|
+ p_instance_ctrl->p_reg = (R_ADC0_Type *) ((uint32_t) R_ADC0 + (address_gap * p_cfg->unit));
|
|
|
+
|
|
|
+ /* Initialize the hardware based on the configuration. */
|
|
|
+ r_adc_open_sub(p_instance_ctrl, p_cfg);
|
|
|
+
|
|
|
+ /* Enable interrupts */
|
|
|
+ r_adc_irq_enable(p_cfg->scan_end_irq, p_cfg->scan_end_ipl, p_instance_ctrl);
|
|
|
+ r_adc_irq_enable(p_cfg->scan_end_b_irq, p_cfg->scan_end_b_ipl, p_instance_ctrl);
|
|
|
+ r_adc_irq_enable(p_extend->window_a_irq, p_extend->window_a_ipl, p_instance_ctrl);
|
|
|
+ r_adc_irq_enable(p_extend->window_b_irq, p_extend->window_b_ipl, p_instance_ctrl);
|
|
|
+
|
|
|
+ /* Invalid scan mask (initialized for later). */
|
|
|
+ p_instance_ctrl->scan_mask = 0U;
|
|
|
+
|
|
|
+ /* Mark driver as opened by initializing it to "RADC" in its ASCII equivalent for this unit. */
|
|
|
+ p_instance_ctrl->opened = ADC_OPEN;
|
|
|
+
|
|
|
+ /* Return the error code */
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Configures the ADC scan parameters. Channel specific settings are set in this function. Pass a pointer to
|
|
|
+ * @ref adc_channel_cfg_t to p_channel_cfg.
|
|
|
+ *
|
|
|
+ * @note This starts group B scans if adc_channel_cfg_t::priority_group_a is set to ADC_GROUP_A_GROUP_B_CONTINUOUS_SCAN.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Channel specific settings applied.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_ScanCfg (adc_ctrl_t * p_ctrl, void const * const p_channel_cfg)
|
|
|
+{
|
|
|
+ adc_channel_cfg_t const * p_adc_channel_cfg = (adc_channel_cfg_t const *) p_channel_cfg;
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+ fsp_err_t err = FSP_SUCCESS;
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+ FSP_ASSERT(NULL != p_instance_ctrl);
|
|
|
+ FSP_ASSERT(NULL != p_adc_channel_cfg);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+
|
|
|
+ err = r_adc_scan_cfg_check(p_instance_ctrl, p_adc_channel_cfg);
|
|
|
+ FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Configure the hardware based on the configuration */
|
|
|
+ r_adc_scan_cfg(p_instance_ctrl, p_adc_channel_cfg);
|
|
|
+
|
|
|
+ /* Save the scan mask locally; this is required for the infoGet function. */
|
|
|
+ p_instance_ctrl->scan_mask = p_adc_channel_cfg->scan_mask;
|
|
|
+
|
|
|
+ /* Return the error code */
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Updates the user callback and has option of providing memory for callback structure.
|
|
|
+ * Implements adc_api_t::callbackSet
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Callback updated successfully.
|
|
|
+ * @retval FSP_ERR_ASSERTION A required pointer is NULL.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN The control block has not been opened.
|
|
|
+ * @retval FSP_ERR_NO_CALLBACK_MEMORY p_callback is non-secure and p_callback_memory is either secure or NULL.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_CallbackSet (adc_ctrl_t * const p_api_ctrl,
|
|
|
+ void ( * p_callback)(adc_callback_args_t *),
|
|
|
+ void const * const p_context,
|
|
|
+ adc_callback_args_t * const p_callback_memory)
|
|
|
+{
|
|
|
+ adc_instance_ctrl_t * p_ctrl = (adc_instance_ctrl_t *) p_api_ctrl;
|
|
|
+
|
|
|
+#if (ADC_CFG_PARAM_CHECKING_ENABLE)
|
|
|
+ FSP_ASSERT(p_ctrl);
|
|
|
+ FSP_ASSERT(p_callback);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Store callback and context */
|
|
|
+
|
|
|
+#if BSP_TZ_SECURE_BUILD
|
|
|
+
|
|
|
+ /* Get security state of p_callback */
|
|
|
+ bool callback_is_secure =
|
|
|
+ (NULL == cmse_check_address_range((void *) p_callback, sizeof(void *), CMSE_AU_NONSECURE));
|
|
|
+
|
|
|
+ #if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+ /* In secure projects, p_callback_memory must be provided in non-secure space if p_callback is non-secure */
|
|
|
+ adc_callback_args_t * const p_callback_memory_checked = cmse_check_pointed_object(p_callback_memory,
|
|
|
+ CMSE_AU_NONSECURE);
|
|
|
+ FSP_ERROR_RETURN(callback_is_secure || (NULL != p_callback_memory_checked), FSP_ERR_NO_CALLBACK_MEMORY);
|
|
|
+ #endif
|
|
|
+
|
|
|
+ p_ctrl->p_callback = callback_is_secure ? p_callback :
|
|
|
+ (void (*)(adc_callback_args_t *))cmse_nsfptr_create(p_callback);
|
|
|
+#else
|
|
|
+ p_ctrl->p_callback = p_callback;
|
|
|
+#endif
|
|
|
+
|
|
|
+ p_ctrl->p_context = p_context;
|
|
|
+ p_ctrl->p_callback_memory = p_callback_memory;
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Starts a software scan or enables the hardware trigger for a scan depending on how the triggers were configured in
|
|
|
+ * the R_ADC_Open call. If the unit was configured for ELC or external hardware triggering, then this function allows
|
|
|
+ * the trigger signal to get to the ADC unit. The function is not able to control the generation of the trigger itself.
|
|
|
+ * If the unit was configured for software triggering, then this function starts the software triggered scan.
|
|
|
+ *
|
|
|
+ * @pre Call R_ADC_ScanCfg after R_ADC_Open before starting a scan.
|
|
|
+ *
|
|
|
+ * @pre On MCUs that support calibration, call R_ADC_Calibrate and wait for calibration to complete before starting
|
|
|
+ * a scan.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Scan started (software trigger) or hardware triggers enabled.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ * @retval FSP_ERR_NOT_INITIALIZED Unit is not initialized.
|
|
|
+ * @retval FSP_ERR_IN_USE Another scan is still in progress (software trigger).
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_ScanStart (adc_ctrl_t * p_ctrl)
|
|
|
+{
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+
|
|
|
+ /* Perform parameter checking */
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+ /* Verify the pointers are valid */
|
|
|
+ FSP_ASSERT(NULL != p_instance_ctrl);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->initialized, FSP_ERR_NOT_INITIALIZED);
|
|
|
+ if (ADC_GROUP_A_GROUP_B_CONTINUOUS_SCAN != p_instance_ctrl->p_reg->ADGSPCR)
|
|
|
+ {
|
|
|
+ FSP_ERROR_RETURN(0U == p_instance_ctrl->p_reg->ADCSR_b.ADST, FSP_ERR_IN_USE);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Enable hardware trigger or start software scan depending on mode. */
|
|
|
+ p_instance_ctrl->p_reg->ADCSR = p_instance_ctrl->scan_start_adcsr;
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * @ref adc_api_t::scanStart is not supported on the ADCH. Use scanStart instead.
|
|
|
+ *
|
|
|
+ * @retval FSP_ERR_UNSUPPORTED Function not supported in this implementation.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_ScanGroupStart (adc_ctrl_t * p_ctrl, adc_group_mask_t group_id)
|
|
|
+{
|
|
|
+ FSP_PARAMETER_NOT_USED(p_ctrl);
|
|
|
+ FSP_PARAMETER_NOT_USED(group_id);
|
|
|
+
|
|
|
+ /* Return the unsupported error. */
|
|
|
+ return FSP_ERR_UNSUPPORTED;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Stops the software scan or disables the unit from being triggered by the hardware trigger (ELC or external) based on
|
|
|
+ * what type of trigger the unit was configured for in the R_ADC_Open function. Stopping a hardware triggered scan via
|
|
|
+ * this function does not abort an ongoing scan, but prevents the next scan from occurring. Stopping a software
|
|
|
+ * triggered scan aborts an ongoing scan.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Scan stopped (software trigger) or hardware triggers disabled.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ * @retval FSP_ERR_NOT_INITIALIZED Unit is not initialized.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_ScanStop (adc_ctrl_t * p_ctrl)
|
|
|
+{
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+
|
|
|
+ /* Perform parameter checking */
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+ /* Verify the pointers are valid */
|
|
|
+ FSP_ASSERT(NULL != p_instance_ctrl);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->initialized, FSP_ERR_NOT_INITIALIZED);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Disable hardware trigger or stop software scan depending on mode. */
|
|
|
+ p_instance_ctrl->p_reg->ADCSR = 0U;
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Provides the status of any scan process that was started, including scans started by ELC or external triggers and
|
|
|
+ * calibration scans on MCUs that support calibration.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Module status stored in the provided pointer p_status
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_StatusGet (adc_ctrl_t * p_ctrl, adc_status_t * p_status)
|
|
|
+{
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+ FSP_ASSERT(NULL != p_instance_ctrl);
|
|
|
+ FSP_ASSERT(NULL != p_status);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Read the status of the ADST bit. ADST is set when a scan is in progress, including calibration scans. */
|
|
|
+ p_status->state = (adc_state_t) p_instance_ctrl->p_reg->ADCSR_b.ADST;
|
|
|
+
|
|
|
+ /* Return the error code */
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Reads conversion results from a single channel or sensor.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Data read into provided p_data.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ * @retval FSP_ERR_NOT_INITIALIZED Unit is not initialized.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_Read (adc_ctrl_t * p_ctrl, adc_channel_t const reg_id, uint16_t * const p_data)
|
|
|
+{
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+
|
|
|
+ /* Perform parameter checking. */
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+ /* Verify the pointers are valid */
|
|
|
+ FSP_ASSERT(NULL != p_instance_ctrl);
|
|
|
+ FSP_ASSERT(NULL != p_data);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->initialized, FSP_ERR_NOT_INITIALIZED);
|
|
|
+
|
|
|
+ /* Verify that the channel is valid for this MCU */
|
|
|
+ if ((reg_id >= ADC_CHANNEL_0) && ((uint32_t) reg_id <= 31U))
|
|
|
+ {
|
|
|
+ uint32_t requested_channel_mask = (1U << (uint32_t) reg_id);
|
|
|
+ FSP_ASSERT(0 != (requested_channel_mask & g_adc_valid_channels[p_instance_ctrl->p_cfg->unit]));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ FSP_ASSERT((reg_id == ADC_CHANNEL_TEMPERATURE) || (reg_id == ADC_CHANNEL_VOLT) ||
|
|
|
+ (reg_id == ADC_CHANNEL_DUPLEX) || (reg_id == ADC_CHANNEL_DUPLEX_A) ||
|
|
|
+ (reg_id == ADC_CHANNEL_DUPLEX_B));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Data is not available to be read from ADDRn registers when ADBUF is enabled. Read API cannot be used with ADBUF enabled. */
|
|
|
+ adc_extended_cfg_t * p_extend = (adc_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend;
|
|
|
+ FSP_ASSERT(1U != p_extend->enable_adbuf);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Read the data from the requested ADC conversion register and return it */
|
|
|
+ *p_data = p_instance_ctrl->p_reg->ADDR[reg_id];
|
|
|
+
|
|
|
+ /* Return the error code */
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Reads conversion results from a single channel or sensor register into a 32-bit result.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Data read into provided p_data.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ * @retval FSP_ERR_NOT_INITIALIZED Unit is not initialized.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_Read32 (adc_ctrl_t * p_ctrl, adc_channel_t const reg_id, uint32_t * const p_data)
|
|
|
+{
|
|
|
+ uint16_t result = 0U;
|
|
|
+ uint32_t result_32 = 0U;
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+ FSP_ASSERT(NULL != p_data);
|
|
|
+#endif
|
|
|
+
|
|
|
+ fsp_err_t err = R_ADC_Read(p_ctrl, reg_id, &result);
|
|
|
+ FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
|
|
|
+
|
|
|
+ result_32 = result;
|
|
|
+
|
|
|
+ /* Left shift the result into the upper 16 bits if the unit is configured for left alignment. */
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+ if (ADC_ALIGNMENT_LEFT == p_instance_ctrl->p_cfg->alignment)
|
|
|
+ {
|
|
|
+ result_32 <<= ADC_SHIFT_LEFT_ALIGNED_32_BIT;
|
|
|
+ }
|
|
|
+
|
|
|
+ *p_data = result_32;
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Sets the sample state count for individual channels. This only needs to be set for special use cases. Normally, use
|
|
|
+ * the default values out of reset.
|
|
|
+ *
|
|
|
+ * @note The sample states for the temperature and voltage sensor are set in R_ADC_ScanCfg.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Sample state count updated.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_INITIALIZED Unit is not initialized.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_SampleStateCountSet (adc_ctrl_t * p_ctrl, adc_sample_state_t * p_sample)
|
|
|
+{
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+ fsp_err_t err = FSP_SUCCESS;
|
|
|
+
|
|
|
+ /* Perform parameter checking */
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+ /* Verify the pointers are valid */
|
|
|
+ FSP_ASSERT(NULL != p_instance_ctrl);
|
|
|
+ FSP_ASSERT(NULL != p_sample);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->initialized, FSP_ERR_NOT_INITIALIZED);
|
|
|
+
|
|
|
+ /* Verify arguments are legal */
|
|
|
+ err = r_adc_sample_state_cfg_check(p_instance_ctrl, p_sample);
|
|
|
+ if (FSP_SUCCESS != err)
|
|
|
+ {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Set the sample state count for the specified register */
|
|
|
+ p_instance_ctrl->p_reg->ADSSTR[p_sample->reg_id] = p_sample->num_states;
|
|
|
+
|
|
|
+ /* Return the error code */
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Returns the address of the lowest number configured channel and the total number of bytes to be read in order to
|
|
|
+ * read the results of the configured channels and return the ELC Event name. If no channels are configured, then a
|
|
|
+ * length of 0 is returned.
|
|
|
+ *
|
|
|
+ * Also provides the temperature sensor slope and the calibration data for the sensor if available on this MCU.
|
|
|
+ * Otherwise, invalid calibration data of 0xFFFFFFFF will be returned.
|
|
|
+ *
|
|
|
+ * @note In group mode, information is returned for group A only. Calculating information for group B is not currently
|
|
|
+ * supported.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Information stored in p_adc_info.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_InfoGet (adc_ctrl_t * p_ctrl, adc_info_t * p_adc_info)
|
|
|
+{
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+ fsp_err_t err = FSP_SUCCESS;
|
|
|
+ uint32_t adc_mask = 0;
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+ FSP_ASSERT(NULL != p_instance_ctrl);
|
|
|
+ FSP_ASSERT(NULL != p_adc_info);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Retrieve the scan mask of active channels from the control structure */
|
|
|
+ adc_mask = p_instance_ctrl->scan_mask;
|
|
|
+
|
|
|
+ /* If at least one channel is configured, determine the highest and lowest configured channels. */
|
|
|
+ if (adc_mask != 0U)
|
|
|
+ {
|
|
|
+ /* Determine the lowest channel that is configured. The lowest sensor is the temperature sensor, at -3 from
|
|
|
+ * channel 0. To get all channels in register order, shift up by 3, then add in the sensors in the bottom
|
|
|
+ * 2 bits. */
|
|
|
+ uint32_t adc_mask_in_order = adc_mask & ~(uint32_t) ADC_MASK_SENSORS;
|
|
|
+ adc_mask_in_order <<= 3U;
|
|
|
+ adc_mask_in_order |= adc_mask >> 28U;
|
|
|
+ int32_t lowest_channel = r_adc_lowest_channel_get(adc_mask_in_order);
|
|
|
+ p_adc_info->p_address = &p_instance_ctrl->p_reg->ADDR[lowest_channel - 3];
|
|
|
+
|
|
|
+ /* Determine the highest channel that is configured. */
|
|
|
+ int32_t highest_channel = 31 - __CLZ(adc_mask_in_order);
|
|
|
+
|
|
|
+ /* Determine the size of data that must be read to read all the channels between and including the
|
|
|
+ * highest and lowest channels.*/
|
|
|
+ p_adc_info->length = (uint32_t) ((highest_channel - lowest_channel) + 1);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* If no channels are configured, set the return length 0. */
|
|
|
+ p_adc_info->length = 0U;
|
|
|
+ }
|
|
|
+
|
|
|
+ p_adc_info->transfer_size = TRANSFER_SIZE_2_BYTE;
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_UNIT_1_CHANNELS
|
|
|
+
|
|
|
+ /* Specify the peripheral name in the ELC list */
|
|
|
+ p_adc_info->elc_event =
|
|
|
+ (elc_event_t) ((uint32_t) ELC_EVENT_ADC0_SCAN_END +
|
|
|
+ (p_instance_ctrl->p_cfg->unit *
|
|
|
+ ((uint32_t) ELC_EVENT_ADC1_SCAN_END - (uint32_t) ELC_EVENT_ADC0_SCAN_END)));
|
|
|
+#else
|
|
|
+ p_adc_info->elc_event = ELC_EVENT_ADC0_SCAN_END;
|
|
|
+#endif
|
|
|
+
|
|
|
+ p_adc_info->elc_peripheral = (elc_peripheral_t) (ELC_PERIPHERAL_ADC0 + (2U * p_instance_ctrl->p_cfg->unit));
|
|
|
+
|
|
|
+ /* Set Temp Sensor calibration data to invalid value */
|
|
|
+ p_adc_info->calibration_data = UINT32_MAX;
|
|
|
+
|
|
|
+ /* If calibration register is available, retrieve it from the MCU */
|
|
|
+#if 1U == BSP_FEATURE_ADC_TSN_CALIBRATION_AVAILABLE
|
|
|
+ #if 1U == BSP_FEATURE_ADC_TSN_CALIBRATION32_AVAILABLE
|
|
|
+
|
|
|
+ /* Read into memory. */
|
|
|
+ uint32_t data = R_TSN_CAL->TSCDR;
|
|
|
+
|
|
|
+ /* Read the temperature calibration data from ROM. */
|
|
|
+ p_adc_info->calibration_data = (data & BSP_FEATURE_ADC_TSN_CALIBRATION32_MASK);
|
|
|
+ #else
|
|
|
+
|
|
|
+ /* Read into memory to prevent compiler warning when performing "|" on volatile register data. */
|
|
|
+ uint32_t high = R_TSN->TSCDRH;
|
|
|
+ uint32_t low = R_TSN->TSCDRL;
|
|
|
+
|
|
|
+ /* Read the calibration data from ROM and shift to fit into result variable. */
|
|
|
+ p_adc_info->calibration_data = ((high << 8) | low);
|
|
|
+ #endif
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Provide the previously retrieved slope information */
|
|
|
+ p_adc_info->slope_microvolts = BSP_FEATURE_ADC_TSN_SLOPE;
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function ends any scan in progress, disables interrupts, and removes power to the A/D peripheral.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Module closed.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_Close (adc_ctrl_t * p_ctrl)
|
|
|
+{
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+ FSP_ASSERT(NULL != p_instance_ctrl);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Mark driver as closed */
|
|
|
+ p_instance_ctrl->opened = 0U;
|
|
|
+ p_instance_ctrl->initialized = 0U;
|
|
|
+
|
|
|
+ /* Disable interrupts. */
|
|
|
+ adc_extended_cfg_t * p_extend = (adc_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend;
|
|
|
+ r_adc_irq_disable(p_instance_ctrl->p_cfg->scan_end_irq);
|
|
|
+ r_adc_irq_disable(p_instance_ctrl->p_cfg->scan_end_b_irq);
|
|
|
+ r_adc_irq_disable(p_extend->window_a_irq);
|
|
|
+ r_adc_irq_disable(p_extend->window_b_irq);
|
|
|
+
|
|
|
+ /* Disable triggers. */
|
|
|
+ p_instance_ctrl->p_reg->ADSTRGR = 0U;
|
|
|
+
|
|
|
+ /* Stop the ADC. */
|
|
|
+ p_instance_ctrl->p_reg->ADCSR = 0U;
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_HAS_SAMPLE_HOLD_REG
|
|
|
+
|
|
|
+ /* Disable sample and hold before entering module stop state to reduce power consumption (reference section 47.6.8
|
|
|
+ * "Available Functions and Register Settings of AN000 to AN002, AN007, AN100 to AN102, and AN107" in the RA6M3
|
|
|
+ * manual R01UH0886EJ0100. */
|
|
|
+ p_instance_ctrl->p_reg->ADSHCR = 0U;
|
|
|
+#endif
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_HAS_VREFAMPCNT
|
|
|
+
|
|
|
+ /* If VREFADC is selected as the high-potential reference voltage revert it to reduce power consumption. */
|
|
|
+ p_instance_ctrl->p_reg->VREFAMPCNT = 0U;
|
|
|
+#endif
|
|
|
+
|
|
|
+ R_BSP_MODULE_STOP(FSP_IP_ADC, p_instance_ctrl->p_cfg->unit);
|
|
|
+
|
|
|
+ /* Return the error code */
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Initiates calibration of the ADC on MCUs that require calibration. This function must be called before starting
|
|
|
+ * a scan on MCUs that require calibration.
|
|
|
+ *
|
|
|
+ * Calibration is complete when the callback is called with ADC_EVENT_CALIBRATION_COMPLETE or when R_ADC_StatusGet
|
|
|
+ * returns ADC_STATUS_IDLE. Reference Figure 32.35 "Software flow and operation example of calibration operation."
|
|
|
+ * in the RA2A1 manual R01UH0888EJ0100.
|
|
|
+ *
|
|
|
+ * ADC calibration time: 12 PCLKB + 774,930 ADCLK. (Reference Table 32.16 "Required calibration time (shown
|
|
|
+ * as the number of ADCLK and PCLKB cycles)" in the RA2A1 manual R01UH0888EJ0100. The lowest supported ADCLK
|
|
|
+ * is 1MHz.
|
|
|
+ *
|
|
|
+ * Calibration will take a minimum of 24 milliseconds at 32 MHz PCLKB and ADCLK. This wait could take up to 780
|
|
|
+ * milliseconds for a 1 MHz PCLKD (ADCLK).
|
|
|
+ *
|
|
|
+ * @param[in] p_ctrl Pointer to the instance control structure
|
|
|
+ * @param[in] p_extend Unused argument. Pass NULL.
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS Calibration successfully initiated.
|
|
|
+ * @retval FSP_ERR_INVALID_HW_CONDITION A scan is in progress or hardware triggers are enabled.
|
|
|
+ * @retval FSP_ERR_UNSUPPORTED Calibration not supported on this MCU.
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_NOT_OPEN Unit is not open.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_Calibrate (adc_ctrl_t * const p_ctrl, void const * p_extend)
|
|
|
+{
|
|
|
+ FSP_PARAMETER_NOT_USED(p_extend);
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_CALIBRATION_REG_AVAILABLE
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) p_ctrl;
|
|
|
+ #if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+ FSP_ASSERT(NULL != p_ctrl);
|
|
|
+ FSP_ERROR_RETURN(ADC_OPEN == p_instance_ctrl->opened, FSP_ERR_NOT_OPEN);
|
|
|
+ #endif
|
|
|
+
|
|
|
+ /* ADC Calibration can only happen if there is no ongoing scan and if the scan trigger is disabled */
|
|
|
+ FSP_ERROR_RETURN(!(p_instance_ctrl->p_reg->ADCSR & ADC_PRV_ADCSR_ADST_TRGE_MASK), FSP_ERR_INVALID_HW_CONDITION);
|
|
|
+
|
|
|
+ /* Set the normal mode interrupt request to occur when calibration is complete */
|
|
|
+ p_instance_ctrl->p_reg->ADICR = ADC_ADICR_CALIBRATION_INTERRUPT_ENABLED;
|
|
|
+
|
|
|
+ /* Initiate calibration */
|
|
|
+ p_instance_ctrl->p_reg->ADCALEXE = ADC_ADCALEXE_SET_CALEXE;
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+#else
|
|
|
+ FSP_PARAMETER_NOT_USED(p_ctrl);
|
|
|
+ FSP_ERROR_LOG(FSP_ERR_UNSUPPORTED);
|
|
|
+
|
|
|
+ return FSP_ERR_UNSUPPORTED;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * @ref adc_api_t::offsetSet is not supported on the ADC.
|
|
|
+ *
|
|
|
+ * @retval FSP_ERR_UNSUPPORTED Function not supported in this implementation.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+fsp_err_t R_ADC_OffsetSet (adc_ctrl_t * const p_ctrl, adc_channel_t const reg_id, int32_t offset)
|
|
|
+{
|
|
|
+ FSP_PARAMETER_NOT_USED(p_ctrl);
|
|
|
+ FSP_PARAMETER_NOT_USED(reg_id);
|
|
|
+ FSP_PARAMETER_NOT_USED(offset);
|
|
|
+
|
|
|
+ /* Return the unsupported error. */
|
|
|
+ return FSP_ERR_UNSUPPORTED;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * @} (end addtogroup ADC)
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+/***********************************************************************************************************************
|
|
|
+ * Private Functions
|
|
|
+ **********************************************************************************************************************/
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Checks the sample state configuration.
|
|
|
+ *
|
|
|
+ * @param[in] p_instance_ctrl Pointer to instance control structure
|
|
|
+ * @param[in] p_sample Pointer to sample state configuration
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS No configuration errors detected
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static fsp_err_t r_adc_sample_state_cfg_check (adc_instance_ctrl_t * p_instance_ctrl, adc_sample_state_t * p_sample)
|
|
|
+{
|
|
|
+ /* Used to prevent compiler warning */
|
|
|
+ FSP_PARAMETER_NOT_USED(p_instance_ctrl);
|
|
|
+
|
|
|
+ adc_sample_state_reg_t reg_id = p_sample->reg_id;
|
|
|
+
|
|
|
+ /* Verify the requested channel exists on the MCU. */
|
|
|
+ if (reg_id >= ADC_SAMPLE_STATE_CHANNEL_0)
|
|
|
+ {
|
|
|
+ uint32_t requested_channel_mask = (1U << (uint32_t) reg_id);
|
|
|
+ FSP_ASSERT(0 != (requested_channel_mask & g_adc_valid_channels[p_instance_ctrl->p_cfg->unit]));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Verify the requested sample states is not less than the minimum. */
|
|
|
+ FSP_ASSERT(p_sample->num_states >= ADC_SAMPLE_STATE_COUNT_MIN);
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Validates the configuration arguments for illegal combinations or options.
|
|
|
+ *
|
|
|
+ * @param[in] p_cfg Pointer to configuration structure
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS No configuration errors detected
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT ADC unit not present on this MCU
|
|
|
+ * @retval FSP_ERR_INVALID_HW_CONDITION The ADC clock must be at least 1 MHz
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static fsp_err_t r_adc_open_cfg_check (adc_cfg_t const * const p_cfg)
|
|
|
+{
|
|
|
+ FSP_ASSERT(NULL != p_cfg);
|
|
|
+
|
|
|
+ /* Verify the unit exists on the MCU. */
|
|
|
+ FSP_ERROR_RETURN(((1U << p_cfg->unit) & BSP_FEATURE_ADC_VALID_UNIT_MASK), FSP_ERR_IP_CHANNEL_NOT_PRESENT);
|
|
|
+
|
|
|
+ /* Verify the ADC clock frequency is at least 1 MHz (reference "Frequency" row of table "60.5 ADC12
|
|
|
+ * Characteristics" in the RA6M3 manual R01UH0886EJ0100. The maximum frequency is the maximum frequency supported
|
|
|
+ * by the ADCLK, so it is not verified here. */
|
|
|
+ uint32_t freq_hz = R_FSP_SystemClockHzGet(BSP_FEATURE_ADC_CLOCK_SOURCE);
|
|
|
+ FSP_ERROR_RETURN(freq_hz >= ADC_PRV_MIN_ADCLK_HZ, FSP_ERR_INVALID_HW_CONDITION);
|
|
|
+
|
|
|
+ /* Check for valid argument values for addition/averaging. Reference section 47.2.10 "A/D-Converted Value
|
|
|
+ * Addition/Average Count Select Register (ADADC)" in the RA6M3 manual R01UH0886EJ0100 and section 32.2.11
|
|
|
+ * "A/D-Converted Value Average Count Select Register (ADADC)" in the RA2A1 manual R01UH0888EJ0100. */
|
|
|
+ adc_extended_cfg_t const * p_cfg_extend = (adc_extended_cfg_t const *) p_cfg->p_extend;
|
|
|
+ if (ADC_ADD_OFF != p_cfg_extend->add_average_count)
|
|
|
+ {
|
|
|
+ #if BSP_FEATURE_ADC_ADDITION_SUPPORTED
|
|
|
+
|
|
|
+ /* The ADC12 and ADC14 do not support averaging 8 or 16 samples. */
|
|
|
+ FSP_ASSERT(p_cfg_extend->add_average_count <= ADC_ADD_AVERAGE_FOUR);
|
|
|
+ #else
|
|
|
+
|
|
|
+ /* The ADC16 supports averaging only, it does not support addition. */
|
|
|
+ FSP_ASSERT(0U != (ADC_ADADC_AVEE_BIT & p_cfg_extend->add_average_count));
|
|
|
+ #endif
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If 16 time addition is used only 12 bit accuracy can be selected. Reference Note 1 of section 47.2.10
|
|
|
+ * "A/D-Converted Value Addition/Average Count Select Register (ADADC)" in the RA6M3 manual R01UH0886EJ0100. */
|
|
|
+ if (ADC_ADD_SIXTEEN == p_cfg_extend->add_average_count)
|
|
|
+ {
|
|
|
+ FSP_ASSERT(ADC_RESOLUTION_12_BIT == p_cfg->resolution);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Only synchronous triggers (ELC) allowed in group scan mode (reference TRSA documentation in section 47.2.12
|
|
|
+ * "A/D Conversion Start Trigger Select Register (ADSTRGR)" in the RA6M3 manual R01UH0886EJ0100. */
|
|
|
+ if ((ADC_MODE_GROUP_SCAN == p_cfg->mode) || (ADC_DOUBLE_TRIGGER_DISABLED != p_cfg_extend->double_trigger_mode))
|
|
|
+ {
|
|
|
+ FSP_ASSERT(ADC_TRIGGER_SYNC_ELC == p_cfg->trigger);
|
|
|
+
|
|
|
+ if ((ADC_MODE_GROUP_SCAN == p_cfg->mode))
|
|
|
+ {
|
|
|
+ FSP_ASSERT(ADC_TRIGGER_SYNC_ELC == p_cfg_extend->trigger_group_b);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function validates the resolution configuration arguments for illegal combinations or options.
|
|
|
+ *
|
|
|
+ * @param[in] p_cfg Pointer to configuration structure
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS No configuration errors detected
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static fsp_err_t r_adc_open_cfg_resolution_check (adc_cfg_t const * const p_cfg)
|
|
|
+{
|
|
|
+ #if 12U == BSP_FEATURE_ADC_MAX_RESOLUTION_BITS
|
|
|
+ #if BSP_FEATURE_ADC_HAS_ADCER_ADPRC
|
|
|
+
|
|
|
+ /* Resolution options for ADC12 (reference section 47.2.11 "A/D Control Extended Register (ADCER)" in the RA6M3
|
|
|
+ * manual R01UH0886EJ0100. */
|
|
|
+ FSP_ASSERT((ADC_RESOLUTION_12_BIT == p_cfg->resolution) ||
|
|
|
+ (ADC_RESOLUTION_10_BIT == p_cfg->resolution) ||
|
|
|
+ (ADC_RESOLUTION_8_BIT == p_cfg->resolution));
|
|
|
+ #else
|
|
|
+ FSP_ASSERT(ADC_RESOLUTION_12_BIT == p_cfg->resolution);
|
|
|
+ #endif
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if 14U == BSP_FEATURE_ADC_MAX_RESOLUTION_BITS
|
|
|
+
|
|
|
+ /* Resolution options for ADC14 (reference section 35.2.11 "A/D Control Extended Register (ADCER)" in the RA4M1
|
|
|
+ * manual R01UH0886EJ0100. */
|
|
|
+ FSP_ASSERT((ADC_RESOLUTION_12_BIT == p_cfg->resolution) ||
|
|
|
+ (ADC_RESOLUTION_14_BIT == p_cfg->resolution));
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if 16U == BSP_FEATURE_ADC_MAX_RESOLUTION_BITS
|
|
|
+
|
|
|
+ /* ADC16 only offers 16-bit resolution (reference Table 32.1 "ADC16 specifications (1 of 2)" in the RA2A1 manual
|
|
|
+ * R01UH0888EJ0100. */
|
|
|
+ FSP_ASSERT(ADC_RESOLUTION_16_BIT == p_cfg->resolution);
|
|
|
+ #endif
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Checks the sample and hold arguments
|
|
|
+ *
|
|
|
+ * @param[in] p_instance_ctrl Pointer to instance control block
|
|
|
+ * @param[in] p_channel_cfg Pointer to channel configuration
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS No configuration errors detected
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static fsp_err_t r_adc_scan_cfg_check_sample_hold (adc_instance_ctrl_t * const p_instance_ctrl,
|
|
|
+ adc_channel_cfg_t const * const p_channel_cfg)
|
|
|
+{
|
|
|
+ #if !BSP_FEATURE_ADC_HAS_SAMPLE_HOLD_REG
|
|
|
+
|
|
|
+ /* If the MCU does not have sample and hold, verify the sample and hold feature is not used. */
|
|
|
+ FSP_ASSERT(0U == p_channel_cfg->sample_hold_mask);
|
|
|
+ FSP_PARAMETER_NOT_USED(p_instance_ctrl);
|
|
|
+ #else
|
|
|
+ if (0U != p_channel_cfg->sample_hold_mask)
|
|
|
+ {
|
|
|
+ /* Sample and Hold channels can only be 0, 1, 2 and must have at least minimum state count specified (reference
|
|
|
+ * section 47.2.15 "A/D Sample and Hold Circuit Control Register (ADSHCR)" in the RA6M3 manual
|
|
|
+ * R01UH0886EJ0100. */
|
|
|
+ FSP_ASSERT(p_channel_cfg->sample_hold_mask <= ADC_SAMPLE_HOLD_CHANNELS);
|
|
|
+ FSP_ASSERT(p_channel_cfg->sample_hold_states >= ADC_SAMPLE_STATE_HOLD_COUNT_MIN);
|
|
|
+
|
|
|
+ uint32_t b_mask = p_channel_cfg->sample_hold_mask & p_channel_cfg->scan_mask_group_b;
|
|
|
+ if (ADC_MODE_GROUP_SCAN == p_instance_ctrl->p_cfg->mode)
|
|
|
+ {
|
|
|
+ if (ADC_GROUP_A_PRIORITY_OFF != p_channel_cfg->priority_group_a)
|
|
|
+ {
|
|
|
+ /* Sample and hold channels cannot be in GroupB if GroupA priority enabled. (reference SHANS[2:0] bits
|
|
|
+ * in section 47.2.15 "A/D Sample and Hold Circuit Control Register (ADSHCR)" in the RA6M3 manual
|
|
|
+ * R01UH0886EJ0100.*/
|
|
|
+ FSP_ASSERT(0 == b_mask);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Enforces constraints on Window Compare function usage per section 47.3.5.3 "Constraints on the compare function" in
|
|
|
+ * the RA6M3 User's Manual (R01UH0886EJ0100)
|
|
|
+ *
|
|
|
+ * @param[in] p_window_cfg Pointer to window compare configuration
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS No configuration errors detected
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static fsp_err_t r_adc_scan_cfg_check_window_compare (adc_window_cfg_t const * const p_window_cfg)
|
|
|
+{
|
|
|
+ if (p_window_cfg)
|
|
|
+ {
|
|
|
+ uint32_t compare_cfg = p_window_cfg->compare_cfg;
|
|
|
+ if (0U != compare_cfg)
|
|
|
+ {
|
|
|
+ if ((compare_cfg & R_ADC0_ADCMPCR_CMPAE_Msk) && (compare_cfg & R_ADC0_ADCMPCR_CMPBE_Msk))
|
|
|
+ {
|
|
|
+ /* Ensure channels selected for Window A do not conflict with Window B */
|
|
|
+ uint32_t compare_b_ch = p_window_cfg->compare_b_channel;
|
|
|
+ compare_b_ch -= compare_b_ch > 31 ? 4 : 0;
|
|
|
+ FSP_ASSERT(!(p_window_cfg->compare_mask & (uint32_t) (1 << compare_b_ch)));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (compare_cfg & R_ADC0_ADCMPCR_WCMPE_Msk)
|
|
|
+ {
|
|
|
+ /* Ensure lower reference values are less than or equal to the high reference values */
|
|
|
+ FSP_ASSERT((p_window_cfg->compare_ref_low <= p_window_cfg->compare_ref_high) &&
|
|
|
+ (p_window_cfg->compare_b_ref_low <= p_window_cfg->compare_b_ref_high));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function checks the Temperature and Voltage sensor arguments
|
|
|
+ *
|
|
|
+ * @param[in] p_instance_ctrl Pointer to instance control block
|
|
|
+ * @param[in] p_channel_cfg Pointer to channel configuration
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS No configuration errors detected
|
|
|
+ * @retval FSP_ERR_ASSERTION Sensor configuration has been selected for Group B on an MCU which does not allow
|
|
|
+ * Group B configuration or sensor is used in Normal/Group A with the double trigger
|
|
|
+ * not enabled or MCU does not allow both the sensors to be used simultaneously
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static fsp_err_t r_adc_scan_cfg_check_sensors (adc_instance_ctrl_t * const p_instance_ctrl,
|
|
|
+ adc_channel_cfg_t const * const p_channel_cfg)
|
|
|
+{
|
|
|
+ /* Some MCUs have nothing to check here. */
|
|
|
+ FSP_PARAMETER_NOT_USED(p_channel_cfg);
|
|
|
+
|
|
|
+ #if !BSP_FEATURE_ADC_GROUP_B_SENSORS_ALLOWED
|
|
|
+
|
|
|
+ /* Sensors are not supported in Group B in some MCUs. Reference section 32.2.14 "A/D Conversion Extended Input
|
|
|
+ * Control Register (ADEXICR)" of the RA2A1 manual R01UH0888EJ0100. */
|
|
|
+ FSP_ASSERT(0U == (p_channel_cfg->scan_mask_group_b & ADC_MASK_SENSORS));
|
|
|
+ #endif
|
|
|
+
|
|
|
+ #if BSP_FEATURE_ADC_SENSORS_EXCLUSIVE
|
|
|
+ uint32_t sensor_mask = p_channel_cfg->scan_mask & ADC_MASK_SENSORS;
|
|
|
+ if (0U != sensor_mask)
|
|
|
+ {
|
|
|
+ /* If the temperature sensor or the internal voltage reference is used, then none of the channels can be used
|
|
|
+ * at the same time. The temperature sensor and the internal voltage reference can only be used in single scan
|
|
|
+ * mode. Reference TSSA and OCSA bits in section 35.2.13 "A/D Conversion Extended Input Control Register
|
|
|
+ * (ADEXICR)" of the RA4M1 manual R01UH0887EJ0100. */
|
|
|
+ FSP_ASSERT(ADC_MASK_SENSORS != sensor_mask);
|
|
|
+ FSP_ASSERT(p_channel_cfg->scan_mask == sensor_mask);
|
|
|
+ FSP_ASSERT(ADC_MODE_SINGLE_SCAN == p_instance_ctrl->p_cfg->mode);
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+
|
|
|
+ /* When using double-trigger modes the sensors must not be configured or used in Group A. */
|
|
|
+ adc_extended_cfg_t const * p_cfg_extend = (adc_extended_cfg_t const *) p_instance_ctrl->p_cfg->p_extend;
|
|
|
+ if (ADC_DOUBLE_TRIGGER_DISABLED != p_cfg_extend->double_trigger_mode)
|
|
|
+ {
|
|
|
+ FSP_ASSERT(0U == (p_channel_cfg->scan_mask & ADC_MASK_SENSORS));
|
|
|
+ }
|
|
|
+
|
|
|
+ return FSP_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * The Open function applies power to the A/D peripheral, sets the operational mode, trigger sources, and
|
|
|
+ * configurations common to all channels and sensors.
|
|
|
+ *
|
|
|
+ * @param[in] p_instance_ctrl Pointer to instance control block
|
|
|
+ * @param[in] p_cfg Pointer to configuration structure
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static void r_adc_open_sub (adc_instance_ctrl_t * const p_instance_ctrl, adc_cfg_t const * const p_cfg)
|
|
|
+{
|
|
|
+ adc_extended_cfg_t const * p_cfg_extend = (adc_extended_cfg_t const *) p_cfg->p_extend;
|
|
|
+
|
|
|
+ /* Determine the value for ADCSR:
|
|
|
+ * * The configured mode is set in ADCSR.ADCS.
|
|
|
+ * * ADCSR.GBADIE is always set by this driver. It will only trigger an interrupt in group mode if the group B
|
|
|
+ * interrupt is enabled.
|
|
|
+ * * If double-trigger mode is selected ADCSR.DBLANS is set to the chosen double-trigger scan channel and
|
|
|
+ * ADCSR.DBLE is set to 1; otherwise, both are set to 0.
|
|
|
+ * * The configured trigger mode is set in ADCSR.EXTRG and ADCSR.TRGE.
|
|
|
+ * * The value to set in ADCSR to start a scan is stored in the control structure. ADCSR.ADST is set in
|
|
|
+ * R_ADC_ScanStart if software trigger mode is used.
|
|
|
+ */
|
|
|
+ uint32_t adcsr = (uint32_t) (p_cfg->mode << R_ADC0_ADCSR_ADCS_Pos);
|
|
|
+ adcsr |= (uint32_t) (R_ADC0_ADCSR_GBADIE_Msk);
|
|
|
+ adcsr |= ((uint32_t) p_cfg->trigger << R_ADC0_ADCSR_EXTRG_Pos);
|
|
|
+
|
|
|
+ if (ADC_DOUBLE_TRIGGER_DISABLED != p_cfg_extend->double_trigger_mode)
|
|
|
+ {
|
|
|
+ adcsr |= R_ADC0_ADCSR_TRGE_Msk | R_ADC0_ADCSR_DBLE_Msk;
|
|
|
+ }
|
|
|
+ else if (ADC_TRIGGER_SOFTWARE == p_cfg->trigger)
|
|
|
+ {
|
|
|
+ adcsr |= R_ADC0_ADCSR_ADST_Msk;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* Do nothing. */
|
|
|
+ }
|
|
|
+
|
|
|
+ p_instance_ctrl->scan_start_adcsr = (uint16_t) adcsr;
|
|
|
+
|
|
|
+ /* The default value for ADSTRGR is 0 out of reset. Update it only if the ADC is triggered on ELC events. */
|
|
|
+ uint32_t adstrgr = 0U;
|
|
|
+ if (ADC_TRIGGER_SYNC_ELC == p_cfg->trigger)
|
|
|
+ {
|
|
|
+ /* Set ADSTRGR per the following:
|
|
|
+ * Extended double-trigger mode:
|
|
|
+ * - Normal (Group A): ELC_PERIPHERAL_ADCn and ELC_PERIPHERAL_ADCn_B
|
|
|
+ * - Group B: None
|
|
|
+ * All other modes:
|
|
|
+ * - Normal (Group A): ELC_PERIPHERAL_ADCn
|
|
|
+ * - Group B: ELC_PERIPHERAL_ADCn_B
|
|
|
+ */
|
|
|
+ adstrgr = adc_elc_trigger_lut[p_cfg_extend->double_trigger_mode];
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Determine the value for ADCER:
|
|
|
+ * * The resolution is set as configured in ADCER.ADPRC (on MCUs that have this bitfield).
|
|
|
+ * * The alignment is set as configured in ADCER.ADFMT (on MCUs that have this bitfield).
|
|
|
+ * * The clearing option is set as configured in ADCER.ACE.
|
|
|
+ * * Always select data range of 0 - 32767 in ADCER.INV (on MCUs that have this bitfield).
|
|
|
+ * * Always disable self-diagnosis (unsupported in this module).
|
|
|
+ */
|
|
|
+ uint32_t adcer = 0U;
|
|
|
+#if BSP_FEATURE_ADC_HAS_ADCER_ADPRC
|
|
|
+ adcer |= (uint32_t) p_cfg->resolution << R_ADC0_ADCER_ADPRC_Pos;
|
|
|
+#endif
|
|
|
+#if BSP_FEATURE_ADC_HAS_ADCER_ADRFMT
|
|
|
+ adcer |= (uint32_t) p_cfg->alignment << R_ADC0_ADCER_ADRFMT_Pos;
|
|
|
+#endif
|
|
|
+ adcer |= (uint32_t) p_cfg_extend->clearing << R_ADC0_ADCER_ACE_Pos;
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_CALIBRATION_REG_AVAILABLE
|
|
|
+ adcer |= 1U << R_ADC0_ADCER_ADINV_Pos;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Determine the value for ADADC:
|
|
|
+ * * The addition/averaging modes are set as configured in ADADC.ADC and ADADC.AVEE.
|
|
|
+ * * On MCUs that do not have the ADADC.AVEE bit (addition not supported), the ADADC.AVEE bit is cleared.
|
|
|
+ */
|
|
|
+ uint32_t adadc = p_cfg_extend->add_average_count;
|
|
|
+#if !BSP_FEATURE_ADC_ADDITION_SUPPORTED
|
|
|
+ adadc &= ~ADC_ADADC_AVEE_BIT;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Apply clock to peripheral. */
|
|
|
+ R_BSP_MODULE_START(FSP_IP_ADC, p_cfg->unit);
|
|
|
+
|
|
|
+ /* Set the predetermined values for ADCSR, ADSTRGR, ADCER, and ADADC without setting ADCSR.ADST or ADCSR.TRGE.
|
|
|
+ * ADCSR.ADST or ADCSR.TRGE are set as configured in R_ADC_ScanStart. */
|
|
|
+ p_instance_ctrl->p_reg->ADCSR = (uint16_t) (adcsr & ADC_PRV_ADCSR_CLEAR_ADST_TRGE);
|
|
|
+ p_instance_ctrl->p_reg->ADSTRGR = (uint16_t) adstrgr;
|
|
|
+ p_instance_ctrl->p_reg->ADCER = (uint16_t) adcer;
|
|
|
+ p_instance_ctrl->p_reg->ADADC = (uint8_t) adadc;
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_HAS_PGA
|
|
|
+
|
|
|
+ /* Disable the unused ADC PGA feature (on MCUs where it is available) since the feature is enabled out of reset on
|
|
|
+ * some MCUs and disabled on others and affects the operation of the normal ADC channels that are multiplexed with
|
|
|
+ * the PGA. */
|
|
|
+ p_instance_ctrl->p_reg->ADPGADCR0 = ADC_ADPGADCR0_DISABLE_PGA;
|
|
|
+ p_instance_ctrl->p_reg->ADPGACR = ADC_ADPGACR_DISABLE_PGA;
|
|
|
+#endif
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_CALIBRATION_REG_AVAILABLE
|
|
|
+
|
|
|
+ /* Use ADC in single-ended mode. */
|
|
|
+ p_instance_ctrl->p_reg->ADANIM = 0U;
|
|
|
+#endif
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_HAS_VREFAMPCNT
|
|
|
+
|
|
|
+ /* If VREFADC is selected as the high-potential reference voltage. */
|
|
|
+ if (ADC_VREF_CONTROL_VREFH != p_cfg_extend->adc_vref_control)
|
|
|
+ {
|
|
|
+ /* Configure Reference Voltage controls
|
|
|
+ * Reference section "32.6 Selecting Reference Voltage" in the RA2A1 manual R01UH0888EJ0100. */
|
|
|
+ p_instance_ctrl->p_reg->VREFAMPCNT =
|
|
|
+ (uint8_t) (p_cfg_extend->adc_vref_control &
|
|
|
+ (R_ADC0_VREFAMPCNT_BGREN_Msk | R_ADC0_VREFAMPCNT_VREFADCG_Msk));
|
|
|
+
|
|
|
+ R_BSP_SoftwareDelay(ADC_BGR_STABILIZATION_DELAY_US, BSP_DELAY_UNITS_MICROSECONDS);
|
|
|
+
|
|
|
+ /* Enable Over current detection and VREFADC output */
|
|
|
+ p_instance_ctrl->p_reg->VREFAMPCNT = (uint8_t) (p_cfg_extend->adc_vref_control);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_HAS_ADHVREFCNT
|
|
|
+
|
|
|
+ /* If the internal voltage is set as VREFH, discharge the VREF node for 1 us before setting ADHVREFCNT.HVSEL to 2.
|
|
|
+ * Reference section 35.7 "A/D Conversion Procedure when Selecting Internal Reference Voltage as High-Potential
|
|
|
+ * Reference Voltage" in the RA4M1 manual R01UH0887EJ0100.
|
|
|
+ *
|
|
|
+ * Also wait 5 us before using the ADC. This wait is the responsibility of the application. */
|
|
|
+ if (ADC_PRV_ADHVREFCNT_VREF_INTERNAL_BIT_1 & p_cfg_extend->adc_vref_control)
|
|
|
+ {
|
|
|
+ p_instance_ctrl->p_reg->ADHVREFCNT = (uint8_t) (p_cfg_extend->adc_vref_control | R_ADC0_ADHVREFCNT_HVSEL_Msk);
|
|
|
+
|
|
|
+ R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
|
|
|
+ }
|
|
|
+ p_instance_ctrl->p_reg->ADHVREFCNT = (uint8_t) p_cfg_extend->adc_vref_control;
|
|
|
+#endif
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_HAS_ADBUF
|
|
|
+ uint8_t adbuf = 0;
|
|
|
+ if (1U == p_cfg_extend->enable_adbuf)
|
|
|
+ {
|
|
|
+ adbuf = R_ADC0_ADBUFEN_BUFEN_Msk;
|
|
|
+ }
|
|
|
+ p_instance_ctrl->p_reg->ADBUFEN = adbuf;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function set the sensor bits taking into account group inclusion and addition/average mode.
|
|
|
+ * This function must only be called if it has been verified that sensors are used in this configuration
|
|
|
+ *
|
|
|
+ * @param[in] p_instance_ctrl Pointer to instance control block
|
|
|
+ * @param[in] p_channel_cfg Pointer to channel configuration
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static void r_adc_sensor_cfg (adc_instance_ctrl_t * const p_instance_ctrl,
|
|
|
+ adc_channel_cfg_t const * const p_channel_cfg)
|
|
|
+{
|
|
|
+ /* Calculate sample states required for temperature and voltage sensor at the current ADCLK speed. */
|
|
|
+ uint32_t sample_states = 0U;
|
|
|
+ r_adc_sensor_sample_state_calculation(&sample_states);
|
|
|
+
|
|
|
+ /* Check if the temperature sensor channel is enabled */
|
|
|
+ uint32_t combined_scan_mask = p_channel_cfg->scan_mask | p_channel_cfg->scan_mask_group_b;
|
|
|
+ uint32_t adexicr = 0U;
|
|
|
+ if (combined_scan_mask & ADC_MASK_TEMPERATURE)
|
|
|
+ {
|
|
|
+#if BSP_FEATURE_ADC_TSN_CONTROL_AVAILABLE
|
|
|
+
|
|
|
+ /* Power on the temperature sensor. This is only needed for TSNs that have the control register */
|
|
|
+ R_BSP_MODULE_START(FSP_IP_TSN, 0U);
|
|
|
+
|
|
|
+ /* Enable the temperature sensor output to the ADC */
|
|
|
+ R_TSN_CTRL->TSCR = ADC_PRV_TSCR_TSN_ENABLE;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Set sample state register to the calculated value */
|
|
|
+ p_instance_ctrl->p_reg->ADSSTRT = (uint8_t) sample_states;
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_GROUP_B_SENSORS_ALLOWED
|
|
|
+ if (p_channel_cfg->scan_mask & ADC_MASK_TEMPERATURE)
|
|
|
+ {
|
|
|
+ /* Scan the temperature sensor in normal/group A. */
|
|
|
+ adexicr |= R_ADC0_ADEXICR_TSSA_Msk;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* Scan the temperature sensor in group B */
|
|
|
+ adexicr |= R_ADC0_ADEXICR_TSSB_Msk;
|
|
|
+ }
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+ /* Scan the temperature sensor in normal/group A. */
|
|
|
+ adexicr |= R_ADC0_ADEXICR_TSSA_Msk;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Enable temperature addition mode if configured. */
|
|
|
+ if (p_channel_cfg->add_mask & ADC_MASK_TEMPERATURE)
|
|
|
+ {
|
|
|
+ adexicr |= R_ADC0_ADEXICR_TSSAD_Msk;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check if the voltage sensor channel is enabled */
|
|
|
+ if (combined_scan_mask & ADC_MASK_VOLT)
|
|
|
+ {
|
|
|
+ /*sample state registers are set to the calculated value */
|
|
|
+ p_instance_ctrl->p_reg->ADSSTRO = (uint8_t) sample_states;
|
|
|
+#if BSP_FEATURE_ADC_GROUP_B_SENSORS_ALLOWED
|
|
|
+ if (p_channel_cfg->scan_mask & ADC_MASK_VOLT)
|
|
|
+ {
|
|
|
+ /* Scan the internal reference voltage in normal/group A. */
|
|
|
+ adexicr |= R_ADC0_ADEXICR_OCSA_Msk;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* Scan the internal reference voltage in group B. */
|
|
|
+ adexicr |= R_ADC0_ADEXICR_OCSB_Msk;
|
|
|
+ }
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+ /* Scan the internal reference voltage in normal/group A. */
|
|
|
+ adexicr |= R_ADC0_ADEXICR_OCSA_Msk;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Enable temperature addition mode if configured. */
|
|
|
+ if (p_channel_cfg->add_mask & ADC_MASK_VOLT)
|
|
|
+ {
|
|
|
+ adexicr |= R_ADC0_ADEXICR_OCSAD_Msk;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ p_instance_ctrl->p_reg->ADEXICR = (uint16_t) adexicr;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function calculates the sample states value for the internal sensors and returns an error if the calculated
|
|
|
+ * value is outside the limit supported by the hardware
|
|
|
+ *
|
|
|
+ * @param[out] p_sample_states: The calculates sample state count.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static void r_adc_sensor_sample_state_calculation (uint32_t * const p_sample_states)
|
|
|
+{
|
|
|
+ /* Calculate sample state values such that the sample time for the temperature and voltage sensor is the
|
|
|
+ * minimum defined by the hardware manual. The minimum is 4.15 microseconds for MF3 devices and
|
|
|
+ * 5 microseconds for RV40. The sample states will be calculated to allow sampling for this duration. */
|
|
|
+
|
|
|
+ /* Retrieve the clock source and frequency used by the ADC peripheral and sampling time required for the sensor. */
|
|
|
+ uint32_t freq_hz = R_FSP_SystemClockHzGet(BSP_FEATURE_ADC_CLOCK_SOURCE);
|
|
|
+
|
|
|
+ /* Calculate sample states required for the current ADC conversion clock (reference section 47.2.14 "A/D Sampling
|
|
|
+ * State Register n (ADSSTRn) (n = 00 to 07, L, T, O)" in the RA6M3 manual R01UH0886EJ0100.
|
|
|
+ *
|
|
|
+ * sample_states = required_sample_time / adclk_period
|
|
|
+ * = required_sample_time (nsec) * adclk_frequency (kHz) / 1000000 (usec / sec) + 1
|
|
|
+ * (refactored to avoid overflowing 32 bits, 1 added to round up)
|
|
|
+ */
|
|
|
+ uint32_t sample_states = ((BSP_FEATURE_ADC_SENSOR_MIN_SAMPLING_TIME * (freq_hz / ADC_PRV_HZ_PER_KHZ)) /
|
|
|
+ ADC_PRV_USEC_PER_SEC) + 1U;
|
|
|
+
|
|
|
+ /* The fastest ADC conversion clock is 60 MHz, and the associated sampling time is 4.15 microseconds. The number
|
|
|
+ * of sample states in this case is 0.00000415 / (1 / 60000000) = 249. This is the maximum number of sample states
|
|
|
+ * required for the on chip sensors, so this calculation will never overflow 8 bits (255). */
|
|
|
+
|
|
|
+ /* If sample states are less than the min number of states required, then set them to the minimum. */
|
|
|
+ if (sample_states < ADC_SAMPLE_STATE_COUNT_MIN)
|
|
|
+ {
|
|
|
+ sample_states = ADC_SAMPLE_STATE_COUNT_MIN;
|
|
|
+ }
|
|
|
+
|
|
|
+ *p_sample_states = sample_states;
|
|
|
+}
|
|
|
+
|
|
|
+#if ADC_CFG_PARAM_CHECKING_ENABLE
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function does extensive checking on channel mask settings based upon operational mode.
|
|
|
+ *
|
|
|
+ * @param[in] p_instance_ctrl Pointer to instance control block
|
|
|
+ * @param[in] p_channel_cfg Pointer to channel configuration
|
|
|
+ *
|
|
|
+ * @retval FSP_SUCCESS No configuration errors detected
|
|
|
+ * @retval FSP_ERR_ASSERTION An input argument is invalid.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static fsp_err_t r_adc_scan_cfg_check (adc_instance_ctrl_t * const p_instance_ctrl,
|
|
|
+ adc_channel_cfg_t const * const p_channel_cfg)
|
|
|
+{
|
|
|
+ fsp_err_t err;
|
|
|
+ uint16_t unit = p_instance_ctrl->p_cfg->unit;
|
|
|
+
|
|
|
+ /* Verify at least one channel is selected for normal / group A. */
|
|
|
+ uint32_t valid_channels = g_adc_valid_channels[unit] | ADC_MASK_TEMPERATURE | ADC_MASK_VOLT;
|
|
|
+ FSP_ASSERT((0U != p_channel_cfg->scan_mask) && (0U == (p_channel_cfg->scan_mask & (~valid_channels))));
|
|
|
+
|
|
|
+ if (ADC_MODE_GROUP_SCAN == p_instance_ctrl->p_cfg->mode)
|
|
|
+ {
|
|
|
+ /* Verify at least one channel is selected for group B. */
|
|
|
+ FSP_ASSERT((0U != p_channel_cfg->scan_mask_group_b) &&
|
|
|
+ (0U == (p_channel_cfg->scan_mask_group_b & (~valid_channels))));
|
|
|
+
|
|
|
+ /* Cannot have the same channel in both groups. */
|
|
|
+ FSP_ASSERT(0 == (p_channel_cfg->scan_mask & p_channel_cfg->scan_mask_group_b));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* If group mode is not enabled, no channels can be selected for group B. */
|
|
|
+ FSP_ASSERT(ADC_MASK_OFF == p_channel_cfg->scan_mask_group_b);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Verify sensor configuration. */
|
|
|
+ err = r_adc_scan_cfg_check_sensors(p_instance_ctrl, p_channel_cfg);
|
|
|
+ FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
|
|
|
+
|
|
|
+ /* Verify that if addition is enabled, then at least one channel is selected. */
|
|
|
+ adc_extended_cfg_t const * p_cfg_extend = (adc_extended_cfg_t const *) p_instance_ctrl->p_cfg->p_extend;
|
|
|
+ if (ADC_ADD_OFF != p_cfg_extend->add_average_count)
|
|
|
+ {
|
|
|
+ /* Addition mask should not include bits from inactive channels.
|
|
|
+ * This also serves as a check for valid channels in the addition mask */
|
|
|
+ uint32_t tmp_mask = p_channel_cfg->scan_mask_group_b | p_channel_cfg->scan_mask;
|
|
|
+ FSP_ASSERT((0U == (p_channel_cfg->add_mask & ~tmp_mask)) && (0U != p_channel_cfg->add_mask));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* Channels cannot be selected for addition if addition is not used. */
|
|
|
+ FSP_ASSERT(ADC_MASK_OFF == p_channel_cfg->add_mask);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check sample and hold settings. */
|
|
|
+ err = r_adc_scan_cfg_check_sample_hold(p_instance_ctrl, p_channel_cfg);
|
|
|
+ FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
|
|
|
+
|
|
|
+ /* Check window compare settings. */
|
|
|
+ err = r_adc_scan_cfg_check_window_compare(p_channel_cfg->p_window_cfg);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function does extensive checking on channel mask settings based upon operational mode. Mask registers are
|
|
|
+ * initialized and interrupts enabled in peripheral. Interrupts are also enabled in ICU if corresponding priority
|
|
|
+ * is not 0.
|
|
|
+ *
|
|
|
+ * @param[in] p_instance_ctrl Pointer to instance control block
|
|
|
+ * @param[in] p_channel_cfg Pointer to channel configuration
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static void r_adc_scan_cfg (adc_instance_ctrl_t * const p_instance_ctrl, adc_channel_cfg_t const * const p_channel_cfg)
|
|
|
+{
|
|
|
+ /* Set mask for Group A channels. */
|
|
|
+ uint32_t scan_mask = p_channel_cfg->scan_mask & ~(uint32_t) ADC_MASK_SENSORS;
|
|
|
+ adc_extended_cfg_t const * p_cfg_extend = (adc_extended_cfg_t const *) p_instance_ctrl->p_cfg->p_extend;
|
|
|
+
|
|
|
+ /* Set other channel masks. */
|
|
|
+ uint32_t scan_mask_group_b = p_channel_cfg->scan_mask_group_b & ~(uint32_t) ADC_MASK_SENSORS;
|
|
|
+ uint32_t add_mask = p_channel_cfg->add_mask & ~(uint32_t) ADC_MASK_SENSORS;
|
|
|
+
|
|
|
+ p_instance_ctrl->p_reg->ADANSA[0] = (uint16_t) (scan_mask);
|
|
|
+ p_instance_ctrl->p_reg->ADANSB[0] = (uint16_t) (scan_mask_group_b);
|
|
|
+ p_instance_ctrl->p_reg->ADADS[0] = (uint16_t) (add_mask);
|
|
|
+ p_instance_ctrl->p_reg->ADANSA[1] = (uint16_t) ((scan_mask >> 16));
|
|
|
+ p_instance_ctrl->p_reg->ADANSB[1] = (uint16_t) ((scan_mask_group_b >> 16));
|
|
|
+ p_instance_ctrl->p_reg->ADADS[1] = (uint16_t) ((add_mask >> 16));
|
|
|
+
|
|
|
+ /* If either voltage or temperature sensor are used, configure them. */
|
|
|
+ uint32_t temp_mask = p_channel_cfg->scan_mask | p_channel_cfg->scan_mask_group_b;
|
|
|
+ if (temp_mask & ADC_MASK_SENSORS)
|
|
|
+ {
|
|
|
+ /* Calculate sample state values such that the sample time for the temperature and voltage sensor is the
|
|
|
+ * minimum defined by the hardware manual. The minimum is 4.15 microseconds for MF3 devices and
|
|
|
+ * 5 microseconds for RV40. The sample states will be calculated to allow sampling for this duration. */
|
|
|
+
|
|
|
+ /* Retrieve the clock source and frequency used by the ADC peripheral and sampling time required for the sensor. */
|
|
|
+ r_adc_sensor_cfg(p_instance_ctrl, p_channel_cfg);
|
|
|
+ }
|
|
|
+
|
|
|
+#if BSP_FEATURE_ADC_HAS_SAMPLE_HOLD_REG
|
|
|
+
|
|
|
+ /* Configure sample and hold. */
|
|
|
+ uint32_t adshcr = p_channel_cfg->sample_hold_states;
|
|
|
+ adshcr |= (p_channel_cfg->sample_hold_mask & ADC_MASK_SAMPLE_HOLD_BYPASS_CHANNELS) <<
|
|
|
+ ADC_MASK_SAMPLE_HOLD_BYPASS_SHIFT;
|
|
|
+ p_instance_ctrl->p_reg->ADSHCR = (uint16_t) adshcr;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Get window compare configuration */
|
|
|
+ adc_window_cfg_t * p_window_cfg = p_channel_cfg->p_window_cfg;
|
|
|
+
|
|
|
+ uint16_t adcmpcr = 0;
|
|
|
+
|
|
|
+ if (p_window_cfg)
|
|
|
+ {
|
|
|
+ /* Save window compare config */
|
|
|
+ adcmpcr = (uint16_t) p_window_cfg->compare_cfg;
|
|
|
+
|
|
|
+ if (p_window_cfg->compare_cfg & R_ADC0_ADCMPCR_CMPAE_Msk)
|
|
|
+ {
|
|
|
+ /* Set Window A boundary values */
|
|
|
+ p_instance_ctrl->p_reg->ADCMPCR = p_window_cfg->compare_cfg & UINT16_MAX;
|
|
|
+ p_instance_ctrl->p_reg->ADCMPDR0 = p_window_cfg->compare_ref_low;
|
|
|
+ p_instance_ctrl->p_reg->ADCMPDR1 = p_window_cfg->compare_ref_high;
|
|
|
+
|
|
|
+ /* Set Window A channel mask */
|
|
|
+ p_instance_ctrl->p_reg->ADCMPANSR[0] = p_window_cfg->compare_mask & UINT16_MAX;
|
|
|
+ p_instance_ctrl->p_reg->ADCMPANSR[1] = (uint16_t) ((p_window_cfg->compare_mask << 4) >> 20);
|
|
|
+ p_instance_ctrl->p_reg->ADCMPANSER = (uint8_t) (p_window_cfg->compare_mask >> 28);
|
|
|
+
|
|
|
+ /* Set Window A channel inequality mode mask */
|
|
|
+ p_instance_ctrl->p_reg->ADCMPLR[0] = p_window_cfg->compare_mode_mask & UINT16_MAX;
|
|
|
+ p_instance_ctrl->p_reg->ADCMPLR[1] = (uint16_t) ((p_window_cfg->compare_mode_mask << 4) >> 20);
|
|
|
+ p_instance_ctrl->p_reg->ADCMPLER = (uint8_t) (p_window_cfg->compare_mode_mask >> 28);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (p_window_cfg->compare_cfg & R_ADC0_ADCMPCR_CMPBE_Msk)
|
|
|
+ {
|
|
|
+ /* Set Window B channel and mode */
|
|
|
+ p_instance_ctrl->p_reg->ADCMPBNSR = (uint8_t) ((adc_window_b_mode_t) p_window_cfg->compare_b_channel |
|
|
|
+ p_window_cfg->compare_b_mode);
|
|
|
+
|
|
|
+ /* Set Window B boundary values */
|
|
|
+ p_instance_ctrl->p_reg->ADWINLLB = p_window_cfg->compare_b_ref_low;
|
|
|
+ p_instance_ctrl->p_reg->ADWINULB = p_window_cfg->compare_b_ref_high;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Set window compare config */
|
|
|
+ p_instance_ctrl->p_reg->ADCMPCR = adcmpcr;
|
|
|
+
|
|
|
+ /* Set group A priority action (not interrupt priority!)
|
|
|
+ * This will also start the Group B scans if configured for ADC_GROUP_A_GROUP_B_CONTINUOUS_SCAN.
|
|
|
+ */
|
|
|
+ p_instance_ctrl->p_reg->ADGSPCR = (uint16_t) p_channel_cfg->priority_group_a;
|
|
|
+
|
|
|
+ /* In double-trigger mode set the channel select bits to the highest selected channel number then return. */
|
|
|
+ if (ADC_DOUBLE_TRIGGER_DISABLED != p_cfg_extend->double_trigger_mode)
|
|
|
+ {
|
|
|
+ uint32_t adcsr = p_instance_ctrl->p_reg->ADCSR;
|
|
|
+ adcsr = (adcsr & ~R_ADC0_ADCSR_DBLANS_Msk) + (31U - __CLZ(scan_mask));
|
|
|
+
|
|
|
+ p_instance_ctrl->p_reg->ADCSR = (uint16_t) adcsr;
|
|
|
+ p_instance_ctrl->scan_start_adcsr |= (uint16_t) adcsr;
|
|
|
+ }
|
|
|
+
|
|
|
+ p_instance_ctrl->initialized = ADC_OPEN;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Disables and clears context for the requested IRQ.
|
|
|
+ *
|
|
|
+ * @param[in] irq IRQ to enable
|
|
|
+ * @param[in] ipl Interrupt priority
|
|
|
+ * @param[in] p_context Pointer to interrupt context
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static void r_adc_irq_enable (IRQn_Type irq, uint8_t ipl, void * p_context)
|
|
|
+{
|
|
|
+ if (irq >= 0)
|
|
|
+ {
|
|
|
+ R_BSP_IrqCfgEnable(irq, ipl, p_context);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Disables and clears context for the requested IRQ.
|
|
|
+ *
|
|
|
+ * @param[in] irq IRQ to disable
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static void r_adc_irq_disable (IRQn_Type irq)
|
|
|
+{
|
|
|
+ if (irq >= 0)
|
|
|
+ {
|
|
|
+ R_BSP_IrqDisable(irq);
|
|
|
+ R_FSP_IsrContextSet(irq, NULL);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Returns the lowest channel index that is configured in order to read the results of the configured channels.
|
|
|
+ *
|
|
|
+ * @param[in] adc_mask scan mask of active channels retrieved from the control structure
|
|
|
+ *
|
|
|
+ * @retval adc_mask_count index value of lowest channel
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static int32_t r_adc_lowest_channel_get (uint32_t adc_mask)
|
|
|
+{
|
|
|
+ /* Initialize the mask result */
|
|
|
+ uint32_t adc_mask_result = 0U;
|
|
|
+ int32_t adc_mask_count = -1;
|
|
|
+ while (0U == adc_mask_result)
|
|
|
+ {
|
|
|
+ /* Increment channel until a channel is found in the mask. */
|
|
|
+ adc_mask_count++;
|
|
|
+ adc_mask_result = (uint32_t) (adc_mask & (1U << adc_mask_count));
|
|
|
+ }
|
|
|
+
|
|
|
+ return adc_mask_count;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Calls user callback.
|
|
|
+ *
|
|
|
+ * @param[in] p_ctrl Pointer to ADC instance control block
|
|
|
+ * @param[in] p_args Pointer to arguments on stack
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static void r_adc_call_callback (adc_instance_ctrl_t * p_ctrl, adc_callback_args_t * p_args)
|
|
|
+{
|
|
|
+ adc_callback_args_t args;
|
|
|
+
|
|
|
+ /* Store callback arguments in memory provided by user if available. This allows callback arguments to be
|
|
|
+ * stored in non-secure memory so they can be accessed by a non-secure callback function. */
|
|
|
+ adc_callback_args_t * p_args_memory = p_ctrl->p_callback_memory;
|
|
|
+ if (NULL == p_args_memory)
|
|
|
+ {
|
|
|
+ /* Use provided args struct on stack */
|
|
|
+ p_args_memory = p_args;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* Save current arguments on the stack in case this is a nested interrupt. */
|
|
|
+ args = *p_args_memory;
|
|
|
+
|
|
|
+ /* Copy the stacked args to callback memory */
|
|
|
+ *p_args_memory = *p_args;
|
|
|
+ }
|
|
|
+
|
|
|
+#if BSP_TZ_SECURE_BUILD
|
|
|
+
|
|
|
+ /* p_callback can point to a secure function or a non-secure function. */
|
|
|
+ if (!cmse_is_nsfptr(p_ctrl->p_callback))
|
|
|
+ {
|
|
|
+ /* If p_callback is secure, then the project does not need to change security state. */
|
|
|
+ p_ctrl->p_callback(p_args_memory);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* If p_callback is Non-secure, then the project must change to Non-secure state in order to call the callback. */
|
|
|
+ adc_prv_ns_callback p_callback = (adc_prv_ns_callback) (p_ctrl->p_callback);
|
|
|
+ p_callback(p_args_memory);
|
|
|
+ }
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+ /* If the project is not Trustzone Secure, then it will never need to change security state in order to call the callback. */
|
|
|
+ p_ctrl->p_callback(p_args_memory);
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (NULL != p_ctrl->p_callback_memory)
|
|
|
+ {
|
|
|
+ /* Restore callback memory in case this is a nested interrupt. */
|
|
|
+ *p_ctrl->p_callback_memory = args;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * Clears interrupt flag and calls a callback to notify application of the event.
|
|
|
+ *
|
|
|
+ * @param[in] event Event that triggered the ISR
|
|
|
+ **********************************************************************************************************************/
|
|
|
+static void r_adc_scan_end_common_isr (adc_event_t event)
|
|
|
+{
|
|
|
+ /* Save context if RTOS is used */
|
|
|
+ FSP_CONTEXT_SAVE;
|
|
|
+
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) R_FSP_IsrContextGet(R_FSP_CurrentIrqGet());
|
|
|
+
|
|
|
+ /* Clear the BSP IRQ Flag */
|
|
|
+ R_BSP_IrqStatusClear(R_FSP_CurrentIrqGet());
|
|
|
+
|
|
|
+ adc_callback_args_t args;
|
|
|
+ args.event = event;
|
|
|
+#if BSP_FEATURE_ADC_CALIBRATION_REG_AVAILABLE
|
|
|
+
|
|
|
+ /* Store the correct event into the callback argument */
|
|
|
+ if (ADC_ADICR_CALIBRATION_INTERRUPT_DISABLED != p_instance_ctrl->p_reg->ADICR)
|
|
|
+ {
|
|
|
+ args.event = ADC_EVENT_CALIBRATION_COMPLETE;
|
|
|
+
|
|
|
+ /* Restore the interrupt source to disable interrupts after calibration is done. */
|
|
|
+ p_instance_ctrl->p_reg->ADICR = 0U;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Store the unit number into the callback argument */
|
|
|
+ args.unit = p_instance_ctrl->p_cfg->unit;
|
|
|
+
|
|
|
+ /* Initialize the channel to 0. It is not used in this implementation. */
|
|
|
+ args.channel = ADC_CHANNEL_0;
|
|
|
+
|
|
|
+ /* Populate the context field. */
|
|
|
+ args.p_context = p_instance_ctrl->p_context;
|
|
|
+
|
|
|
+ /* If a callback was provided, call it with the argument */
|
|
|
+ if (NULL != p_instance_ctrl->p_callback)
|
|
|
+ {
|
|
|
+ r_adc_call_callback(p_instance_ctrl, &args);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Restore context if RTOS is used */
|
|
|
+ FSP_CONTEXT_RESTORE;
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function implements the unit 0 interrupt handler for normal/Group A/double trigger scan complete.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+void adc_scan_end_isr (void)
|
|
|
+{
|
|
|
+ r_adc_scan_end_common_isr(ADC_EVENT_SCAN_COMPLETE);
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function implements the interrupt handler for Group B scan complete.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+void adc_scan_end_b_isr (void)
|
|
|
+{
|
|
|
+ r_adc_scan_end_common_isr(ADC_EVENT_SCAN_COMPLETE_GROUP_B);
|
|
|
+}
|
|
|
+
|
|
|
+/*******************************************************************************************************************//**
|
|
|
+ * This function implements the interrupt handler for window compare events.
|
|
|
+ **********************************************************************************************************************/
|
|
|
+void adc_window_compare_isr (void)
|
|
|
+{
|
|
|
+ /* Save context if RTOS is used */
|
|
|
+ FSP_CONTEXT_SAVE;
|
|
|
+
|
|
|
+ IRQn_Type irq = R_FSP_CurrentIrqGet();
|
|
|
+
|
|
|
+ adc_instance_ctrl_t * p_instance_ctrl = (adc_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
|
|
|
+ adc_extended_cfg_t * p_extend = (adc_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend;
|
|
|
+
|
|
|
+ adc_callback_args_t args;
|
|
|
+ args.event = (irq == p_extend->window_a_irq) ? ADC_EVENT_WINDOW_COMPARE_A : ADC_EVENT_WINDOW_COMPARE_B;
|
|
|
+
|
|
|
+ /* Store the unit number into the callback argument */
|
|
|
+ args.unit = p_instance_ctrl->p_cfg->unit;
|
|
|
+
|
|
|
+ if (ADC_EVENT_WINDOW_COMPARE_A == args.event)
|
|
|
+ {
|
|
|
+ args.channel = (adc_channel_t) 0;
|
|
|
+
|
|
|
+ R_ADC0_Type * p_reg = p_instance_ctrl->p_reg;
|
|
|
+
|
|
|
+ /* Get all Window A status registers */
|
|
|
+ uint16_t adcmpsr0 = p_reg->ADCMPSR[0];
|
|
|
+ uint16_t adcmpsr1 = p_reg->ADCMPSR[1];
|
|
|
+ uint8_t adcmpser = p_reg->ADCMPSER;
|
|
|
+
|
|
|
+ /* Get the lowest channel that meets Window A criteria */
|
|
|
+ uint32_t lowest_channel = __CLZ(__RBIT(adcmpsr0 + (uint32_t) (adcmpsr1 << 16) + (uint32_t) (adcmpser << 28)));
|
|
|
+
|
|
|
+ /* Clear the status flag corresponding to the lowest channel */
|
|
|
+ if (lowest_channel < 16)
|
|
|
+ {
|
|
|
+ p_reg->ADCMPSR[0] = (uint16_t) (adcmpsr0 & ~(1 << (lowest_channel & 0xF)));
|
|
|
+ }
|
|
|
+ else if (lowest_channel < 28)
|
|
|
+ {
|
|
|
+ p_reg->ADCMPSR[1] = (uint16_t) (adcmpsr1 & ~(1 << (lowest_channel & 0xF)));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ p_reg->ADCMPSER = (uint8_t) (adcmpser & ~(1 << (lowest_channel & 0x3)));
|
|
|
+ }
|
|
|
+
|
|
|
+ args.channel = (adc_channel_t) lowest_channel;
|
|
|
+
|
|
|
+ if (args.channel > 28)
|
|
|
+ {
|
|
|
+ /* Adjust sensor channels to align with the adc_channel_t enumeration */
|
|
|
+ args.channel = (adc_channel_t) (ADC_CHANNEL_TEMPERATURE + (args.channel - 28));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ /* Get channel selected for Window B */
|
|
|
+ args.channel = (adc_channel_t) p_instance_ctrl->p_reg->ADCMPBNSR_b.CMPCHB;
|
|
|
+
|
|
|
+ if (args.channel > 31)
|
|
|
+ {
|
|
|
+ /* Adjust sensor channels to align with the adc_channel_t enumeration */
|
|
|
+ args.channel = (adc_channel_t) (ADC_CHANNEL_TEMPERATURE + (args.channel & 0xF));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Clear IRQ */
|
|
|
+ p_instance_ctrl->p_reg->ADCMPBSR_b.CMPSTB = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Populate the context field. */
|
|
|
+ args.p_context = p_instance_ctrl->p_context;
|
|
|
+
|
|
|
+ /* If a callback was provided, call it with the argument */
|
|
|
+ if (NULL != p_instance_ctrl->p_callback)
|
|
|
+ {
|
|
|
+ r_adc_call_callback(p_instance_ctrl, &args);
|
|
|
+ }
|
|
|
+
|
|
|
+ R_BSP_IrqStatusClear(irq);
|
|
|
+
|
|
|
+ /* Restore context if RTOS is used */
|
|
|
+ FSP_CONTEXT_RESTORE;
|
|
|
+}
|