text: /***************************************************************************//**
   * @file
   * @brief Capacitive Sense Module (CSEN) peripheral API
   *******************************************************************************
   * # License
   * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
   *******************************************************************************
   *
   * SPDX-License-Identifier: Zlib
   *
   * The licensor of this software is Silicon Laboratories Inc.
   *
   * This software is provided 'as-is', without any express or implied
   * warranty. In no event will the authors be held liable for any damages
   * arising from the use of this software.
   *
   * Permission is granted to anyone to use this software for any purpose,
   * including commercial applications, and to alter it and redistribute it
   * freely, subject to the following restrictions:
   *
   * 1. The origin of this software must not be misrepresented; you must not
   *    claim that you wrote the original software. If you use this software
   *    in a product, an acknowledgment in the product documentation would be
   *    appreciated but is not required.
   * 2. Altered source versions must be plainly marked as such, and must not be
   *    misrepresented as being the original software.
   * 3. This notice may not be removed or altered from any source distribution.
   *
   ******************************************************************************/
  
  #include "em_csen.h"
  #if defined(CSEN_COUNT) && (CSEN_COUNT > 0)
  
  #include "em_assert.h"
  #include "em_cmu.h"
  #include <stddef.h>
  
  /***************************************************************************//**
   * @addtogroup csen
   * @{
   ******************************************************************************/
  
  /*******************************************************************************
   *******************************   DEFINES   ***********************************
   ******************************************************************************/
  
  /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
  
  /** Validation of CSEN register block pointer reference for assert statements. */
  #define CSEN_REF_VALID(ref)   ((ref) == CSEN)
  
  /** @endcond */
  
  /*******************************************************************************
   **************************   GLOBAL FUNCTIONS   *******************************
   ******************************************************************************/
  
  /***************************************************************************//**
   * @brief
   *   Set the DM integrator initial value.
   *
   * @details
   *   Sets the initial value of the integrator(s) for the Delta Modulation (DM)
   *   converter. The initial value for the ramp-down integrator has no effect
   *   if the low-frequency attenuation was not selected by the mode initialization
   *   function @ref CSEN_InitMode().
   *
   * @note
   *   Confirm CSEN is idle before calling this function.
   *
   * @param[in] csen
   *   A pointer to the CSEN peripheral register block.
   *
   * @param[in] up
   *   An initial value for the ramp-up integrator.
   *
   * @param[in] down
   *  An initial value for the ramp-down integrator. Has no effect if low-frequency
   *  attenuation is not configured.
   ******************************************************************************/
  void CSEN_DMBaselineSet(CSEN_TypeDef *csen, uint32_t up, uint32_t down)
  {
    EFM_ASSERT(up < 0x10000);
    EFM_ASSERT(down < 0x10000);
  
    csen->DMBASELINE = (up << _CSEN_DMBASELINE_BASELINEUP_SHIFT)
                       | (down << _CSEN_DMBASELINE_BASELINEDN_SHIFT);
  }
  
  /***************************************************************************//**
   * @brief
   *   Initialize CSEN.
   *
   * @details
   *   Initializes common functionality for all measurement types. In addition,
   *   measurement mode must be configured. See @ref CSEN_InitMode().
   *
   * @note
   *   This function will stop any ongoing conversion and disable CSEN.
   *
   * @param[in] csen
   *   A pointer to the CSEN peripheral register block.
   *
   * @param[in] init
   *   A pointer to the CSEN initialization structure.
   ******************************************************************************/
  void CSEN_Init(CSEN_TypeDef *csen, const CSEN_Init_TypeDef *init)
  {
    uint32_t tmp;
  
    EFM_ASSERT(CSEN_REF_VALID(csen));
    EFM_ASSERT(init->warmUpCount < 4);
  
    /* Initialize CTRL. This will stop any conversion in progress. */
    tmp = CSEN_CTRL_STM_DEFAULT;
  
    if (init->cpAccuracyHi) {
      tmp |= CSEN_CTRL_CPACCURACY_HI;
    }
  
    if (init->localSense) {
      tmp |= _CSEN_CTRL_LOCALSENS_MASK;
    }
  
    if (init->keepWarm) {
      tmp |= CSEN_CTRL_WARMUPMODE_KEEPCSENWARM;
    }
  
    csen->CTRL = tmp;
  
    /* Initialize TIMCTRL. */
    csen->TIMCTRL = (init->warmUpCount << _CSEN_TIMCTRL_WARMUPCNT_SHIFT)
                    | (init->pcReload << _CSEN_TIMCTRL_PCTOP_SHIFT)
                    | (init->pcPrescale << _CSEN_TIMCTRL_PCPRESC_SHIFT);
  
    /* PRSSEL only has one field */
    csen->PRSSEL = init->prsSel << _CSEN_PRSSEL_PRSSEL_SHIFT;
  
    /* Set input selections for inputs 0 to 31. */
    csen->SCANINPUTSEL0 = (init->input0To7 << _CSEN_SCANINPUTSEL0_INPUT0TO7SEL_SHIFT)
                          | (init->input8To15 << _CSEN_SCANINPUTSEL0_INPUT8TO15SEL_SHIFT)
                          | (init->input16To23 << _CSEN_SCANINPUTSEL0_INPUT16TO23SEL_SHIFT)
                          | (init->input24To31 << _CSEN_SCANINPUTSEL0_INPUT24TO31SEL_SHIFT);
  
    /* Set input selections for inputs 32 to 63. */
    csen->SCANINPUTSEL1 = (init->input32To39 << _CSEN_SCANINPUTSEL1_INPUT32TO39SEL_SHIFT)
                          | (init->input40To47 << _CSEN_SCANINPUTSEL1_INPUT40TO47SEL_SHIFT)
                          | (init->input48To55 << _CSEN_SCANINPUTSEL1_INPUT48TO55SEL_SHIFT)
                          | (init->input56To63 << _CSEN_SCANINPUTSEL1_INPUT56TO63SEL_SHIFT);
  }
  
  /***************************************************************************//**
   * @brief
   *   Initialize a CSEN measurement mode.
   *
   * @details
   *   Used to configure any type of measurement mode. After the measurement
   *   has been configured, calling @ref CSEN_Enable() will enable CSEN and
   *   allow it to start a conversion from the selected trigger source. To
   *   manually start a conversion, use @ref CSEN_Start(). To check if a
   *   conversion is in progress, use @ref CSEN_IsBusy(), or alternatively
   *   use the interrupt flags returned by @ref CSEN_IntGet() to detect when
   *   a conversion is completed.
   *
   * @note
   *   This function will stop any ongoing conversion and disable CSEN.
   *
   * @param[in] csen
   *   A pointer to the CSEN peripheral register block.
   *
   * @param[in] init
   *   A pointer to the CSEN measurement mode initialization structure.
   ******************************************************************************/
  void CSEN_InitMode(CSEN_TypeDef *csen, const CSEN_InitMode_TypeDef *init)
  {
    uint32_t tmp;
  
    EFM_ASSERT(CSEN_REF_VALID(csen));
    EFM_ASSERT(init->dmIterPerCycle < 0x10);
    EFM_ASSERT(init->dmCycles < 0x10);
  
    /* Initialize CTRL. This will stop any conversion in progress.
     * These composite inputs set multiple fields. They do not need
     * to be shifted. */
    tmp = ((uint32_t)init->sampleMode
           | (uint32_t)init->convSel
           | (uint32_t)init->cmpMode);
  
    tmp |= (init->trigSel << _CSEN_CTRL_STM_SHIFT)
           | (init->accMode << _CSEN_CTRL_ACU_SHIFT)
           | (init->sarRes << _CSEN_CTRL_SARCR_SHIFT);
  
    if (init->enableDma) {
      tmp |= CSEN_CTRL_DMAEN_ENABLE;
    }
  
    if (init->sumOnly) {
      tmp |= CSEN_CTRL_DRSF_ENABLE;
    }
  
    if (init->autoGnd) {
      tmp |= CSEN_CTRL_AUTOGND_ENABLE;
    }
  
    /* Preserve the fields that were initialized by CSEN_Init(). */
    tmp |= csen->CTRL & (_CSEN_CTRL_CPACCURACY_MASK
                         | _CSEN_CTRL_LOCALSENS_MASK
                         | _CSEN_CTRL_WARMUPMODE_MASK);
  
    csen->CTRL = tmp;
  
    /* EMACTRL only has one field. */
    csen->EMACTRL = init->emaSample << _CSEN_EMACTRL_EMASAMPLE_SHIFT;
  
    /* CMPTHR only has one field. */
    csen->CMPTHR = init->cmpThr << _CSEN_CMPTHR_CMPTHR_SHIFT;
  
    /* SINGLECTRL only has one field. */
    csen->SINGLECTRL = init->singleSel << _CSEN_SINGLECTRL_SINGLESEL_SHIFT;
  
    /* Set all input enables. */
    csen->SCANMASK0 = init->inputMask0;
    csen->SCANMASK1 = init->inputMask1;
  
    /* Initialize DMCFG. */
    tmp = (init->dmRes << _CSEN_DMCFG_CRMODE_SHIFT)
          | (init->dmCycles << _CSEN_DMCFG_DMCR_SHIFT)
          | (init->dmIterPerCycle << _CSEN_DMCFG_DMR_SHIFT)
          | (init->dmDelta << _CSEN_DMCFG_DMG_SHIFT);
  
    if (init->dmFixedDelta) {
      tmp |= CSEN_DMCFG_DMGRDIS;
    }
  
    csen->DMCFG = tmp;
  
    /* Initialize ANACTRL. */
    csen->ANACTRL = (init->resetPhase << _CSEN_ANACTRL_TRSTPROG_SHIFT)
                    | (init->driveSel << _CSEN_ANACTRL_IDACIREFS_SHIFT)
                    | (init->gainSel << _CSEN_ANACTRL_IREFPROG_SHIFT);
  }
  
  /***************************************************************************//**
   * @brief
   *   Reset CSEN to same state that it was in after a hardware reset.
   *
   * @param[in] csen
   *   A pointer to the CSEN peripheral register block.
   ******************************************************************************/
  void CSEN_Reset(CSEN_TypeDef *csen)
  {
    EFM_ASSERT(CSEN_REF_VALID(csen));
  
    /* Resetting CTRL stops any conversion in progress. */
    csen->CTRL          = _CSEN_CTRL_RESETVALUE;
    csen->TIMCTRL       = _CSEN_TIMCTRL_RESETVALUE;
    csen->PRSSEL        = _CSEN_PRSSEL_RESETVALUE;
    csen->DATA          = _CSEN_DATA_RESETVALUE;
    csen->SCANMASK0     = _CSEN_SCANMASK0_RESETVALUE;
    csen->SCANINPUTSEL0 = _CSEN_SCANINPUTSEL0_RESETVALUE;
    csen->SCANMASK1     = _CSEN_SCANMASK1_RESETVALUE;
    csen->SCANINPUTSEL1 = _CSEN_SCANINPUTSEL1_RESETVALUE;
    csen->CMPTHR        = _CSEN_CMPTHR_RESETVALUE;
    csen->EMA           = _CSEN_EMA_RESETVALUE;
    csen->EMACTRL       = _CSEN_EMACTRL_RESETVALUE;
    csen->SINGLECTRL    = _CSEN_SINGLECTRL_RESETVALUE;
    csen->DMBASELINE    = _CSEN_DMBASELINE_RESETVALUE;
    csen->DMCFG         = _CSEN_DMCFG_RESETVALUE;
    csen->ANACTRL       = _CSEN_ANACTRL_RESETVALUE;
    csen->IEN           = _CSEN_IEN_RESETVALUE;
    csen->IFC           = _CSEN_IF_MASK;
  }
  
  /** @} (end addtogroup csen) */
  #endif /* defined(CSEN_COUNT) && (CSEN_COUNT > 0) */
  