Esempio n. 1
0
/***************************************************************************//**
 * @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
 *   Pointer to CSEN peripheral register block.
 *
 * @param[in] init
 *   Pointer to 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);
}
Esempio n. 2
0
__ramfunc
#endif
#endif /* !EM_MSC_RUN_FROM_FLASH */
__STATIC_INLINE MSC_Status_TypeDef
  MSC_LoadWriteData(uint32_t* data,
                    uint32_t numWords,
                    MSC_WriteStrategy_Typedef writeStrategy)
{
  uint32_t timeOut;
  uint32_t wordIndex;
  uint32_t wordsPerDataPhase;
  MSC_Status_TypeDef retval = mscReturnOk;

#if defined(_MSC_WRITECTRL_LPWRITE_MASK) && defined(_MSC_WRITECTRL_WDOUBLE_MASK)
  /* If LPWRITE (Low Power Write) is NOT enabled, set WDOUBLE (Write Double word) */
  if (!(MSC->WRITECTRL & MSC_WRITECTRL_LPWRITE))
  {
    /* If the number of words to be written are odd, we need to align by writing
       a single word first, before setting the WDOUBLE bit. */
    if (numWords & 0x1)
    {
      /* Wait for the MSC to become ready for the next word. */
      timeOut = MSC_PROGRAM_TIMEOUT;
      while ((!(MSC->STATUS & MSC_STATUS_WDATAREADY)) && (timeOut != 0))
      {
        timeOut--;
      }
      /* Check for timeout */
      if (timeOut == 0)
      {
        return mscReturnTimeOut;
      }
      /* Clear double word option, in order to write the initial single word. */
      MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
      /* Write first data word. */
      MSC->WDATA = *data++;
      MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;

      /* Wait for the operation to finish. It may be required to change the WDOUBLE
         config after the initial write. It should not be changed while BUSY. */
      timeOut = MSC_PROGRAM_TIMEOUT;
      while((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0))
      {
        timeOut--;
      }
      /* Check for timeout */
      if (timeOut == 0)
      {
        return mscReturnTimeOut;
      }
      /* Subtract this initial odd word for the write loop below */
      numWords -= 1;
      retval = mscReturnOk;
    }
    /* Now we can set the double word option in order to write two words per
       data phase. */
    MSC->WRITECTRL |= MSC_WRITECTRL_WDOUBLE;
    wordsPerDataPhase = 2;
  }
  else
#endif /* defined( _MSC_WRITECTRL_LPWRITE_MASK ) && defined( _MSC_WRITECTRL_WDOUBLE_MASK ) */
  {
    wordsPerDataPhase = 1;
  }

  /* Write the rest as double word write if wordsPerDataPhase == 2 */
  if (numWords > 0)
  {
    /**** Write strategy: mscWriteIntSafe ****/
    if (writeStrategy == mscWriteIntSafe)
    {
      /* Requires a system core clock at 1MHz or higher */
      EFM_ASSERT(SystemCoreClockGet() >= 1000000);
      wordIndex = 0;
      while(wordIndex < numWords)
      {
        MSC->WDATA = *data++;
        wordIndex++;
        if (wordsPerDataPhase == 2)
        {
          while (!(MSC->STATUS & MSC_STATUS_WDATAREADY));
          MSC->WDATA = *data++;
          wordIndex++;
        }
        MSC->WRITECMD = MSC_WRITECMD_WRITEONCE;

        /* Wait for the transaction to finish. */
        timeOut = MSC_PROGRAM_TIMEOUT;
        while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0))
        {
          timeOut--;
        }
        /* Check for timeout */
        if (timeOut == 0)
        {
          retval = mscReturnTimeOut;
          break;
        }
#if defined( _EFM32_GECKO_FAMILY )
        MSC->ADDRB += 4;
        MSC->WRITECMD = MSC_WRITECMD_LADDRIM;
#endif
      }
    }

    /**** Write strategy: mscWriteFast ****/
    else
    {
#if defined( _EFM32_GECKO_FAMILY )
      /* Gecko does not have auto-increment of ADDR. */
      EFM_ASSERT(0);
#else
      /* Requires a system core clock at 14MHz or higher */
      EFM_ASSERT(SystemCoreClockGet() >= 14000000);

      wordIndex = 0;
      INT_Disable();
      while(wordIndex < numWords)
      {
        /* Wait for the MSC to be ready for the next word. */
        while (!(MSC->STATUS & MSC_STATUS_WDATAREADY))
        {
          /* If the write to MSC->WDATA below missed the 30us timeout and the
             following MSC_WRITECMD_WRITETRIG command arrived while
             MSC_STATUS_BUSY is 1, then the MSC_WRITECMD_WRITETRIG could be ignored by
             the MSC. In this case, MSC_STATUS_WORDTIMEOUT is set to 1
             and MSC_STATUS_BUSY is 0. A new trigger is therefore needed here to
             complete write of data in MSC->WDATA.
             If WDATAREADY became high since entry into this loop, exit and continue
             to the next WDATA write.
          */
          if ((MSC->STATUS & (MSC_STATUS_WORDTIMEOUT
                              | MSC_STATUS_BUSY
                              | MSC_STATUS_WDATAREADY))
              == MSC_STATUS_WORDTIMEOUT)
          {
            MSC->WRITECMD = MSC_WRITECMD_WRITETRIG;
          }
        }
        MSC->WDATA = *data;
        if ((wordsPerDataPhase == 1)
            || ((wordsPerDataPhase == 2) && (wordIndex & 0x1)))
        {
          MSC->WRITECMD = MSC_WRITECMD_WRITETRIG;
        }
        data++;
        wordIndex++;
      }
      INT_Enable();

      /* Wait for the transaction to finish. */
      timeOut = MSC_PROGRAM_TIMEOUT;
      while ((MSC->STATUS & MSC_STATUS_BUSY) && (timeOut != 0))
      {
        timeOut--;
      }
      /* Check for timeout */
      if (timeOut == 0)
      {
        retval = mscReturnTimeOut;
      }
#endif
    } /* writeStrategy */
  }

#if defined( _MSC_WRITECTRL_WDOUBLE_MASK )
  /* Clear double word option, which should not be left on when returning. */
  MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
#endif

  return retval;
}
Esempio n. 3
0
/***************************************************************************//**
 * @brief
 *   Unlock the TIMER so that writing to locked registers again is possible.
 *
 * @param[in] timer
 *   Pointer to TIMER peripheral register block.
 ******************************************************************************/
void TIMER_Unlock(TIMER_TypeDef *timer)
{
  EFM_ASSERT(TIMER_REF_VALID(timer));

  timer->DTLOCK = TIMER_DTLOCK_LOCKKEY_UNLOCK;
}
Esempio n. 4
0
/***************************************************************************//**
 * @brief
 *   Enable/disable I2C.
 *
 * @note
 *   After enabling the I2C (from being disabled), the I2C is in BUSY state.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] enable
 *   true to enable counting, false to disable.
 ******************************************************************************/
void I2C_Enable(I2C_TypeDef *i2c, bool enable)
{
  EFM_ASSERT(I2C_REF_VALID(i2c));

  BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, enable);
}
Esempio n. 5
0
/***************************************************************************//**
 * @brief
 *   Enable/disable I2C.
 *
 * @note
 *   After enabling the I2C (from being disabled), the I2C is in BUSY state.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] enable
 *   true to enable counting, false to disable.
 ******************************************************************************/
void I2C_Enable(I2C_TypeDef *i2c, bool enable)
{
    EFM_ASSERT(I2C_REF_VALID(i2c));

    BITBAND_Peripheral(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, (unsigned int)enable);
}
Esempio n. 6
0
/***************************************************************************//**
 * @brief
 *   Set bits GPIO data out register to 1.
 *
 * @note
 *   In order for the setting to take effect on the respective output pads, the
 *   pins must have been configured properly. If not, it will take effect
 *   whenever the pin has been properly configured.
 *
 * @param[in] port
 *   The GPIO port to access.
 *
 * @param[in] pins
 *   Bit mask for bits to set to 1 in DOUT register.
 ******************************************************************************/
void GPIO_PortOutSet(GPIO_Port_TypeDef port, uint32_t pins)
{
  EFM_ASSERT(GPIO_PORT_VALID(port));

  GPIO->P[port].DOUTSET = pins & _GPIO_P_DOUTSET_DOUTSET_MASK;
}
Esempio n. 7
0
/***************************************************************************//**
 * @brief
 *   Toggle a single pin in GPIO port data out register.
 *
 * @note
 *   In order for the setting to take effect on the output pad, the pin must
 *   have been configured properly. If not, it will take effect whenever the
 *   pin has been properly configured.
 *
 * @param[in] port
 *   The GPIO port to access.
 *
 * @param[in] pins
 *   Bitmask with pins to toggle.
 ******************************************************************************/
void GPIO_PortOutToggle(GPIO_Port_TypeDef port, uint32_t pins)
{
  EFM_ASSERT(GPIO_PORT_VALID(port));

  GPIO->P[port].DOUTTGL = pins & _GPIO_P_DOUTTGL_DOUTTGL_MASK;
}
Esempio n. 8
0
/***************************************************************************//**
 * @brief
 *   Configure USART/UART operating in asynchronous mode to use a given
 *   baudrate (or as close as possible to specified baudrate).
 *
 * @param[in] usart
 *   Pointer to USART/UART peripheral register block.
 *
 * @param[in] refFreq
 *   USART/UART reference clock frequency in Hz that will be used. If set to 0,
 *   the currently configured reference clock is assumed.
 *
 * @param[in] baudrate
 *   Baudrate to try to achieve for USART/UART.
 *
 * @param[in] ovs
 *   Oversampling to be used. Normal is 16x oversampling, but lower oversampling
 *   may be used to achieve higher rates or better baudrate accuracy in some
 *   cases. Notice that lower oversampling frequency makes channel more
 *   vulnerable to bit faults during reception due to clock inaccuracies
 *   compared to link partner.
 ******************************************************************************/
void USART_BaudrateAsyncSet(USART_TypeDef *usart,
                            uint32_t refFreq,
                            uint32_t baudrate,
                            USART_OVS_TypeDef ovs)
{
  uint32_t clkdiv;
  uint32_t oversample;

  /* Inhibit divide by 0 */
  EFM_ASSERT(baudrate);

  /*
   * We want to use integer division to avoid forcing in float division
   * utils, and yet keep rounding effect errors to a minimum.
   *
   * CLKDIV in asynchronous mode is given by:
   *
   * CLKDIV = 256 * (fHFPERCLK/(oversample * br) - 1)
   * or
   * CLKDIV = (256 * fHFPERCLK)/(oversample * br) - 256
   *
   * The basic problem with integer division in the above formula is that
   * the dividend (256 * fHFPERCLK) may become higher than max 32 bit
   * integer. Yet, we want to evaluate dividend first before dividing in
   * order to get as small rounding effects as possible. We do not want
   * to make too harsh restrictions on max fHFPERCLK value either.
   *
   * One can possibly factorize 256 and oversample/br. However,
   * since the last 6 bits of CLKDIV are don't care, we can base our
   * integer arithmetic on the below formula
   *
   * CLKDIV / 64 = (4 * fHFPERCLK)/(oversample * br) - 4
   *
   * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK
   * up to 1GHz without overflowing a 32 bit value!
   */

  /* HFPERCLK used to clock all USART/UART peripheral modules */
  if (!refFreq)
  {
    refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
  }

  /* Map oversampling */
  switch (ovs)
  {
  case USART_CTRL_OVS_X16:
    EFM_ASSERT(baudrate <= (refFreq / 16));
    oversample = 16;
    break;

  case USART_CTRL_OVS_X8:
    EFM_ASSERT(baudrate <= (refFreq / 8));
    oversample = 8;
    break;

  case USART_CTRL_OVS_X6:
    EFM_ASSERT(baudrate <= (refFreq / 6));
    oversample = 6;
    break;

  case USART_CTRL_OVS_X4:
    EFM_ASSERT(baudrate <= (refFreq / 4));
    oversample = 4;
    break;

  default:
    /* Invalid input */
    EFM_ASSERT(0);
    return;
  }

  /* Calculate and set CLKDIV with fractional bits.
   * The addend (oversample*baudrate)/2 in the first line is to round the
   * divisor up by half the divisor before the division in order to reduce the
   * integer division error, which consequently results in a higher baudrate
   * than desired. */
  clkdiv  = 4 * refFreq + (oversample * baudrate) / 2;
  clkdiv /= (oversample * baudrate);
  clkdiv -= 4;
  clkdiv *= 64;

  /* Verify that resulting clock divider is within limits */
  EFM_ASSERT(clkdiv <= _USART_CLKDIV_MASK);

  /* If EFM_ASSERT is not enabled, make sure we don't write to reserved bits */
  clkdiv &= _USART_CLKDIV_MASK;

  usart->CTRL  &= ~_USART_CTRL_OVS_MASK;
  usart->CTRL  |= ovs;
  usart->CLKDIV = clkdiv;
}
Esempio n. 9
0
/***************************************************************************//**
 * @brief
 *   Enable or disable a LDMA channel request.
 *
 * @details
 *   Use this function to enable or disable a LDMA channel request. This will
 *   prevent the LDMA from proceeding after its current transaction if disabled.
 *
 * @param[in] channel
 *   LDMA channel to enable or disable requests on.
 *
 * @param[in] enable
 *   If 'true' request will be enabled. If 'false' request will be disabled.
 ******************************************************************************/
void LDMA_EnableChannelRequest( int ch, bool enable)
{
  EFM_ASSERT( ch < DMA_CHAN_COUNT );

  BUS_RegBitWrite (&LDMA->REQDIS, ch, !enable);
}
Esempio n. 10
0
/***************************************************************************//**
 * @brief
 *   Configure bias level for a specific segment line for Direct Segment Control
 *
 * @note
 *   When DSC is active, each configuration takes up 4 bits in the Segment
 *   Registers (SEGD0L/SEGD1H) which defines bias level.
 *   For optimal use of this feature, the entire SEGD-registers should be set
 *   at once in a optimized routine, so this function is mainly here to
 *   demonstrate how to correctly configure the bias levels, and should be used
 *   with care.
 *
 * @param[in] segmentLine
 *   Segment line number
 *
 * @param[in] biasLevel
 *   Bias configuration level, 0-4. This value must be within the constraint
 *   defined by the LCD_DISPCTRL bias setting, see Reference Manual/Datasheet
 ******************************************************************************/
void LCD_BiasSegmentSet(int segmentLine, int biasLevel)
{
  int               biasRegister;
  int               bitShift;
  volatile uint32_t *segmentRegister;

#if defined(_EFM32_TINY_FAMILY)
  EFM_ASSERT(segmentLine < 20);
#endif
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  EFM_ASSERT(segmentLine < 40);
#endif
#if defined(_EFM32_TINY_FAMILY)
  /* Bias config for 8 segment lines per SEGDnL register */
  biasRegister = segmentLine / 8;
  bitShift     = (segmentLine % 8) * 4;

  switch (biasRegister)
  {
  case 0:
    segmentRegister = &LCD->SEGD0L;
    break;
  case 1:
    segmentRegister = &LCD->SEGD1L;
    break;
  case 2:
    segmentRegister = &LCD->SEGD2L;
    break;
  case 3:
    segmentRegister = &LCD->SEGD3L;
    break;
  default:
    segmentRegister = (uint32_t *)0x00000000;
    EFM_ASSERT(0);
    break;
  }
#endif
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) 
  /* Bias config for 10 segment lines per SEGDn L+H registers */
  biasRegister = segmentLine / 10;
  bitShift     = (segmentLine % 10) * 4;

  switch (biasRegister)
  {
  case 0:
    if (bitShift < 32)
    {
      segmentRegister = &LCD->SEGD0L;
    }
    else
    {
      segmentRegister = &LCD->SEGD0H;
      bitShift       -= 32;
    }
    break;
  case 1:
    if (bitShift < 32)
    {
      segmentRegister = &LCD->SEGD1L;
    }
    else
    {
      segmentRegister = &LCD->SEGD1H;
      bitShift       -= 32;
    }
    break;
  case 2:
    if (bitShift < 32)
    {
      segmentRegister = &LCD->SEGD2L;
    }
    else
    {
      segmentRegister = &LCD->SEGD1H;
      bitShift       -= 32;
    }
    break;
  case 3:
    if (bitShift < 32)
    {
      segmentRegister = &LCD->SEGD3L;
    }
    else
    {
      segmentRegister = &LCD->SEGD3H;
      bitShift       -= 32;
    }
    break;
  default:
    segmentRegister = (uint32_t *)0x00000000;
    EFM_ASSERT(0);
    break;
  }
#endif

  /* Configure new bias setting */
  *segmentRegister = (*segmentRegister & ~(0xF << bitShift)) | (biasLevel << bitShift);
}
Esempio n. 11
0
/***************************************************************************//**
 * @brief
 *   Configure and enable Voltage Comparator
 *
 * @param[in] vcmpInit
 *   VCMP Initialization structure
 ******************************************************************************/
void VCMP_Init(const VCMP_Init_TypeDef *vcmpInit)
{
  /* Verify input */
  EFM_ASSERT((vcmpInit->inactive == 0) || (vcmpInit->inactive == 1));
  EFM_ASSERT((vcmpInit->biasProg >= 0) && (vcmpInit->biasProg < 16));

  /* Configure Half Bias setting */
  if (vcmpInit->halfBias)
  {
    VCMP->CTRL |= VCMP_CTRL_HALFBIAS;
  }
  else
  {
    VCMP->CTRL &= ~(VCMP_CTRL_HALFBIAS);
  }

  /* Configure bias prog */
  VCMP->CTRL &= ~(_VCMP_CTRL_BIASPROG_MASK);
  VCMP->CTRL |= (vcmpInit->biasProg << _VCMP_CTRL_BIASPROG_SHIFT);

  /* Configure sense for falling edge */
  if (vcmpInit->irqFalling)
  {
    VCMP->CTRL |= VCMP_CTRL_IFALL;
  }
  else
  {
    VCMP->CTRL &= ~(VCMP_CTRL_IFALL);
  }

  /* Configure sense for rising edge */
  if (vcmpInit->irqRising)
  {
    VCMP->CTRL |= VCMP_CTRL_IRISE;
  }
  else
  {
    VCMP->CTRL &= ~(VCMP_CTRL_IRISE);
  }

  /* Configure warm-up time */
  VCMP->CTRL &= ~(_VCMP_CTRL_WARMTIME_MASK);
  VCMP->CTRL |= (vcmpInit->warmup << _VCMP_CTRL_WARMTIME_SHIFT);

  /* Configure hysteresis */
  switch (vcmpInit->hyst)
  {
    case vcmpHyst20mV:
      VCMP->CTRL |= VCMP_CTRL_HYSTEN;
      break;
    case vcmpHystNone:
      VCMP->CTRL &= ~(VCMP_CTRL_HYSTEN);
      break;
    default:
      break;
  }

  /* Configure inactive output value */
  VCMP->CTRL |= (vcmpInit->inactive << _VCMP_CTRL_INACTVAL_SHIFT);

  /* Configure trigger level */
  VCMP_TriggerSet(vcmpInit->triggerLevel);

  /* Enable or disable VCMP */
  if (vcmpInit->enable)
  {
    VCMP->CTRL |= VCMP_CTRL_EN;
  }
  else
  {
    VCMP->CTRL &= ~(VCMP_CTRL_EN);
  }

  /* If Low Power Reference is enabled, wait until VCMP is ready */
  /* before enabling it, see reference manual for deatils        */
  /* Configuring Low Power Ref without enable has no effect      */
  if(vcmpInit->lowPowerRef && vcmpInit->enable)
  {
    /* Poll for VCMP ready */
    while(!VCMP_Ready());
    VCMP_LowPowerRefSet(vcmpInit->lowPowerRef);
  }

  /* Clear edge interrupt */
  VCMP_IntClear(VCMP_IF_EDGE);
}
Esempio n. 12
0
/***************************************************************************//**
 * @brief
 *   Updated the high (32-39) segments on a given COM-line in one operation
 *
 * @param[in] com
 *   Which COM line to update
 *
 * @param[in] mask
 *   Bit mask for segments 32-39
 *
 * @param[in] bits
 *   Bit pattern for segments 32-39
 ******************************************************************************/
void LCD_SegmentSetHigh(int com, uint32_t mask, uint32_t bits)
{
  uint32_t segData;

#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  EFM_ASSERT(com < 8);
#endif
#if defined(_EFM32_GECKO_FAMILY)
  EFM_ASSERT(com < 4);
#endif

  /* Maximum number of com lines */
  switch (com)
  {
  case 0:
    segData     = LCD->SEGD0H;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD0H = segData;
    break;
  case 1:
    segData     = LCD->SEGD1H;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD1H = segData;
    break;
  case 2:
    segData     = LCD->SEGD2H;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD2H = segData;
    break;
  case 3:
    segData     = LCD->SEGD3H;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD3H = segData;
    break;
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  case 4:
    segData     = LCD->SEGD4H;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD4H = segData;
    break;
#endif
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  case 5:
    segData     = LCD->SEGD5H;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD5H = segData;
    break;
#endif
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  case 6:
    segData     = LCD->SEGD6H;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD6H = segData;
    break;
#endif
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  case 7:
    segData     = LCD->SEGD7H;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD7H = segData;
    break;
#endif
  default:
    break;
  }
}
Esempio n. 13
0
/***************************************************************************//**
 * @brief
 *   Updates the 0-31 lowest segments on a given COM-line in one operation,
 *   according to bit mask
 *
 * @param[in] com
 *   Which COM line to update
 *
 * @param[in] mask
 *   Bit mask for segments 0-31
 *
 * @param[in] bits
 *   Bit pattern for segments 0-31
 ******************************************************************************/
void LCD_SegmentSetLow(int com, uint32_t mask, uint32_t bits)
{
  uint32_t segData;

  /* Maximum number of com lines */
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  EFM_ASSERT(com < 8);
#else
  /* Gecko Family supports up to 4 COM lines */
  EFM_ASSERT(com < 4);
#endif

  switch (com)
  {
  case 0:
    segData     = LCD->SEGD0L;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD0L = segData;
    break;
  case 1:
    segData     = LCD->SEGD1L;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD1L = segData;
    break;
  case 2:
    segData     = LCD->SEGD2L;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD2L = segData;
    break;
  case 3:
    segData     = LCD->SEGD3L;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD3L = segData;
    break;
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  case 4:
    segData     = LCD->SEGD4L;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD4L = segData;
    break;
#endif
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY) 
  case 5:
    segData     = LCD->SEGD5L;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD5L = segData;
    break;
#endif
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  case 6:
    segData     = LCD->SEGD6L;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD6L = segData;
    break;
#endif
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  case 7:
    segData     = LCD->SEGD7L;
    segData    &= ~(mask);
    segData    |= (mask & bits);
    LCD->SEGD7L = segData;
    break;
#endif
  default:
    EFM_ASSERT(0);
    break;
  }
}
Esempio n. 14
0
/***************************************************************************//**
 * @brief
 *   Turn on or clear a segment
 *
 * @note
 *    On Gecko Family, max configuration is (COM-lines x Segment-Lines) 4x40
 *    On Tiny Family, max configuration is 8x20 or 4x24
 *    On Giant Family, max configuration is 8x36 or 4x40
 *
 * @param[in] com
 *   COM line to change
 *
 * @param[in] bit
 *   Bit index of which field to change
 *
 * @param[in] enable
 *   When true will set segment, when false will clear segment
 ******************************************************************************/
void LCD_SegmentSet(int com, int bit, bool enable)
{
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  /* Tiny and Giant Family supports up to 8 COM lines */
  EFM_ASSERT(com < 8);
#else
  /* Gecko Family supports up to 4 COM lines */
  EFM_ASSERT(com < 4);
#endif

#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  EFM_ASSERT(bit < 40);
#else
  /* Tiny Gecko Family supports only "low" segment registers */
  EFM_ASSERT(bit < 32);
#endif

  /* Use bitband access for atomic bit set/clear of segment */
  switch (com)
  {
  case 0:
    if (bit < 32)
    {
      BITBAND_Peripheral(&(LCD->SEGD0L), bit, (unsigned int)enable);
    }
#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    else
    {
      bit -= 32;
      BITBAND_Peripheral(&(LCD->SEGD0H), bit, (unsigned int)enable);
    }
#endif
    break;
  case 1:
    if (bit < 32)
    {
      BITBAND_Peripheral(&(LCD->SEGD1L), bit, (unsigned int)enable);
    }
#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    else
    {
      bit -= 32;
      BITBAND_Peripheral(&(LCD->SEGD1H), bit, (unsigned int)enable);
    }
#endif
    break;
  case 2:
    if (bit < 32)
    {
      BITBAND_Peripheral(&(LCD->SEGD2L), bit, (unsigned int)enable);
    }
#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    else
    {
      bit -= 32;
      BITBAND_Peripheral(&(LCD->SEGD2H), bit, (unsigned int)enable);
    }
#endif
    break;
  case 3:
    if (bit < 32)
    {
      BITBAND_Peripheral(&(LCD->SEGD3L), bit, (unsigned int)enable);
    }
#if defined(_EFM32_GECKO_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    else
    {
      bit -= 32;
      BITBAND_Peripheral(&(LCD->SEGD3H), bit, (unsigned int)enable);
    }
#endif
    break;
  case 4:
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    if (bit < 32)
    {
      BITBAND_Peripheral(&(LCD->SEGD4L), bit, (unsigned int)enable);
    }
#endif
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    else
    {
      bit -= 32;
      BITBAND_Peripheral(&(LCD->SEGD4H), bit, (unsigned int)enable);
    }
#endif
    break;
  case 5:
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    if (bit < 32)
    {
      BITBAND_Peripheral(&(LCD->SEGD5L), bit, (unsigned int)enable);
    }
#endif
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    else
    {
      bit -= 32;
      BITBAND_Peripheral(&(LCD->SEGD5H), bit, (unsigned int)enable);
    }
#endif
    break;
  case 6:
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    if (bit < 32)
    {
      BITBAND_Peripheral(&(LCD->SEGD6L), bit, (unsigned int)enable);
    }
#endif
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    else
    {
      bit -= 32;
      BITBAND_Peripheral(&(LCD->SEGD6H), bit, (unsigned int)enable);
    }
#endif
    break;
  case 7:
#if defined(_EFM32_TINY_FAMILY) || defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    if (bit < 32)
    {
      BITBAND_Peripheral(&(LCD->SEGD7L), bit, (unsigned int)enable);
    }
#endif
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    else
    {
      bit -= 32;
      BITBAND_Peripheral(&(LCD->SEGD7H), bit, (unsigned int)enable);
    }
#endif
    break;

  default:
    EFM_ASSERT(0);
    break;
  }
}
Esempio n. 15
0
/***************************************************************************//**
 * @brief
 *   Set bits in DOUT register for a port to 0.
 *
 * @note
 *   In order for the setting to take effect on the output pad, the pin must
 *   have been configured properly. If not, it will take effect whenever the
 *   pin has been properly configured.
 *
 * @param[in] port
 *   The GPIO port to access.
 *
 * @param[in] pins
 *   Bit mask for bits to clear in DOUT register.
 ******************************************************************************/
void GPIO_PortOutClear(GPIO_Port_TypeDef port, uint32_t pins)
{
  EFM_ASSERT(GPIO_PORT_VALID(port));

  GPIO->P[port].DOUTCLR = pins & _GPIO_P_DOUTCLR_DOUTCLR_MASK;
}
Esempio n. 16
0
/***************************************************************************//**
 * @brief
 *   Start a DMA transfer.
 *
 * @param[in] ch
 *   DMA channel.
 *
 * @param[in] transfer
 *   Initialization structure used to configure the transfer.
 *
 * @param[in] descriptor
 *   Transfer descriptor, can be an array of descriptors linked together.
 ******************************************************************************/
void LDMA_StartTransfer(  int ch,
                          LDMA_TransferCfg_t *transfer,
                          LDMA_Descriptor_t  *descriptor )
{
  uint32_t tmp;
  uint32_t chMask = 1 << ch;

  EFM_ASSERT( ch < DMA_CHAN_COUNT );
  EFM_ASSERT( transfer != NULL );
  EFM_ASSERT( !( transfer->ldmaReqSel & ~_LDMA_CH_REQSEL_MASK ) );

  EFM_ASSERT( !( ( transfer->ldmaCtrlSyncPrsClrOff << _LDMA_CTRL_SYNCPRSCLREN_SHIFT )
                 & ~_LDMA_CTRL_SYNCPRSCLREN_MASK ) );
  EFM_ASSERT( !( ( transfer->ldmaCtrlSyncPrsClrOn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT )
                 & ~_LDMA_CTRL_SYNCPRSCLREN_MASK ) );
  EFM_ASSERT( !( ( transfer->ldmaCtrlSyncPrsSetOff << _LDMA_CTRL_SYNCPRSSETEN_SHIFT )
                 & ~_LDMA_CTRL_SYNCPRSSETEN_MASK ) );
  EFM_ASSERT( !( ( transfer->ldmaCtrlSyncPrsSetOn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT  )
                 & ~_LDMA_CTRL_SYNCPRSSETEN_MASK ) );

  EFM_ASSERT( !( ( transfer->ldmaCfgArbSlots << _LDMA_CH_CFG_ARBSLOTS_SHIFT )
                 & ~_LDMA_CH_CFG_ARBSLOTS_MASK ) );
  EFM_ASSERT( !( ( transfer->ldmaCfgSrcIncSign << _LDMA_CH_CFG_SRCINCSIGN_SHIFT )
                 & ~_LDMA_CH_CFG_SRCINCSIGN_MASK ) );
  EFM_ASSERT( !( ( transfer->ldmaCfgDstIncSign << _LDMA_CH_CFG_DSTINCSIGN_SHIFT )
                 & ~_LDMA_CH_CFG_DSTINCSIGN_MASK ) );
  EFM_ASSERT( !( ( transfer->ldmaLoopCnt << _LDMA_CH_LOOP_LOOPCNT_SHIFT )
                 & ~_LDMA_CH_LOOP_LOOPCNT_MASK ) );

  LDMA->CH[ ch ].REQSEL = transfer->ldmaReqSel;

  LDMA->CH[ ch ].LOOP =
    (   transfer->ldmaLoopCnt       << _LDMA_CH_LOOP_LOOPCNT_SHIFT     );

  LDMA->CH[ ch ].CFG =
    ( transfer->ldmaCfgArbSlots     << _LDMA_CH_CFG_ARBSLOTS_SHIFT     )
    | ( transfer->ldmaCfgSrcIncSign << _LDMA_CH_CFG_SRCINCSIGN_SHIFT   )
    | ( transfer->ldmaCfgDstIncSign << _LDMA_CH_CFG_DSTINCSIGN_SHIFT   );

  /* Set descriptor address. */
  LDMA->CH[ ch ].LINK = (uint32_t)descriptor & _LDMA_CH_LINK_LINKADDR_MASK;

  /* Clear pending channel interrupt. */
  LDMA->IFC = chMask;

  /* Critical region. */
  INT_Disable();

  /* Enable channel interrupt. */
  LDMA->IEN |= chMask;

  if ( transfer->ldmaReqDis )
  {
    LDMA->REQDIS |= chMask;
  }

  if ( transfer->ldmaDbgHalt )
  {
    LDMA->DBGHALT |= chMask;
  }

  tmp = LDMA->CTRL;

  if ( transfer->ldmaCtrlSyncPrsClrOff )
  {
    tmp &= ~_LDMA_CTRL_SYNCPRSCLREN_MASK
           | (~transfer->ldmaCtrlSyncPrsClrOff << _LDMA_CTRL_SYNCPRSCLREN_SHIFT);
  }

  if ( transfer->ldmaCtrlSyncPrsClrOn )
  {
    tmp |= transfer->ldmaCtrlSyncPrsClrOn << _LDMA_CTRL_SYNCPRSCLREN_SHIFT;
  }

  if ( transfer->ldmaCtrlSyncPrsSetOff )
  {
    tmp &= ~_LDMA_CTRL_SYNCPRSSETEN_MASK
           | (~transfer->ldmaCtrlSyncPrsSetOff << _LDMA_CTRL_SYNCPRSSETEN_SHIFT);
  }

  if ( transfer->ldmaCtrlSyncPrsSetOn )
  {
    tmp |= transfer->ldmaCtrlSyncPrsSetOn << _LDMA_CTRL_SYNCPRSSETEN_SHIFT;
  }

  LDMA->CTRL = tmp;

  BUS_RegMaskedClear(&LDMA->CHDONE, chMask);  /* Clear the done flag.     */
  LDMA->LINKLOAD = chMask;      /* Start transfer by loading descriptor.  */

  /* Critical region end. */
  INT_Enable();
}
Esempio n. 17
0
/***************************************************************************//**
 * @brief
 *   Get current setting for a GPIO port data out register.
 *
 * @param[in] port
 *   The GPIO port to access.
 *
 * @return
 *   The data out setting for the requested port.
 ******************************************************************************/
uint32_t GPIO_PortOutGet(GPIO_Port_TypeDef port)
{
  EFM_ASSERT(GPIO_PORT_VALID(port));

  return(GPIO->P[port].DOUT & _GPIO_P_DOUT_DOUT_MASK);
}
Esempio n. 18
0
/***************************************************************************//**
 * @brief
 *   Configure a single LESENSE sensor channel.
 *
 * @details
 *   This function configures a single sensor channel of the LESENSE interface.
 *   Please refer to the configuration parameter type definition
 *   (LESENSE_ChDesc_TypeDef) for more details.
 *
 * @note
 *   This function has been designed to minimize the effects of sensor channel
 *   reconfiguration while LESENSE is in operation, however one shall be aware
 *   of these effects and the right timing of calling this function.
 *   Parameter @p useAltEx must be true in the channel configuration in order to
 *   use alternate excitation pins.
 *
 * @param[in] confCh
 *   Configuration structure for a single LESENSE sensor channel.
 *
 * @param[in] chIdx
 *   Channel index to configure (0-15).
 ******************************************************************************/
void LESENSE_ChannelConfig(LESENSE_ChDesc_TypeDef const *confCh,
                           uint32_t const chIdx)
{
  uint32_t tmp; /* Service variable. */


  /* Sanity check of configuration parameters */
  EFM_ASSERT(chIdx < 16U);
  EFM_ASSERT(confCh->exTime < 64U);
  EFM_ASSERT(confCh->sampleDelay < 128U);
  EFM_ASSERT(confCh->measDelay < 128U);
  /* Not a complete assert, as the max. value of acmpThres depends on other
   * configuration parameters, check the parameter description of acmpThres for
   * for more details! */
  EFM_ASSERT(confCh->acmpThres < 4096U);
  EFM_ASSERT(!(confCh->chPinExMode == lesenseChPinExDACOut &&
               (chIdx != 2U) && (chIdx != 3U) && (chIdx != 4U) && (chIdx != 5U)));
  EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh1 &&
               ((chIdx != 12U) && (chIdx != 13U) && (chIdx != 14U) && (chIdx != 15U))));
  EFM_ASSERT(!(confCh->chPinIdleMode == lesenseChPinIdleDACCh0 &&
               ((chIdx != 0U) && (chIdx != 1U) && (chIdx != 2U) && (chIdx != 3U))));


  /* Configure chIdx setup in LESENSE idle phase.
   * Read-modify-write in order to support reconfiguration during LESENSE
   * operation. */
  tmp               = (LESENSE->IDLECONF & ~((uint32_t)0x3UL << (chIdx * 2UL)));
  tmp              |= ((uint32_t)confCh->chPinIdleMode << (chIdx * 2UL));
  LESENSE->IDLECONF = tmp;

  /* Channel specific timing configuration on scan channel chIdx.
   * Set excitation time, sampling delay, measurement delay. */
  LESENSE_ChannelTimingSet(chIdx,
                           (uint32_t)confCh->exTime,
                           (uint32_t)confCh->sampleDelay,
                           (uint32_t)confCh->measDelay);

  /* Channel specific configuration of clocks, sample mode, excitation pin mode
   * alternate excitation usage and interrupt mode on scan channel chIdx in
   * LESENSE_CHchIdx_INTERACT. */
  LESENSE->CH[chIdx].INTERACT = ((uint32_t)confCh->exClk << 
                                 _LESENSE_CH_INTERACT_EXCLK_SHIFT) |
                                ((uint32_t)confCh->sampleClk <<
                                 _LESENSE_CH_INTERACT_SAMPLECLK_SHIFT) |
                                (uint32_t)confCh->sampleMode |
                                (uint32_t)confCh->intMode |
                                (uint32_t)confCh->chPinExMode |
                                ((uint32_t)confCh->useAltEx <<
                                 _LESENSE_CH_INTERACT_ALTEX_SHIFT);

  /* Configure channel specific counter comparison mode, optional result
   * forwarding to decoder, optional counter value storing and optional result
   * inverting on scan channel chIdx in LESENSE_CHchIdx_EVAL. */
  LESENSE->CH[chIdx].EVAL = (uint32_t)confCh->compMode |
                            ((uint32_t)confCh->shiftRes <<
                             _LESENSE_CH_EVAL_DECODE_SHIFT) |
                            ((uint32_t)confCh->storeCntRes <<
                             _LESENSE_CH_EVAL_STRSAMPLE_SHIFT) |
                            ((uint32_t)confCh->invRes <<
                             _LESENSE_CH_EVAL_SCANRESINV_SHIFT);

  /* Configure analog comparator (ACMP) threshold and decision threshold for
   * counter separately with the function provided for that. */
  LESENSE_ChannelThresSet(chIdx,
                         (uint32_t)confCh->acmpThres,
                         (uint32_t)confCh->cntThres);

  /* Enable/disable interrupts on channel.
   * Note: BITBAND_Peripheral() function is used for setting/clearing single
   * bit peripheral register bitfields. Read the function description in
   * efm32_bitband.h for more details. */
  BITBAND_Peripheral(&(LESENSE->IEN),
                     (uint32_t)chIdx,
                     (uint32_t)confCh->enaInt);

  /* Enable/disable CHchIdx pin. */
  BITBAND_Peripheral(&(LESENSE->ROUTE),
                     (uint32_t)chIdx,
                     (uint32_t)confCh->enaPin);

  /* Enable/disable scan channel chIdx. */
  BITBAND_Peripheral(&(LESENSE->CHEN),
                     (uint32_t)chIdx,
                     (uint32_t)confCh->enaScanCh);
}
Esempio n. 19
0
/***************************************************************************//**
 * @brief
 *   Set GPIO port data out register.
 *
 * @note
 *   In order for the setting to take effect on the respective output pads, the
 *   pins must have been configured properly. If not, it will take effect
 *   whenever the pin has been properly configured.
 *
 * @param[in] port
 *   The GPIO port to access.
 *
 * @param[in] val
 *   Value to write to port data out register.
 *
 * @param[in] mask
 *   Mask indicating which bits to modify.
 ******************************************************************************/
void GPIO_PortOutSetVal(GPIO_Port_TypeDef port, uint32_t val, uint32_t mask)
{
  EFM_ASSERT(GPIO_PORT_VALID(port));

  GPIO->P[port].DOUT = (GPIO->P[port].DOUT & ~mask) | (val & mask);
}
Esempio n. 20
0
/***************************************************************************//**
 * @brief
 *   Set LESENSE decoder state.
 *
 * @details
 *   This function can be used for setting the initial state of the LESENSE
 *   decoder.
 *
 * @note
 *   Make sure the LESENSE decoder state is initialized by this function before
 *   enabling the decoder!
 *
 * @param[in] decSt
 *   Decoder state to set as current state. Valid range: 0-15
 ******************************************************************************/
void LESENSE_DecoderStateSet(uint32_t decSt)
{
  EFM_ASSERT(decSt < 16U);

  LESENSE->DECSTATE = decSt & _LESENSE_DECSTATE_DECSTATE_MASK;
}
Esempio n. 21
0
/***************************************************************************//**
 * @brief
 *   Init pulse counter.
 *
 * @details
 *   This function will configure the pulse counter. The clock selection is
 *   configured as follows, depending on operational mode:
 *
 *   @li #pcntModeOvsSingle - Use LFACLK.
 *   @li #pcntModeExtSingle - Use external PCNTn_S0 pin.
 *   @li #pcntModeExtQuad - Use external PCNTn_S0 pin.
 *
 *   Notice that the LFACLK must be enabled in all modes, since some basic setup
 *   is done with this clock even if external pin clock usage mode is chosen.
 *   The pulse counter clock for the selected instance must also be enabled
 *   prior to init.
 *
 *   Notice that pins used by the PCNT module must be properly configured
 *   by the user explicitly through setting the ROUTE register, in order for
 *   the PCNT to work as intended.
 *
 *   Writing to CNT will not occur in external clock modes (EXTCLKQUAD and
 *   EXTCLKSINGLE) because the external clock rate is unknown. The user should
 *   handle it manually depending on the application
 *
 *   TOPB is written for all modes but in external clock mode it will take
 *   3 external clock cycles to sync to TOP
 *
 *
 * @note
 *   Initializing requires synchronization into the low frequency domain. This
 *   may cause some delay.
 *
 * @param[in] pcnt
 *   Pointer to PCNT peripheral register block.
 *
 * @param[in] init
 *   Pointer to initialization structure used to initialize.
 ******************************************************************************/
void PCNT_Init(PCNT_TypeDef *pcnt, const PCNT_Init_TypeDef *init)
{
  unsigned int inst;
  uint32_t     tmp;

  EFM_ASSERT(PCNT_REF_VALID(pcnt));

  /* Map pointer to instance */
  inst = PCNT_Map(pcnt);

#if (defined (_EFM32_TINY_FAMILY) || defined (_EFM32_GIANT_FAMILY) || defined (_EFM32_WONDER_FAMILY))
  /* Selecting the PRS channels for the PRS input sources of the PCNT. These are
   * written with a Read-Modify-Write sequence in order to keep the value of the
   * input enable bits which can be modified using PCNT_PRSInputEnable(). */
  tmp = pcnt->INPUT & ~(_PCNT_INPUT_S0PRSSEL_MASK | _PCNT_INPUT_S1PRSSEL_MASK);
  tmp |= ((uint32_t)init->s0PRS << _PCNT_INPUT_S0PRSSEL_SHIFT) |
         ((uint32_t)init->s1PRS << _PCNT_INPUT_S1PRSSEL_SHIFT);
  pcnt->INPUT = tmp;
#endif

  /* Build CTRL setting, except for mode */
  tmp = 0;
  if (init->negEdge)
  {
    tmp |= PCNT_CTRL_EDGE_NEG;
  }

  if (init->countDown)
  {
    tmp |= PCNT_CTRL_CNTDIR_DOWN;
  }

  if (init->filter)
  {
    tmp |= PCNT_CTRL_FILT;
  }

#if (defined (_EFM32_TINY_FAMILY) || defined (_EFM32_GIANT_FAMILY) || defined (_EFM32_WONDER_FAMILY)) 
  if (init->hyst)
  {
    tmp |= PCNT_CTRL_HYST;
  }

  if (init->s1CntDir)
  {
    tmp |= PCNT_CTRL_S1CDIR;
  }

  /* Configure counter events for regular and auxiliary counter. */
  tmp |= init->cntEvent << _PCNT_CTRL_CNTEV_SHIFT;
  tmp |= init->auxCntEvent << _PCNT_CTRL_AUXCNTEV_SHIFT;
#endif

  /* Reset pulse counter while changing clock source. The reset bit */
  /* is asynchronous, we don't have to check for SYNCBUSY. */
  BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);

  /* Select LFACLK to clock in control setting */
  CMU_PCNTClockExternalSet(inst, false);

  /* Handling depends on whether using external clock or not. */
  switch (init->mode)
  {
  case pcntModeExtSingle:
  case pcntModeExtQuad:
    tmp |= init->mode << _PCNT_CTRL_MODE_SHIFT;

    /* In most cases, the SYNCBUSY bit is set due to reset bit set, and waiting
     * for asynchronous reset bit is strictly not necessary.
     * But in theory, other operations on CTRL register may have been done
     * outside this function, so wait. */
    PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);

    /* Enable PCNT Clock Domain Reset. The PCNT must be in reset before changing
     * the clock source to an external clock */
    pcnt->CTRL = PCNT_CTRL_RSTEN;

    /* Wait until CTRL write synchronized into LF domain. */
    PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);

    /* Change to external clock BEFORE disabling reset */
    CMU_PCNTClockExternalSet(inst, true);

    /* Write to TOPB. If using external clock TOPB will sync to TOP at the same
     * time as the mode. This will insure that if the user chooses to count
     * down, the first "countable" pulse will make CNT go to TOP and not 0xFF
     * (default TOP value). */
    pcnt->TOPB = init->top;

    /* This bit has no effect on rev. C and onwards parts - for compatibility */
    pcnt->CMD = PCNT_CMD_LTOPBIM;

    /* Write the CTRL register with the configurations.
     * This should be written after TOPB in the eventuality of a pulse between
     * these two writes that would cause the CTRL register to be synced one
     * clock cycle earlier than the TOPB. */
    pcnt->CTRL = tmp;

    /* There are no syncs for TOP, CMD or CTRL because the clock rate is unknown
     * and the program could stall
     * These will be synced within 3 clock cycles of the external clock  /
     * For the same reason CNT cannot be written here. */
    break;

  /* pcntModeDisable */
  /* pcntModeOvsSingle */
  default:
    /* No need to set disabled mode if already disabled. */
    if ((pcnt->CTRL & _PCNT_CTRL_MODE_MASK) != PCNT_CTRL_MODE_DISABLE)
    {
      /* Set control to disabled mode, leave reset on until ensured disabled.
       * We don't need to wait for CTRL SYNCBUSY completion here, it was
       * triggered by reset bit above, which is asynchronous. */
      pcnt->CTRL = tmp | PCNT_CTRL_MODE_DISABLE | PCNT_CTRL_RSTEN;

      /* Wait until CTRL write synchronized into LF domain before proceeding
       * to disable reset. */
      PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
    }

    /* Disable reset bit, counter should now be in disabled mode. */
    BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);

    /* Set counter and top values as specified. */
    PCNT_CounterTopSet(pcnt, init->counter, init->top);

    /* Enter oversampling mode if selected. */
    if (init->mode == pcntModeOvsSingle)
    {
      PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
      pcnt->CTRL = tmp | (init->mode << _PCNT_CTRL_MODE_SHIFT);
    }
    break;
  }
}
Esempio n. 22
0
/***************************************************************************//**
 * @brief
 *   Initialize the LESENSE module.
 *
 * @details
 *   This function configures the main parameters of the LESENSE interface.
 *   Please refer to the initialization parameter type definition
 *   (@ref LESENSE_Init_TypeDef) for more details.
 *
 * @note
 *   @ref LESENSE_Init() has been designed for initializing LESENSE once in an
 *   operation cycle. Be aware of the effects of reconfiguration if using this
 *   function from multiple sources in your code. This function has not been
 *   designed to be re-entrant.
 *   Requesting reset by setting @p reqReset to true is required in each reset
 *   or power-on cycle in order to configure the default values of the RAM
 *   mapped LESENSE registers.
 *   Notice that GPIO pins used by the LESENSE module must be properly
 *   configured by the user explicitly, in order for the LESENSE to work as
 *   intended.
 *   (When configuring pins, one should remember to consider the sequence of
 *   configuration, in order to avoid unintended pulses/glitches on output
 *   pins.)
 *
 * @param[in] init
 *   LESENSE initialization structure.
 *
 * @param[in] reqReset
 *   Request to call @ref LESENSE_Reset() first in order to initialize all
 *   LESENSE registers with the default value.
 ******************************************************************************/
void LESENSE_Init(LESENSE_Init_TypeDef const *init, bool const reqReset)
{
  /* Sanity check of initialization values */
  EFM_ASSERT((uint32_t)init->timeCtrl.startDelay < 4U);
  EFM_ASSERT((uint32_t)init->perCtrl.dacPresc < 32U);

  /* Reset LESENSE registers if requested. */
  if (reqReset)
  {
    LESENSE_Reset();
  }

  /* Set sensor start delay for each channel. */
  LESENSE_StartDelaySet((uint32_t)init->timeCtrl.startDelay);

  /* LESENSE core control configuration.
   * Set PRS source, SCANCONF register usage strategy, interrupt and
   * DMA trigger level condition, DMA wakeup condition, bias mode,
   * enable/disable to sample both ACMPs simultaneously, enable/disable to store
   * SCANRES in CNT_RES after each scan, enable/disable to always write to the
   * result buffer, even if it is full, enable/disable LESENSE running in debug
   * mode. */
  LESENSE->CTRL = ((uint32_t)init->coreCtrl.prsSel <<
                   _LESENSE_CTRL_PRSSEL_SHIFT) |
                  (uint32_t)init->coreCtrl.scanConfSel |
                  (uint32_t)init->coreCtrl.bufTrigLevel |
                  (uint32_t)init->coreCtrl.wakeupOnDMA |
                  ((uint32_t)init->coreCtrl.invACMP0 <<
                   _LESENSE_CTRL_ACMP0INV_SHIFT) |
                  ((uint32_t)init->coreCtrl.invACMP1 <<
                   _LESENSE_CTRL_ACMP1INV_SHIFT) |
                  ((uint32_t)init->coreCtrl.dualSample <<
                   _LESENSE_CTRL_DUALSAMPLE_SHIFT) |
                  ((uint32_t)init->coreCtrl.storeScanRes <<
                   _LESENSE_CTRL_STRSCANRES_SHIFT) |
                  ((uint32_t)init->coreCtrl.bufOverWr <<
                   _LESENSE_CTRL_BUFOW_SHIFT) |
                  ((uint32_t)init->coreCtrl.debugRun <<
                   _LESENSE_CTRL_DEBUGRUN_SHIFT);

  /* Set scan mode in the CTRL register using the provided function, don't
   * start scanning immediately. */
  LESENSE_ScanModeSet((LESENSE_ScanMode_TypeDef)init->coreCtrl.scanStart, false);

  /* LESENSE peripheral control configuration.
   * Set DAC0 and DAC1 data source, conversion mode, output mode. Set DAC
   * prescaler and reference. Set ACMP0 and ACMP1 control mode. Set ACMP and DAC
   * duty cycle (warm up) mode. */
  LESENSE->PERCTRL = ((uint32_t)init->perCtrl.dacCh0Data <<
                      _LESENSE_PERCTRL_DACCH0DATA_SHIFT) |
                     ((uint32_t)init->perCtrl.dacCh0ConvMode <<
                      _LESENSE_PERCTRL_DACCH0CONV_SHIFT) |
                     ((uint32_t)init->perCtrl.dacCh0OutMode <<
                      _LESENSE_PERCTRL_DACCH0OUT_SHIFT) |
                     ((uint32_t)init->perCtrl.dacCh1Data <<
                      _LESENSE_PERCTRL_DACCH1DATA_SHIFT) |
                     ((uint32_t)init->perCtrl.dacCh1ConvMode <<
                      _LESENSE_PERCTRL_DACCH1CONV_SHIFT) |
                     ((uint32_t)init->perCtrl.dacCh1OutMode <<
                      _LESENSE_PERCTRL_DACCH1OUT_SHIFT) |
                     ((uint32_t)init->perCtrl.dacPresc <<
                      _LESENSE_PERCTRL_DACPRESC_SHIFT) |
                     (uint32_t)init->perCtrl.dacRef |
                     ((uint32_t)init->perCtrl.acmp0Mode <<
                      _LESENSE_PERCTRL_ACMP0MODE_SHIFT) |
                     ((uint32_t)init->perCtrl.acmp1Mode <<
                      _LESENSE_PERCTRL_ACMP1MODE_SHIFT) |
                     (uint32_t)init->perCtrl.warmupMode;

  /* LESENSE decoder general control configuration.
   * Set decoder input source, select PRS input for decoder bits.
   * Enable/disable the decoder to check the present state.
   * Enable/disable decoder to channel interrupt mapping.
   * Enable/disable decoder hysteresis on PRS output.
   * Enable/disable decoder hysteresis on count events.
   * Enable/disable decoder hysteresis on interrupt requests.
   * Enable/disable count mode on LESPRS0 and LESPRS1. */
  LESENSE->DECCTRL = (uint32_t)init->decCtrl.decInput |
                     ((uint32_t)init->decCtrl.prsChSel0 <<
                      _LESENSE_DECCTRL_PRSSEL0_SHIFT) |
                     ((uint32_t)init->decCtrl.prsChSel1 <<
                      _LESENSE_DECCTRL_PRSSEL1_SHIFT) |
                     ((uint32_t)init->decCtrl.prsChSel2 <<
                      _LESENSE_DECCTRL_PRSSEL2_SHIFT) |
                     ((uint32_t)init->decCtrl.prsChSel3 <<
                      _LESENSE_DECCTRL_PRSSEL3_SHIFT) |
                     ((uint32_t)init->decCtrl.chkState <<
                      _LESENSE_DECCTRL_ERRCHK_SHIFT) |
                     ((uint32_t)init->decCtrl.intMap <<
                      _LESENSE_DECCTRL_INTMAP_SHIFT) |
                     ((uint32_t)init->decCtrl.hystPRS0 <<
                      _LESENSE_DECCTRL_HYSTPRS0_SHIFT) |
                     ((uint32_t)init->decCtrl.hystPRS1 <<
                      _LESENSE_DECCTRL_HYSTPRS1_SHIFT) |
                     ((uint32_t)init->decCtrl.hystPRS2 <<
                      _LESENSE_DECCTRL_HYSTPRS2_SHIFT) |
                     ((uint32_t)init->decCtrl.hystIRQ <<
                      _LESENSE_DECCTRL_HYSTIRQ_SHIFT) |
                     ((uint32_t)init->decCtrl.prsCount <<
                      _LESENSE_DECCTRL_PRSCNT_SHIFT);

  /* Set initial LESENSE decoder state. */
  LESENSE_DecoderStateSet((uint32_t)init->decCtrl.initState);

  /* LESENSE bias control configuration. */
  LESENSE->BIASCTRL = (uint32_t)init->coreCtrl.biasMode;
}
Esempio n. 23
0
/***************************************************************************//**
 * @brief
 *   Initialize LETIMER.
 *
 * @details
 *   Note that the compare/repeat values must be set separately with
 *   LETIMER_CompareSet() and LETIMER_RepeatSet(). That should probably be done
 *   prior to the use of this function if configuring the LETIMER to start when
 *   initialization is completed.
 *
 * @note
 *   The initialization of the LETIMER modifies the LETIMER CTRL/CMD registers
 *   which require synchronization into the low frequency domain. If any of those
 *   registers are modified before a previous update to the same register has
 *   completed, this function will stall until the previous synchronization has
 *   completed. This only applies to the Gecko Family, see comment in the
 *   LETIMER_Sync() internal function call.
 *
 * @param[in] letimer
 *   Pointer to LETIMER peripheral register block.
 *
 * @param[in] init
 *   Pointer to LETIMER initialization structure.
 ******************************************************************************/
void LETIMER_Init(LETIMER_TypeDef *letimer, const LETIMER_Init_TypeDef *init)
{
  uint32_t tmp = 0;

  EFM_ASSERT(LETIMER_REF_VALID(letimer));

  /* Stop timer if specified to be disabled and running */
  if (!(init->enable) && (letimer->STATUS & LETIMER_STATUS_RUNNING))
  {
#if defined(_EFM32_GECKO_FAMILY)
    /* LF register about to be modified require sync. busy check */
    LETIMER_Sync(letimer, LETIMER_SYNCBUSY_CMD);
#endif
    letimer->CMD = LETIMER_CMD_STOP;
  }

  /* Configure DEBUGRUN flag, sets whether or not counter should be
   * updated when debugger is active */
  if (init->debugRun)
  {
    tmp |= LETIMER_CTRL_DEBUGRUN;
  }

  if (init->rtcComp0Enable)
  {
    tmp |= LETIMER_CTRL_RTCC0TEN;
  }

  if (init->rtcComp1Enable)
  {
    tmp |= LETIMER_CTRL_RTCC1TEN;
  }

  if (init->comp0Top)
  {
    tmp |= LETIMER_CTRL_COMP0TOP;
  }

  if (init->bufTop)
  {
    tmp |= LETIMER_CTRL_BUFTOP;
  }

  if (init->out0Pol)
  {
    tmp |= LETIMER_CTRL_OPOL0;
  }

  if (init->out1Pol)
  {
    tmp |= LETIMER_CTRL_OPOL1;
  }

  tmp |= init->ufoa0 << _LETIMER_CTRL_UFOA0_SHIFT;
  tmp |= init->ufoa1 << _LETIMER_CTRL_UFOA1_SHIFT;
  tmp |= init->repMode << _LETIMER_CTRL_REPMODE_SHIFT;

#if defined(_EFM32_GECKO_FAMILY)
  /* LF register about to be modified require sync. busy check */
  LETIMER_Sync(letimer, LETIMER_SYNCBUSY_CTRL);
#endif
  letimer->CTRL = tmp;

  /* Start timer if specified to be enabled and not already running */
  if (init->enable && !(letimer->STATUS & LETIMER_STATUS_RUNNING))
  {
#if defined(_EFM32_GECKO_FAMILY)
    /* LF register about to be modified require sync. busy check */
    LETIMER_Sync(letimer, LETIMER_SYNCBUSY_CMD);
#endif
    letimer->CMD = LETIMER_CMD_START;
  }
}
Esempio n. 24
0
/***************************************************************************//**
 * @brief
 *   Get current setting for a pin in a GPIO port data out register.
 *
 * @param[in] port
 *   The GPIO port to access.
 *
 * @param[in] pin
 *   The pin to get setting for.
 *
 * @return
 *   The DOUT setting for the requested pin, 0 or 1.
 ******************************************************************************/
unsigned int GPIO_PinOutGet(GPIO_Port_TypeDef port, unsigned int pin)
{
  EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_PIN_VALID(pin));

  return((unsigned int)((GPIO->P[port].DOUT >> pin) & 0x1));
}
Esempio n. 25
0
/***************************************************************************//**
 * @brief
 *   Continue an initiated I2C transfer (single master mode only).
 *
 * @details
 *   This function is used repeatedly after a I2C_TransferInit() in order to
 *   complete a transfer. It may be used in polled mode as the below example
 *   shows:
 * @verbatim
 * I2C_TransferReturn_TypeDef ret;
 *
 * // Do a polled transfer
 * ret = I2C_TransferInit(I2C0, seq);
 * while (ret == i2cTransferInProgress)
 * {
 *   ret = I2C_Transfer(I2C0);
 * }
 * @endverbatim
 *  It may also be used in interrupt driven mode, where this function is invoked
 *  from the interrupt handler. Notice that if used in interrupt mode, NVIC
 *  interrupts must be configured and enabled for the I2C bus used. I2C
 *  peripheral specific interrupts are managed by this SW.
 *
 * @note
 *   Only single master mode is supported.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @return
 *   Returns status for ongoing transfer.
 *   @li #i2cTransferInProgress - indicates that transfer not finished.
 *   @li #i2cTransferDone - transfer completed successfully.
 *   @li otherwise some sort of error has occurred.
 *
 ******************************************************************************/
I2C_TransferReturn_TypeDef I2C_Transfer(I2C_TypeDef *i2c)
{
    uint32_t                tmp;
    uint32_t                pending;
    I2C_Transfer_TypeDef    *transfer;
    I2C_TransferSeq_TypeDef *seq;

    EFM_ASSERT(I2C_REF_VALID(i2c));

    /* Support up to 2 I2C buses */
    if (i2c == I2C0)
    {
        transfer = i2cTransfer;
    }
#if (I2C_COUNT > 1)
    else if (i2c == I2C1)
    {
        transfer = i2cTransfer + 1;
    }
#endif
    else
    {
        return(i2cTransferUsageFault);
    }

    seq = transfer->seq;
    for (;; )
    {
        pending = i2c->IF;

        /* If some sort of fault, abort transfer. */
        if (pending & I2C_IF_ERRORS)
        {
            if (pending & I2C_IF_ARBLOST)
            {
                /* If arbitration fault, it indicates either a slave device */
                /* not responding as expected, or other master which is not */
                /* supported by this SW. */
                transfer->result = i2cTransferArbLost;
            }
            else if (pending & I2C_IF_BUSERR)
            {
                /* A bus error indicates a misplaced start or stop, which should */
                /* not occur in master mode controlled by this SW. */
                transfer->result = i2cTransferBusErr;
            }

            /* If error situation occurred, it is difficult to know */
            /* exact cause and how to resolve. It will be up to a wrapper */
            /* to determine how to handle a fault/recovery if possible. */
            transfer->state = i2cStateDone;
            goto done;
        }

        switch (transfer->state)
        {
        /***************************************************/
        /* Send first start+address (first byte if 10 bit) */
        /***************************************************/
        case i2cStateStartAddrSend:
            if (seq->flags & I2C_FLAG_10BIT_ADDR)
            {
                tmp = (((uint32_t)(seq->addr) >> 8) & 0x06) | 0xf0;

                /* In 10 bit address mode, the address following the first */
                /* start always indicate write. */
            }
            else
            {
                tmp = (uint32_t)(seq->addr) & 0xfe;

                if (seq->flags & I2C_FLAG_READ)
                {
                    /* Indicate read request */
                    tmp |= 1;
                }
            }

            transfer->state = i2cStateAddrWFAckNack;
            i2c->TXDATA     = tmp; /* Data not transmitted until START sent */
            i2c->CMD        = I2C_CMD_START;
            goto done;

        /*******************************************************/
        /* Wait for ACK/NACK on address (first byte if 10 bit) */
        /*******************************************************/
        case i2cStateAddrWFAckNack:
            if (pending & I2C_IF_NACK)
            {
                i2c->IFC         = I2C_IFC_NACK;
                transfer->result = i2cTransferNack;
                transfer->state  = i2cStateWFStopSent;
                i2c->CMD         = I2C_CMD_STOP;
            }
            else if (pending & I2C_IF_ACK)
            {
                i2c->IFC = I2C_IFC_ACK;

                /* If 10 bit address, send 2nd byte of address. */
                if (seq->flags & I2C_FLAG_10BIT_ADDR)
                {
                    transfer->state = i2cStateAddrWF2ndAckNack;
                    i2c->TXDATA     = (uint32_t)(seq->addr) & 0xff;
                }
                else
                {
                    /* Determine whether receiving or sending data */
                    if (seq->flags & I2C_FLAG_READ)
                    {
                        transfer->state = i2cStateWFData;
                    }
                    else
                    {
                        transfer->state = i2cStateDataSend;
                        continue;
                    }
                }
            }
            goto done;

        /******************************************************/
        /* Wait for ACK/NACK on second byte of 10 bit address */
        /******************************************************/
        case i2cStateAddrWF2ndAckNack:
            if (pending & I2C_IF_NACK)
            {
                i2c->IFC         = I2C_IFC_NACK;
                transfer->result = i2cTransferNack;
                transfer->state  = i2cStateWFStopSent;
                i2c->CMD         = I2C_CMD_STOP;
            }
            else if (pending & I2C_IF_ACK)
            {
                i2c->IFC = I2C_IFC_ACK;

                /* If using plain read sequence with 10 bit address, switch to send */
                /* repeated start. */
                if (seq->flags & I2C_FLAG_READ)
                {
                    transfer->state = i2cStateRStartAddrSend;
                }
                /* Otherwise expected to write 0 or more bytes */
                else
                {
                    transfer->state = i2cStateDataSend;
                }
                continue;
            }
            goto done;

        /*******************************/
        /* Send repeated start+address */
        /*******************************/
        case i2cStateRStartAddrSend:
            if (seq->flags & I2C_FLAG_10BIT_ADDR)
            {
                tmp = ((seq->addr >> 8) & 0x06) | 0xf0;
            }
Esempio n. 26
0
/***************************************************************************//**
 * @brief
 *   Toggle a single pin in GPIO port data out register.
 *
 * @note
 *   In order for the setting to take effect on the output pad, the pin must
 *   have been configured properly. If not, it will take effect whenever the
 *   pin has been properly configured.
 *
 * @param[in] port
 *   The GPIO port to access.
 *
 * @param[in] pin
 *   The pin to toggle.
 ******************************************************************************/
void GPIO_PinOutToggle(GPIO_Port_TypeDef port, unsigned int pin)
{
  EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_PIN_VALID(pin));

  GPIO->P[port].DOUTTGL = 1 << pin;
}
Esempio n. 27
0
/* "Possible rom access from within a __ramfunc function"               */
#pragma diag_suppress=Ta022
#pragma diag_suppress=Ta023
#endif
#endif /* !EM_MSC_RUN_FROM_FLASH */
static MSC_Status_TypeDef MSC_WriteWordI(uint32_t *address,
                                         void const *data,
                                         uint32_t numBytes,
                                         MSC_WriteStrategy_Typedef writeStrategy)
{
  uint32_t wordCount;
  uint32_t numWords;
  uint32_t pageWords;
  uint32_t* pData;
  MSC_Status_TypeDef retval = mscReturnOk;

  /* Check alignment (Must be aligned to words) */
  EFM_ASSERT(((uint32_t) address & 0x3) == 0);

  /* Check number of bytes. Must be divisable by four */
  EFM_ASSERT((numBytes & 0x3) == 0);

  /* Enable writing to the MSC */
  MSC->WRITECTRL |= MSC_WRITECTRL_WREN;

  /* Convert bytes to words */
  numWords = numBytes >> 2;
  EFM_ASSERT(numWords > 0);

  /* The following loop splits the data into chunks corresponding to flash pages.
     The address is loaded only once per page, because the hardware automatically
     increments the address internally for each data load inside a page. */
  for (wordCount = 0, pData = (uint32_t *)data; wordCount < numWords; )
  {
    /* First we load address. The address is auto-incremented within a page.
       Therefore the address phase is only needed once for each page. */
    retval = MSC_LoadVerifyAddress(address + wordCount);
    if (mscReturnOk != retval)
    {
      return retval;
    }
    /* Compute the number of words to write to the current page. */
    pageWords =
      (FLASH_PAGE_SIZE -
       (((uint32_t) (address + wordCount)) & (FLASH_PAGE_SIZE - 1)))
      / sizeof(uint32_t);
    if (pageWords > numWords - wordCount)
    {
      pageWords = numWords - wordCount;
    }
    /* Now write the data in the current page. */
    retval = MSC_LoadWriteData(pData, pageWords, writeStrategy);
    if (mscReturnOk != retval)
    {
      break;
    }
    wordCount += pageWords;
    pData += pageWords;
  }

  /* Disable writing to the MSC */
  MSC->WRITECTRL &= ~MSC_WRITECTRL_WREN;

#if defined( _MSC_WRITECTRL_WDOUBLE_MASK )
#if ( WORDS_PER_DATA_PHASE == 2 )
  /* Turn off double word write cycle support. */
  MSC->WRITECTRL &= ~MSC_WRITECTRL_WDOUBLE;
#endif
#endif

  return retval;
}
Esempio n. 28
0
/***************************************************************************//**
 * @brief
 *   Read the pad values for GPIO port.
 *
 * @param[in] port
 *   The GPIO port to access.
 ******************************************************************************/
uint32_t GPIO_PortInGet(GPIO_Port_TypeDef port)
{
  EFM_ASSERT(GPIO_PORT_VALID(port));

  return(GPIO->P[port].DIN & _GPIO_P_DIN_DIN_MASK);
}
Esempio n. 29
0
/***************************************************************************//**
 * @brief Initialize BURTC
 *
 * @details
 *    Configures the BURTC peripheral.
 *
 * @note
 *   Before initialization, BURTC module must first be enabled by clearing the
 *   reset bit in the RMU, i.e.
 * @verbatim
 *   RMU_ResetControl(rmuResetBU, rmuResetModeClear);
 * @endverbatim
 *   Compare channel 0 must be configured outside this function, before
 *   initialization if enable is set to true. The counter will always be reset.
 *
 * @param[in] burtcInit
 *   Pointer to BURTC initialization structure
 ******************************************************************************/
void BURTC_Init(const BURTC_Init_TypeDef *burtcInit)
{
  uint32_t ctrl;
  uint32_t presc;

  /* Check initializer structure integrity */
  EFM_ASSERT(burtcInit != (BURTC_Init_TypeDef *) 0);
  /* Clock divider must be between 1 and 128, really on the form 2^n */
  EFM_ASSERT((burtcInit->clkDiv >= 1) && (burtcInit->clkDiv <= 128));
  /* Ignored compare bits during low power operation must be less than 7 */
  /* Note! Giant Gecko revision C errata, do NOT use LPCOMP=7 */
  EFM_ASSERT(burtcInit->lowPowerComp <= 6);
  /* You cannot enable the BURTC if mode is set to disabled */
  EFM_ASSERT((burtcInit->enable == false) ||
             ((burtcInit->enable == true)
              && (burtcInit->mode != burtcModeDisable)));
  /* Low power mode is only available with LFRCO or LFXO as clock source */
  EFM_ASSERT((burtcInit->clkSel != burtcClkSelULFRCO)
             || ((burtcInit->clkSel == burtcClkSelULFRCO)
                  && (burtcInit->lowPowerMode == burtcLPDisable)));

  /* Calculate prescaler value from clock divider input */
  /* Note! If clock select (clkSel) is ULFRCO, a clock divisor (clkDiv) of
     value 1 will select a 2kHz ULFRCO clock, while any other value will
     select a 1kHz ULFRCO clock source. */
  presc = divToLog2(burtcInit->clkDiv);

  /* Make sure all registers are updated simultaneously */
  if (burtcInit->enable)
  {
    BURTC_FreezeEnable(true);
  }

  /* Modification of LPMODE register requires sync with potential ongoing
   * register updates in LF domain. */
  regSync(BURTC_SYNCBUSY_LPMODE);

  /* Configure low power mode */
  BURTC->LPMODE = (uint32_t) (burtcInit->lowPowerMode);

  /* New configuration */
  ctrl = (BURTC_CTRL_RSTEN
          | (burtcInit->mode)
          | (burtcInit->debugRun << _BURTC_CTRL_DEBUGRUN_SHIFT)
          | (burtcInit->compare0Top << _BURTC_CTRL_COMP0TOP_SHIFT)
          | (burtcInit->lowPowerComp << _BURTC_CTRL_LPCOMP_SHIFT)
          | (presc << _BURTC_CTRL_PRESC_SHIFT)
          | (burtcInit->clkSel)
          | (burtcInit->timeStamp << _BURTC_CTRL_BUMODETSEN_SHIFT));

  /* Clear interrupts */
  BURTC_IntClear(0xFFFFFFFF);

  /* Set new configuration */
  BURTC->CTRL = ctrl;

  /* Enable BURTC and counter */
  if (burtcInit->enable)
  {
    /* To enable BURTC counter, we need to disable reset */
    BURTC_Enable(true);

    /* Clear freeze */
    BURTC_FreezeEnable(false);
  }
}
Esempio n. 30
0
/***************************************************************************//**
 * @brief
 *   Configure EBI pin polarity for selected bank(s) for devices with individual
 *   timing support
 *
 * @param[in] banks
 *   Mask of memory bank(s) to configure polarity for
 *
 * @param[in] line
 *   Which pin/line to configure
 *
 * @param[in] polarity
 *   Active high, or active low
 ******************************************************************************/
void EBI_BankPolaritySet(uint32_t banks, EBI_Line_TypeDef line, EBI_Polarity_TypeDef polarity)
{
  uint32_t bankSet = 0;
  volatile uint32_t *polRegister = 0;

  /* Verify only valid banks are used */
  EFM_ASSERT((banks & ~(EBI_BANK0 | EBI_BANK1 | EBI_BANK2 | EBI_BANK3)) == 0);

  while (banks)
  {
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    if (banks & EBI_BANK0)
    {
      polRegister = &EBI->POLARITY;
      bankSet = EBI_BANK0;
    }
    if (banks & EBI_BANK1)
    {
      polRegister = &EBI->POLARITY1;
      bankSet = EBI_BANK1;
    }
    if (banks & EBI_BANK2)
    {
      polRegister = &EBI->POLARITY2;
      bankSet = EBI_BANK2;
    }
    if (banks & EBI_BANK3)
    {
      polRegister = &EBI->POLARITY3;
      bankSet = EBI_BANK3;
    }
#else
    polRegister = &EBI->POLARITY;
    banks       = 0;
#endif

    /* What line to configure */
    switch (line)
    {
    case ebiLineARDY:
      BITBAND_Peripheral(polRegister, _EBI_POLARITY_ARDYPOL_SHIFT, polarity);
      break;
    case ebiLineALE:
      BITBAND_Peripheral(polRegister, _EBI_POLARITY_ALEPOL_SHIFT, polarity);
      break;
    case ebiLineWE:
      BITBAND_Peripheral(polRegister, _EBI_POLARITY_WEPOL_SHIFT, polarity);
      break;
    case ebiLineRE:
      BITBAND_Peripheral(polRegister, _EBI_POLARITY_REPOL_SHIFT, polarity);
      break;
    case ebiLineCS:
      BITBAND_Peripheral(polRegister, _EBI_POLARITY_CSPOL_SHIFT, polarity);
      break;
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    case ebiLineBL:
      BITBAND_Peripheral(polRegister, _EBI_POLARITY_BLPOL_SHIFT, polarity);
      break;
    case ebiLineTFTVSync:
      BITBAND_Peripheral(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_VSYNCPOL_SHIFT, polarity);
      break;
    case ebiLineTFTHSync:
      BITBAND_Peripheral(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_HSYNCPOL_SHIFT, polarity);
      break;
    case ebiLineTFTDataEn:
      BITBAND_Peripheral(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_DATAENPOL_SHIFT, polarity);
      break;
    case ebiLineTFTDClk:
      BITBAND_Peripheral(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_DCLKPOL_SHIFT, polarity);
      break;
    case ebiLineTFTCS:
      BITBAND_Peripheral(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_CSPOL_SHIFT, polarity);
      break;
#endif
    default:
      EFM_ASSERT(0);
      break;
    }
    banks = banks & (~bankSet);
  }
}