/***************************************************************************//**
 * @brief
 *   Enable/disable the selected PRS input of PCNT.
 *
 * @details
 *   Notice that this function does not do any configuration.
 *
 * @param[in] pcnt
 *   Pointer to PCNT peripheral register block.
 *
 * @param[in] prsInput
 *   PRS input (S0 or S1) of the selected PCNT module.
 *
 * @param[in] enable
 *   Set to true to enable, false to disable the selected PRS input.
 ******************************************************************************/
void PCNT_PRSInputEnable(PCNT_TypeDef *pcnt,
                         PCNT_PRSInput_TypeDef prsInput,
                         bool enable)
{
  EFM_ASSERT(PCNT_REF_VALID(pcnt));

  /* Enable/disable the selected PRS input on the selected PCNT module. */
  switch (prsInput)
  {
    /* Enable/disable PRS input S0. */
    case pcntPRSInputS0:
      BUS_RegBitWrite(&(pcnt->INPUT), _PCNT_INPUT_S0PRSEN_SHIFT, enable);
      break;

    /* Enable/disable PRS input S1. */
    case pcntPRSInputS1:
      BUS_RegBitWrite(&(pcnt->INPUT), _PCNT_INPUT_S1PRSEN_SHIFT, enable);
      break;

    /* Invalid parameter, asserted. */
    default:
      EFM_ASSERT(0);
    break;
  }
}
Exemple #2
0
/***************************************************************************//**
 * @brief
 *   Clear the reset cause register.
 *
 * @details
 *   This function clears all the reset cause bits of the RSTCAUSE register.
 *   The reset cause bits must be cleared by SW before a new reset occurs,
 *   otherwise reset causes may accumulate. See @ref RMU_ResetCauseGet().
 ******************************************************************************/
void RMU_ResetCauseClear(void)
{
  RMU->CMD = RMU_CMD_RCCLR;

#if defined(EMU_AUXCTRL_HRCCLR)
  {
    uint32_t locked;

    /* Clear some reset causes not cleared with RMU CMD register */
    /* (If EMU registers locked, they must be unlocked first) */
    locked = EMU->LOCK & EMU_LOCK_LOCKKEY_LOCKED;
    if (locked)
    {
      EMU_Unlock();
    }

    BUS_RegBitWrite(&(EMU->AUXCTRL), _EMU_AUXCTRL_HRCCLR_SHIFT, 1);
    BUS_RegBitWrite(&(EMU->AUXCTRL), _EMU_AUXCTRL_HRCCLR_SHIFT, 0);

    if (locked)
    {
      EMU_Lock();
    }
  }
#endif
}
/***************************************************************************//**
 * @brief
 *   Reset PCNT to same state as after a HW reset.
 *
 * @details
 *   Notice the LFACLK must be enabled, since some basic reset is done with
 *   this clock. The pulse counter clock for the selected instance must also
 *   be enabled prior to init.
 *
 * @note
 *   The ROUTE register is NOT reset by this function, in order to allow for
 *   centralized setup of this feature.
 *
 * @param[in] pcnt
 *   Pointer to PCNT peripheral register block.
 ******************************************************************************/
void PCNT_Reset(PCNT_TypeDef *pcnt)
{
  unsigned int inst;

  EFM_ASSERT(PCNT_REF_VALID(pcnt));

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

  pcnt->IEN = _PCNT_IEN_RESETVALUE;

  /* Notice that special SYNCBUSY handling is not applicable for the RSTEN
   * bit of the control register, so we don't need to wait for it when only
   * modifying RSTEN. The SYNCBUSY bit will be set, leading to a
   * synchronization in the LF domain, with in reality no changes to LF domain.
   * Enable reset of CNT and TOP register. */
  BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);

  /* Select LFACLK as default */
  CMU_PCNTClockExternalSet(inst, false);

  PCNT_TopBufferSet(pcnt, _PCNT_TOPB_RESETVALUE);

  /* Reset CTRL leaving RSTEN set */
  pcnt->CTRL = _PCNT_CTRL_RESETVALUE | PCNT_CTRL_RSTEN;

  /* Disable reset after CTRL reg has been synchronized */
  PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
  BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);

  /* Clear pending interrupts */
  pcnt->IFC = _PCNT_IFC_MASK;

  /* Do not reset route register, setting should be done independently */
}
Exemple #4
0
/***************************************************************************//**
 * @brief
 *   Enable/disable the watchdog timer.
 *
 * @note
 *   This function modifies the WDOG CTRL register which requires
 *   synchronization into the low frequency domain. If this register is modified
 *   before a previous update to the same register has completed, this function
 *   will stall until the previous synchronization has completed.
 *
 * @param[in] wdog
 *   Pointer to WDOG peripheral register block.
 *
 * @param[in] enable
 *   true to enable watchdog, false to disable. Watchdog cannot be disabled if
 *   watchdog has been locked.
 ******************************************************************************/
void WDOGn_Enable(WDOG_TypeDef *wdog, bool enable)
{
  /* SYNCBUSY may stall when locked. */
  if (wdog->CTRL & WDOG_CTRL_LOCK)
  {
    return;
  }

  if (!enable)
  {
    /* If the user intends to disable and the WDOG is enabled */
    if (BUS_RegBitRead(&wdog->CTRL, _WDOG_CTRL_EN_SHIFT))
    {
      /* Wait for any pending previous write operation to have been completed in */
      /* low frequency domain */
      while (wdog->SYNCBUSY & WDOG_SYNCBUSY_CTRL)
        ;

      BUS_RegBitWrite(&wdog->CTRL, _WDOG_CTRL_EN_SHIFT, 0);
    }
  }
  else
  {
    BUS_RegBitWrite(&wdog->CTRL, _WDOG_CTRL_EN_SHIFT, 1);
  }
}
Exemple #5
0
/***************************************************************************//**
 * @brief
 *   Restore BURTC to reset state
 * @note
 *   Before accessing the BURTC, BURSTEN in RMU->CTRL must be cleared.
 *   LOCK will not be reset to default value, as this will disable access
 *   to core BURTC registers.
 ******************************************************************************/
void BURTC_Reset(void)
{
  bool buResetState;

  /* Read reset state, set reset and restore state */
  buResetState = BUS_RegBitRead(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT);
  BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, 1);
  BUS_RegBitWrite(&RMU->CTRL, _RMU_CTRL_BURSTEN_SHIFT, buResetState);
}
/***************************************************************************//**
 * @brief
 *   Reset PCNT counters and TOP register.
 *
 * @note
 *   Notice that special SYNCBUSY handling is not applicable for the RSTEN
 *   bit of the control register, so we don't need to wait for it when only
 *   modifying RSTEN. (It would mean undefined wait time if clocked by external
 *   clock.) The SYNCBUSY bit will however be set, leading to a synchronization
 *   in the LF domain, with in reality no changes.
 *
 * @param[in] pcnt
 *   Pointer to PCNT peripheral register block.
 ******************************************************************************/
void PCNT_CounterReset(PCNT_TypeDef *pcnt)
{
  EFM_ASSERT(PCNT_REF_VALID(pcnt));

  /* Enable reset of CNT and TOP register */
  BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);

  /* Disable reset of CNT and TOP register */
  BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
}
/***************************************************************************//**
 * @brief
 *   Configure write operation parameters for selected bank
 *
 * @param[in] banks
 *   Mask of memory bank(s) to configure write timing for
 *
 * @param[in] writeBufDisable
 *   If true, disable the write buffer
 *
 * @param[in] halfWE
 *   Enables or disables half cycle WE strobe in last strobe cycle
 ******************************************************************************/
void EBI_BankWriteTimingConfig(uint32_t banks, bool writeBufDisable, bool halfWE)
{
  /* Verify only valid banks are used */
  EFM_ASSERT((banks & ~(EBI_BANK0 | EBI_BANK1 | EBI_BANK2 | EBI_BANK3)) == 0);

  /* Configure write operation parameters */
  if( banks & EBI_BANK0 )
  {
    BUS_RegBitWrite(&EBI->WRTIMING, _EBI_WRTIMING_WBUFDIS_SHIFT, writeBufDisable);
    BUS_RegBitWrite(&EBI->WRTIMING, _EBI_WRTIMING_HALFWE_SHIFT, halfWE);
  }
  if( banks & EBI_BANK1 )
  {
    BUS_RegBitWrite(&EBI->WRTIMING1, _EBI_WRTIMING_WBUFDIS_SHIFT, writeBufDisable);
    BUS_RegBitWrite(&EBI->WRTIMING1, _EBI_WRTIMING_HALFWE_SHIFT, halfWE);
  }
  if( banks & EBI_BANK2 )
  {
    BUS_RegBitWrite(&EBI->WRTIMING2, _EBI_WRTIMING_WBUFDIS_SHIFT, writeBufDisable);
    BUS_RegBitWrite(&EBI->WRTIMING2, _EBI_WRTIMING_HALFWE_SHIFT, halfWE);
  }
  if( banks & EBI_BANK3 )
  {
    BUS_RegBitWrite(&EBI->WRTIMING3, _EBI_WRTIMING_WBUFDIS_SHIFT, writeBufDisable);
    BUS_RegBitWrite(&EBI->WRTIMING3, _EBI_WRTIMING_HALFWE_SHIFT, halfWE);
  }
}
Exemple #8
0
/***************************************************************************//**
 * @brief
 *   Initialize I2C.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] init
 *   Pointer to I2C initialization structure.
 ******************************************************************************/
void I2C_Init(I2C_TypeDef *i2c, const I2C_Init_TypeDef *init)
{
  EFM_ASSERT(I2C_REF_VALID(i2c));

  i2c->IEN = 0;
  i2c->IFC = _I2C_IFC_MASK;

  /* Set SLAVE select mode */
  BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_SLAVE_SHIFT, init->master ? 0 : 1);

  I2C_BusFreqSet(i2c, init->refFreq, init->freq, init->clhr);

  BUS_RegBitWrite(&(i2c->CTRL), _I2C_CTRL_EN_SHIFT, init->enable);
}
Exemple #9
0
/***************************************************************************//**
 * @brief
 *   Set the Id and the filter for a specific Message Object.
 *
 * @details
 *   The Init bit have to be 0 to use this function.
 *
 * @param[in] can
 *   Pointer to CAN peripheral register block.
 *
 * @param[in] interface
 *   Indicate which Message Interface Register to use.
 *
 * @param[in] useMask
 *   Boolean to choose whether or not to use the masks.
 *
 * @param[in] message
 *   Message Object
 *
 * @param[in] wait
 *   If true, wait for the end of the transfer between the MIRx registers and
 *   the RAM to exit. If false, exit immediately, the transfer can still be
 *   in progress.
 ******************************************************************************/
void CAN_SetIdAndFilter(CAN_TypeDef *can,
                        uint8_t interface,
                        bool useMask,
                        const CAN_MessageObject_TypeDef *message,
                        bool wait)
{
  /* Make sure msgNum is in the correct range */
  EFM_ASSERT((message->msgNum > 0) && (message->msgNum <= 32));

  CAN_MIR_TypeDef * mir = &can->MIR[interface];
  CAN_ReadyWait(can, interface);

  /* Set which registers to read from the RAM */
  mir->CMDMASK = CAN_MIR_CMDMASK_WRRD_READ
                 | CAN_MIR_CMDMASK_ARBACC
                 | CAN_MIR_CMDMASK_CONTROL;

  /* Send reading request and wait (3 to 6 cpu cycle) */
  CAN_SendRequest(can, interface, message->msgNum, true);

  /* Reset MSGVAL */
  mir->CMDMASK |= CAN_MIR_CMDMASK_WRRD;
  mir->ARB &= ~(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT);
  CAN_SendRequest(can, interface, message->msgNum, true);

  /* Set which registers to write to the RAM */
  mir->CMDMASK |= CAN_MIR_CMDMASK_MASKACC;

  /* Set UMASK bit */
  BUS_RegBitWrite(&mir->CTRL, _CAN_MIR_CTRL_UMASK_SHIFT, useMask);

  /* Configure the id */
  if (message->extended) {
    EFM_ASSERT(message->id <= _CAN_MIR_ARB_ID_MASK);
    mir->ARB = (mir->ARB & ~_CAN_MIR_ARB_ID_MASK)
               | (message->id << _CAN_MIR_ARB_ID_SHIFT)
               | (uint32_t)(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT)
               | CAN_MIR_ARB_XTD_EXT;
  } else {
    EFM_ASSERT(message->id <= _CAN_MIR_ARB_STD_ID_MAX);
    mir->ARB = (mir->ARB & ~(_CAN_MIR_ARB_ID_MASK | CAN_MIR_ARB_XTD_STD))
               | (message->id << _CAN_MIR_ARB_STD_ID_SHIFT)
               | (uint32_t)(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT);
  }

  if (message->extendedMask) {
    mir->MASK = (message->mask << _CAN_MIR_MASK_MASK_SHIFT);
  } else {
    mir->MASK = (message->mask << _CAN_MIR_MASK_STD_SHIFT)
                & _CAN_MIR_ARB_STD_ID_MASK;
  }

  /* Configure the masks */
  mir->MASK |= (message->extendedMask << _CAN_MIR_MASK_MXTD_SHIFT)
               | (message->directionMask << _CAN_MIR_MASK_MDIR_SHIFT);

  /* Send writing request */
  CAN_SendRequest(can, interface, message->msgNum, wait);
}
/***************************************************************************//**
 * @brief
 *   Enable or disable EBI Chip Select
 *
 * @param[in] cs
 *   ChipSelect lines to reconfigure, mask of EBI_CS<n> flags
 *
 * @param[in] enable
 *   True to enable, false to disable
 ******************************************************************************/
void EBI_ChipSelectEnable(uint32_t cs, bool enable)
{
  if (cs & EBI_CS0)
  {
    BUS_RegBitWrite(&(EBI->ROUTE), _EBI_ROUTE_CS0PEN_SHIFT, enable);
  }
  if (cs & EBI_CS1)
  {
    BUS_RegBitWrite(&(EBI->ROUTE), _EBI_ROUTE_CS1PEN_SHIFT, enable);
  }
  if (cs & EBI_CS2)
  {
    BUS_RegBitWrite(&(EBI->ROUTE), _EBI_ROUTE_CS2PEN_SHIFT, enable);
  }
  if (cs & EBI_CS3)
  {
    BUS_RegBitWrite(&(EBI->ROUTE), _EBI_ROUTE_CS3PEN_SHIFT, enable);
  }
}
Exemple #11
0
/***************************************************************************//**
 * @brief
 *   Lock the watchdog configuration.
 *
 * @details
 *   This prevents errors from overwriting the watchdog configuration, possibly
 *   disabling it. Only a reset can unlock the watchdog config, once locked.
 *
 *   If the LFRCO or LFXO clocks are used to clock the watchdog, one should
 *   consider using the option of inhibiting those clocks to be disabled,
 *   please see the WDOG_Enable() init structure.
 *
 * @note
 *   This function modifies the WDOG CTRL register which requires
 *   synchronization into the low frequency domain. If this register is modified
 *   before a previous update to the same register has completed, this function
 *   will stall until the previous synchronization has completed.
 ******************************************************************************/
void WDOG_Lock(void)
{
  /* Wait for any pending previous write operation to have been completed in */
  /* low frequency domain */
  while (WDOG->SYNCBUSY & WDOG_SYNCBUSY_CTRL)
    ;

  /* Disable writing to the control register */
  BUS_RegBitWrite(&(WDOG->CTRL), _WDOG_CTRL_LOCK_SHIFT, 1);
}
/***************************************************************************//**
 * @brief
 *   Enable or disable EBI Bank
 *
 * @param[in] banks
 *   Banks to reconfigure, mask of EBI_BANK<n> flags
 *
 * @param[in] enable
 *   True to enable, false to disable
 ******************************************************************************/
void EBI_BankEnable(uint32_t banks, bool enable)
{
  if (banks & EBI_BANK0)
  {
    BUS_RegBitWrite(&(EBI->CTRL), _EBI_CTRL_BANK0EN_SHIFT, enable);
  }
  if (banks & EBI_BANK1)
  {
    BUS_RegBitWrite(&(EBI->CTRL), _EBI_CTRL_BANK1EN_SHIFT, enable);
  }
  if (banks & EBI_BANK2)
  {
    BUS_RegBitWrite(&(EBI->CTRL), _EBI_CTRL_BANK2EN_SHIFT, enable);
  }
  if (banks & EBI_BANK3)
  {
    BUS_RegBitWrite(&(EBI->CTRL), _EBI_CTRL_BANK3EN_SHIFT, enable);
  }
}
Exemple #13
0
/***************************************************************************//**
 * @brief
 *   Enable/disable the watchdog timer.
 *
 * @note
 *   This function modifies the WDOG CTRL register which requires
 *   synchronization into the low frequency domain. If this register is modified
 *   before a previous update to the same register has completed, this function
 *   will stall until the previous synchronization has completed.
 *
 * @param[in] enable
 *   true to enable watchdog, false to disable. Watchdog cannot be disabled if
 *   watchdog has been locked.
 ******************************************************************************/
void WDOG_Enable(bool enable)
{
  if (!enable)
  {
    /* Wait for any pending previous write operation to have been completed in */
    /* low frequency domain */
    while (WDOG->SYNCBUSY & WDOG_SYNCBUSY_CTRL)
      ;
  }
  BUS_RegBitWrite(&(WDOG->CTRL), _WDOG_CTRL_EN_SHIFT, enable);
}
Exemple #14
0
/***************************************************************************//**
 * @brief
 *   Configure GPIO interrupt.
 *
 * @details
 *   If reconfiguring a GPIO interrupt that is already enabled, it is generally
 *   recommended to disable it first, see GPIO_Disable().
 *
 *   The actual GPIO interrupt handler must be in place before enabling the
 *   interrupt.
 *
 *   Notice that any pending interrupt for the selected pin is cleared by this
 *   function.
 *
 * @note
 *   A certain pin number can only be associated with one port. Ie, if GPIO
 *   interrupt 1 is assigned to port A/pin 1, then it is not possibly to use
 *   pin 1 from any other ports for interrupts. Please refer to the reference
 *   manual.
 *
 * @param[in] port
 *   The port to associate with @p pin.
 *
 * @param[in] pin
 *   The GPIO interrupt number (= port pin).
 *
 * @param[in] risingEdge
 *   Set to true if interrupts shall be enabled on rising edge, otherwise false.
 *
 * @param[in] fallingEdge
 *   Set to true if interrupts shall be enabled on falling edge, otherwise false.
 *
 * @param[in] enable
 *   Set to true if interrupt shall be enabled after configuration completed,
 *   false to leave disabled. See GPIO_IntDisable() and GPIO_IntEnable().
 ******************************************************************************/
void GPIO_IntConfig(GPIO_Port_TypeDef port,
                    unsigned int pin,
                    bool risingEdge,
                    bool fallingEdge,
                    bool enable)
{
  uint32_t tmp;

  EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));

  /* There are two registers controlling the interrupt configuration:
   * The EXTIPSELL register controls pins 0-7 and EXTIPSELH controls
   * pins 8-15. */
  if (pin < 8)
  {
    BUS_RegMaskedWrite(&GPIO->EXTIPSELL,
                       0xF << (4 * pin),
                       port << (4 * pin));
  }
  else
  {
    tmp             = pin - 8;
    BUS_RegMaskedWrite(&GPIO->EXTIPSELH,
                       0xF << (4 * tmp),
                       port << (4 * tmp));
  }

  /* Enable/disable rising edge */
  BUS_RegBitWrite(&(GPIO->EXTIRISE), pin, risingEdge);

  /* Enable/disable falling edge */
  BUS_RegBitWrite(&(GPIO->EXTIFALL), pin, fallingEdge);

  /* Clear any pending interrupt */
  GPIO->IFC = 1 << pin;

  /* Finally enable/disable interrupt */
  BUS_RegBitWrite(&(GPIO->IEN), pin, enable);
}
/***************************************************************************//**
 * @brief
 *   Configure address operation parameters for selected bank
 *
 * @param[in] banks
 *   Mask of memory bank(s) to configure write timing for
 *
 * @param[in] halfALE
 *   Enables or disables half cycle ALE strobe in last strobe cycle
 ******************************************************************************/
void EBI_BankAddressTimingConfig(uint32_t banks, bool halfALE)
{
  /* Verify only valid banks are used */
  EFM_ASSERT((banks & ~(EBI_BANK0 | EBI_BANK1 | EBI_BANK2 | EBI_BANK3)) == 0);

  if( banks & EBI_BANK0 )
  {
    BUS_RegBitWrite(&EBI->ADDRTIMING, _EBI_ADDRTIMING_HALFALE_SHIFT, halfALE);
  }
  if( banks & EBI_BANK1 )
  {
    BUS_RegBitWrite(&EBI->ADDRTIMING1, _EBI_ADDRTIMING_HALFALE_SHIFT, halfALE);
  }
  if( banks & EBI_BANK2 )
  {
    BUS_RegBitWrite(&EBI->ADDRTIMING2, _EBI_ADDRTIMING_HALFALE_SHIFT, halfALE);
  }
  if( banks & EBI_BANK3 )
  {
    BUS_RegBitWrite(&EBI->ADDRTIMING3, _EBI_ADDRTIMING_HALFALE_SHIFT, halfALE);
  }
}
/***************************************************************************//**
 * @brief
 *   Configure Byte Lane Enable for select banks
 *   timing support
 *
 * @param[in] banks
 *   Mask of memory bank(s) to configure polarity for
 *
 * @param[in] enable
 *   Flag
 ******************************************************************************/
void EBI_BankByteLaneEnable(uint32_t banks, bool enable)
{
  /* Verify only valid banks are used */
  EFM_ASSERT((banks & ~(EBI_BANK0 | EBI_BANK1 | EBI_BANK2 | EBI_BANK3)) == 0);

  /* Configure byte lane support for each selected bank */
  if (banks & EBI_BANK0)
  {
    BUS_RegBitWrite(&(EBI->CTRL), _EBI_CTRL_BL_SHIFT, enable);
  }
  if (banks & EBI_BANK1)
  {
    BUS_RegBitWrite(&(EBI->CTRL), _EBI_CTRL_BL1_SHIFT, enable);
  }
  if (banks & EBI_BANK2)
  {
    BUS_RegBitWrite(&(EBI->CTRL), _EBI_CTRL_BL2_SHIFT, enable);
  }
  if (banks & EBI_BANK3)
  {
    BUS_RegBitWrite(&(EBI->CTRL), _EBI_CTRL_BL3_SHIFT, enable);
  }
}
Exemple #17
0
/***************************************************************************//**
 * @brief
 *   Disable/enable reset for various peripherals and signal sources
 *
 * @param[in] reset Reset types to enable/disable
 *
 * @param[in] enable
 *   @li false - Disable reset signal or flag
 *   @li true - Enable reset signal or flag
 ******************************************************************************/
void RMU_ResetControl(RMU_Reset_TypeDef reset, RMU_ResetMode_TypeDef mode)
{
  /* Note that the RMU supports bit-band access, but not peripheral bit-field set/clear */
#if defined(_RMU_CTRL_PINRMODE_MASK)
  uint32_t val;
#endif
  uint32_t shift;

  shift = EFM32_CTZ((uint32_t)reset);
#if defined(_RMU_CTRL_PINRMODE_MASK)
  val = (uint32_t)mode << shift;
  RMU->CTRL = (RMU->CTRL & ~reset) | val;
#else
  BUS_RegBitWrite(&RMU->CTRL, (uint32_t)shift, mode);
#endif
}
/***************************************************************************//**
 * @brief
 *   Configure EBI pin polarity
 *
 * @param[in] line
 *   Which pin/line to configure
 *
 * @param[in] polarity
 *   Active high, or active low
 ******************************************************************************/
void EBI_PolaritySet(EBI_Line_TypeDef line, EBI_Polarity_TypeDef polarity)
{
  switch (line)
  {
    case ebiLineARDY:
      BUS_RegBitWrite(&(EBI->POLARITY), _EBI_POLARITY_ARDYPOL_SHIFT, polarity);
      break;
    case ebiLineALE:
      BUS_RegBitWrite(&(EBI->POLARITY), _EBI_POLARITY_ALEPOL_SHIFT, polarity);
      break;
    case ebiLineWE:
      BUS_RegBitWrite(&(EBI->POLARITY), _EBI_POLARITY_WEPOL_SHIFT, polarity);
      break;
    case ebiLineRE:
      BUS_RegBitWrite(&(EBI->POLARITY), _EBI_POLARITY_REPOL_SHIFT, polarity);
      break;
    case ebiLineCS:
      BUS_RegBitWrite(&(EBI->POLARITY), _EBI_POLARITY_CSPOL_SHIFT, polarity);
      break;
#if defined (_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    case ebiLineBL:
      BUS_RegBitWrite(&(EBI->POLARITY), _EBI_POLARITY_BLPOL_SHIFT, polarity);
      break;
    case ebiLineTFTVSync:
      BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_VSYNCPOL_SHIFT, polarity);
      break;
    case ebiLineTFTHSync:
      BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_HSYNCPOL_SHIFT, polarity);
      break;
    case ebiLineTFTDataEn:
      BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_DATAENPOL_SHIFT, polarity);
      break;
    case ebiLineTFTDClk:
      BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_DCLKPOL_SHIFT, polarity);
      break;
    case ebiLineTFTCS:
      BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_CSPOL_SHIFT, polarity);
      break;
#endif
    default:
      EFM_ASSERT(0);
      break;
  }
}
Exemple #19
0
/***************************************************************************//**
 * @brief Reset counter
 ******************************************************************************/
void BURTC_CounterReset(void)
{
  /* Set and clear reset bit */
  BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 1);
  BUS_RegBitWrite(&BURTC->CTRL, _BURTC_CTRL_RSTEN_SHIFT, 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(_LCD_SEGD7L_MASK)
  /* 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(_LCD_SEGD0H_MASK)
  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)
      {
        BUS_RegBitWrite(&(LCD->SEGD0L), bit, enable);
      }
#if defined(_LCD_SEGD0H_MASK)
      else
      {
        bit -= 32;
        BUS_RegBitWrite(&(LCD->SEGD0H), bit, enable);
      }
#endif
      break;
    case 1:
      if (bit < 32)
      {
        BUS_RegBitWrite(&(LCD->SEGD1L), bit, enable);
      }
#if defined(_LCD_SEGD1H_MASK)
      else
      {
        bit -= 32;
        BUS_RegBitWrite(&(LCD->SEGD1H), bit, enable);
      }
#endif
      break;
    case 2:
      if (bit < 32)
      {
        BUS_RegBitWrite(&(LCD->SEGD2L), bit, enable);
      }
#if defined(_LCD_SEGD2H_MASK)
      else
      {
        bit -= 32;
        BUS_RegBitWrite(&(LCD->SEGD2H), bit, enable);
      }
#endif
      break;
    case 3:
      if (bit < 32)
      {
        BUS_RegBitWrite(&(LCD->SEGD3L), bit, enable);
      }
#if defined(_LCD_SEGD3H_MASK)
      else
      {
        bit -= 32;
        BUS_RegBitWrite(&(LCD->SEGD3H), bit, enable);
      }
#endif
      break;
#if defined(_LCD_SEGD4L_MASK)
    case 4:
      if (bit < 32)
      {
        BUS_RegBitWrite(&(LCD->SEGD4L), bit, enable);
      }
#if defined(_LCD_SEGD4H_MASK)
      else
      {
        bit -= 32;
        BUS_RegBitWrite(&(LCD->SEGD4H), bit, enable);
      }
#endif
      break;
#endif
#if defined(_LCD_SEGD5L_MASK)
    case 5:
      if (bit < 32)
      {
        BUS_RegBitWrite(&(LCD->SEGD5L), bit, enable);
      }
#if defined(_LCD_SEGD5H_MASK)
      else
      {
        bit -= 32;
        BUS_RegBitWrite(&(LCD->SEGD5H), bit, enable);
      }
#endif
      break;
#endif
    case 6:
#if defined(_LCD_SEGD6L_MASK)
      if (bit < 32)
      {
        BUS_RegBitWrite(&(LCD->SEGD6L), bit, enable);
      }
#if defined(_LCD_SEGD6H_MASK)
      else
      {
        bit -= 32;
        BUS_RegBitWrite(&(LCD->SEGD6H), bit, enable);
      }
#endif
      break;
#endif
#if defined(_LCD_SEGD7L_MASK)
    case 7:
      if (bit < 32)
      {
        BUS_RegBitWrite(&(LCD->SEGD7L), bit, enable);
      }
#if defined(_LCD_SEGD7H_MASK)
      else
      {
        bit -= 32;
        BUS_RegBitWrite(&(LCD->SEGD7H), bit, enable);
      }
#endif
      break;
#endif

    default:
      EFM_ASSERT(0);
      break;
  }
}
Exemple #21
0
/***************************************************************************//**
 * @brief
 *   Initialize watchdog (assuming the watchdog configuration has not been
 *   locked).
 *
 * @note
 *   This function modifies the WDOG CTRL register which requires
 *   synchronization into the low frequency domain. If this register is modified
 *   before a previous update to the same register has completed, this function
 *   will stall until the previous synchronization has completed.
 *
 * @param[in] init
 *   Structure holding watchdog configuration. A default setting
 *   #WDOG_INIT_DEFAULT is available for init.
 ******************************************************************************/
void WDOG_Init(const WDOG_Init_TypeDef *init)
{
  uint32_t setting;

  if (init->enable)
  {
    setting = WDOG_CTRL_EN;
  }
  else
  {
    setting = 0;
  }

  if (init->debugRun)
  {
    setting |= WDOG_CTRL_DEBUGRUN;
  }

  if (init->em2Run)
  {
    setting |= WDOG_CTRL_EM2RUN;
  }

  if (init->em3Run)
  {
    setting |= WDOG_CTRL_EM3RUN;
  }

  if (init->em4Block)
  {
    setting |= WDOG_CTRL_EM4BLOCK;
  }

  if (init->swoscBlock)
  {
    setting |= WDOG_CTRL_SWOSCBLOCK;
  }

  setting |= ((uint32_t)(init->clkSel)   << _WDOG_CTRL_CLKSEL_SHIFT)
             | ((uint32_t)(init->perSel) << _WDOG_CTRL_PERSEL_SHIFT);

  /* Wait for any pending previous write operation to have been completed in */
  /* low frequency domain */
  while (WDOG->SYNCBUSY & WDOG_SYNCBUSY_CTRL)
    ;

  WDOG->CTRL = setting;

  /* Optional register locking */
  if (init->lock)
  {
    if (init->enable)
    {
      WDOG_Lock();
    }
    else
    {
      BUS_RegBitWrite(&(WDOG->CTRL), _WDOG_CTRL_LOCK_SHIFT, 1);
    }
  }
}
/***************************************************************************//**
 * @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));

#ifdef PCNT0
  if (PCNT0 == pcnt)
  {
    EFM_ASSERT((1<<PCNT0_CNT_SIZE) > init->counter);
    EFM_ASSERT((1<<PCNT0_CNT_SIZE) > init->top);
  }
#endif

#ifdef PCNT1
  if (PCNT1 == pcnt)
  {
    EFM_ASSERT((1<<PCNT1_CNT_SIZE) > init->counter);
    EFM_ASSERT((1<<PCNT1_CNT_SIZE) > init->top);
  }
#endif

#ifdef PCNT2
  if (PCNT2 == pcnt)
  {
    EFM_ASSERT((1<<PCNT2_CNT_SIZE) > init->counter);
    EFM_ASSERT((1<<PCNT2_CNT_SIZE) > init->top);
  }
#endif

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

#if defined(_PCNT_INPUT_MASK)
  /* 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(PCNT_CTRL_HYST)
  if (init->hyst)
  {
    tmp |= PCNT_CTRL_HYST;
  }
#endif

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

  /* Configure counter events for regular and auxiliary counter. */
#if defined(_PCNT_CTRL_CNTEV_SHIFT)
  tmp |= init->cntEvent << _PCNT_CTRL_CNTEV_SHIFT;
#endif

#if defined(_PCNT_CTRL_AUXCNTEV_SHIFT)
  {
    /* Modify the auxCntEvent value before writing to the AUXCNTEV field in
       the CTRL register because the AUXCNTEV field values are different from
       the CNTEV field values, and cntEvent and auxCntEvent are of the same type
       PCNT_CntEvent_TypeDef.
    */
    uint32_t auxCntEventField = 0; /* Get rid of compiler warning. */
    switch (init->auxCntEvent)
    {
      case pcntCntEventBoth:
        auxCntEventField = pcntCntEventNone;
        break;
      case pcntCntEventNone:
        auxCntEventField = pcntCntEventBoth;
        break;
      case pcntCntEventUp:
      case pcntCntEventDown:
        auxCntEventField = init->auxCntEvent;
        break;
      default:
        /* Invalid parameter, asserted. */
        EFM_ASSERT(0);
        break;
    }
    tmp |= auxCntEventField << _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. */
  BUS_RegBitWrite(&(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. */
      BUS_RegBitWrite(&(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;
  }
}
Exemple #23
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);
}
/***************************************************************************//**
 * @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);
}
/***************************************************************************//**
 * @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:
        BUS_RegBitWrite(polRegister, _EBI_POLARITY_ARDYPOL_SHIFT, polarity);
        break;
      case ebiLineALE:
        BUS_RegBitWrite(polRegister, _EBI_POLARITY_ALEPOL_SHIFT, polarity);
        break;
      case ebiLineWE:
        BUS_RegBitWrite(polRegister, _EBI_POLARITY_WEPOL_SHIFT, polarity);
        break;
      case ebiLineRE:
        BUS_RegBitWrite(polRegister, _EBI_POLARITY_REPOL_SHIFT, polarity);
        break;
      case ebiLineCS:
        BUS_RegBitWrite(polRegister, _EBI_POLARITY_CSPOL_SHIFT, polarity);
        break;
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
      case ebiLineBL:
        BUS_RegBitWrite(polRegister, _EBI_POLARITY_BLPOL_SHIFT, polarity);
        break;
      case ebiLineTFTVSync:
        BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_VSYNCPOL_SHIFT, polarity);
        break;
      case ebiLineTFTHSync:
        BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_HSYNCPOL_SHIFT, polarity);
        break;
      case ebiLineTFTDataEn:
        BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_DATAENPOL_SHIFT, polarity);
        break;
      case ebiLineTFTDClk:
        BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_DCLKPOL_SHIFT, polarity);
        break;
      case ebiLineTFTCS:
        BUS_RegBitWrite(&(EBI->TFTPOLARITY), _EBI_TFTPOLARITY_CSPOL_SHIFT, polarity);
        break;
#endif
      default:
        EFM_ASSERT(0);
        break;
    }
    banks = banks & ~bankSet;
  }
}
/***************************************************************************//**
 * @brief
 *   Configure read operation parameters for selected bank
 *
 * @param[in] banks
 *   Mask of memory bank(s) to configure write timing for
 *
 * @param[in] pageMode
 *   Enables or disables half cycle WE strobe in last strobe cycle
 *
 * @param[in] prefetch
 *   Enables or disables half cycle WE strobe in last strobe cycle
 *
 * @param[in] halfRE
 *   Enables or disables half cycle WE strobe in last strobe cycle
 ******************************************************************************/
void EBI_BankReadTimingConfig(uint32_t banks, bool pageMode, bool prefetch, bool halfRE)
{
 /* Verify only valid banks are used */
  EFM_ASSERT((banks & ~(EBI_BANK0 | EBI_BANK1 | EBI_BANK2 | EBI_BANK3)) == 0);

  /* Configure read operation parameters */
  if( banks & EBI_BANK0 )
  {
    BUS_RegBitWrite(&EBI->RDTIMING, _EBI_RDTIMING_PAGEMODE_SHIFT, pageMode);
    BUS_RegBitWrite(&EBI->RDTIMING, _EBI_RDTIMING_PREFETCH_SHIFT, prefetch);
    BUS_RegBitWrite(&EBI->RDTIMING, _EBI_RDTIMING_HALFRE_SHIFT, halfRE);
  }
  if( banks & EBI_BANK1 )
  {
    BUS_RegBitWrite(&EBI->RDTIMING1, _EBI_RDTIMING_PAGEMODE_SHIFT, pageMode);
    BUS_RegBitWrite(&EBI->RDTIMING1, _EBI_RDTIMING_PREFETCH_SHIFT, prefetch);
    BUS_RegBitWrite(&EBI->RDTIMING1, _EBI_RDTIMING_HALFRE_SHIFT, halfRE);
  }
  if( banks & EBI_BANK2 )
  {
    BUS_RegBitWrite(&EBI->RDTIMING2, _EBI_RDTIMING_PAGEMODE_SHIFT, pageMode);
    BUS_RegBitWrite(&EBI->RDTIMING2, _EBI_RDTIMING_PREFETCH_SHIFT, prefetch);
    BUS_RegBitWrite(&EBI->RDTIMING2, _EBI_RDTIMING_HALFRE_SHIFT, halfRE);
  }
  if( banks & EBI_BANK3 )
  {
    BUS_RegBitWrite(&EBI->RDTIMING3, _EBI_RDTIMING_PAGEMODE_SHIFT, pageMode);
    BUS_RegBitWrite(&EBI->RDTIMING3, _EBI_RDTIMING_PREFETCH_SHIFT, prefetch);
    BUS_RegBitWrite(&EBI->RDTIMING3, _EBI_RDTIMING_HALFRE_SHIFT, halfRE);
  }
}
/***************************************************************************//**
 * @brief
 *   Configure and enable External Bus Interface
 *
 * @param[in] ebiInit
 *   EBI configuration structure
 *
 * @note
 *   GPIO lines must be configured as PUSH_PULL for correct operation
 *   GPIO and EBI clocks must be enabled in the CMU
 ******************************************************************************/
void EBI_Init(const EBI_Init_TypeDef *ebiInit)
{
  uint32_t ctrl = EBI->CTRL;

#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  /* Enable Independent Timing for devices that supports it */
  ctrl |= EBI_CTRL_ITS;

  /* Set polarity of address ready */
  EBI_BankPolaritySet(ebiInit->banks, ebiLineARDY, ebiInit->ardyPolarity);
  /* Set polarity of address latch enable */
  EBI_BankPolaritySet(ebiInit->banks, ebiLineALE, ebiInit->alePolarity);
  /* Set polarity of write enable */
  EBI_BankPolaritySet(ebiInit->banks, ebiLineWE, ebiInit->wePolarity);
  /* Set polarity of read enable */
  EBI_BankPolaritySet(ebiInit->banks, ebiLineRE, ebiInit->rePolarity);
  /* Set polarity of chip select lines */
  EBI_BankPolaritySet(ebiInit->banks, ebiLineCS, ebiInit->csPolarity);
  /* Set polarity of byte lane line */
  EBI_BankPolaritySet(ebiInit->banks, ebiLineBL, ebiInit->blPolarity);
#else
  /* Set polarity of address ready */
  EBI_PolaritySet(ebiLineARDY, ebiInit->ardyPolarity);
  /* Set polarity of address latch enable */
  EBI_PolaritySet(ebiLineALE, ebiInit->alePolarity);
  /* Set polarity of write enable */
  EBI_PolaritySet(ebiLineWE, ebiInit->wePolarity);
  /* Set polarity of read enable */
  EBI_PolaritySet(ebiLineRE, ebiInit->rePolarity);
  /* Set polarity of chip select lines */
  EBI_PolaritySet(ebiLineCS, ebiInit->csPolarity);
#endif

  /* Configure EBI mode and control settings  */
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  if (ebiInit->banks & EBI_BANK0)
  {
    ctrl &= ~(_EBI_CTRL_MODE_MASK
              | _EBI_CTRL_ARDYEN_MASK
              | _EBI_CTRL_ARDYTODIS_MASK
              | _EBI_CTRL_BL_MASK
              | _EBI_CTRL_NOIDLE_MASK
              | _EBI_CTRL_BANK0EN_MASK);
    ctrl |= (ebiInit->mode << _EBI_CTRL_MODE_SHIFT);
    ctrl |= (ebiInit->ardyEnable << _EBI_CTRL_ARDYEN_SHIFT);
    ctrl |= (ebiInit->ardyDisableTimeout << _EBI_CTRL_ARDYTODIS_SHIFT);
    ctrl |= (ebiInit->blEnable << _EBI_CTRL_BL_SHIFT);
    ctrl |= (ebiInit->noIdle << _EBI_CTRL_NOIDLE_SHIFT);
    if ( ebiInit->enable)
    {
      ctrl |= EBI_CTRL_BANK0EN;
    }
  }
  if (ebiInit->banks & EBI_BANK1)
  {
    ctrl &= ~(_EBI_CTRL_BL1_MASK
              | _EBI_CTRL_MODE1_MASK
              | _EBI_CTRL_ARDY1EN_MASK
              | _EBI_CTRL_ARDYTO1DIS_MASK
              | _EBI_CTRL_NOIDLE1_MASK
              | _EBI_CTRL_BANK1EN_MASK);
    ctrl |= (ebiInit->mode << _EBI_CTRL_MODE1_SHIFT);
    ctrl |= (ebiInit->ardyEnable << _EBI_CTRL_ARDY1EN_SHIFT);
    ctrl |= (ebiInit->ardyDisableTimeout << _EBI_CTRL_ARDYTO1DIS_SHIFT);
    ctrl |= (ebiInit->blEnable << _EBI_CTRL_BL1_SHIFT);
    ctrl |= (ebiInit->noIdle << _EBI_CTRL_NOIDLE1_SHIFT);
    if ( ebiInit->enable)
    {
      ctrl |= EBI_CTRL_BANK1EN;
    }
  }
  if (ebiInit->banks & EBI_BANK2)
  {
    ctrl &= ~(_EBI_CTRL_BL2_MASK
              | _EBI_CTRL_MODE2_MASK
              | _EBI_CTRL_ARDY2EN_MASK
              | _EBI_CTRL_ARDYTO2DIS_MASK
              | _EBI_CTRL_NOIDLE2_MASK
              | _EBI_CTRL_BANK2EN_MASK);
    ctrl |= (ebiInit->mode << _EBI_CTRL_MODE2_SHIFT);
    ctrl |= (ebiInit->ardyEnable << _EBI_CTRL_ARDY2EN_SHIFT);
    ctrl |= (ebiInit->ardyDisableTimeout << _EBI_CTRL_ARDYTO2DIS_SHIFT);
    ctrl |= (ebiInit->blEnable << _EBI_CTRL_BL2_SHIFT);
    ctrl |= (ebiInit->noIdle << _EBI_CTRL_NOIDLE2_SHIFT);
    if ( ebiInit->enable)
    {
      ctrl |= EBI_CTRL_BANK2EN;
    }
  }
  if (ebiInit->banks & EBI_BANK3)
  {
    ctrl &= ~(_EBI_CTRL_BL3_MASK
              | _EBI_CTRL_MODE3_MASK
              | _EBI_CTRL_ARDY3EN_MASK
              | _EBI_CTRL_ARDYTO3DIS_MASK
              | _EBI_CTRL_NOIDLE3_MASK
              | _EBI_CTRL_BANK3EN_MASK);
    ctrl |= (ebiInit->mode << _EBI_CTRL_MODE3_SHIFT);
    ctrl |= (ebiInit->ardyEnable << _EBI_CTRL_ARDY3EN_SHIFT);
    ctrl |= (ebiInit->ardyDisableTimeout << _EBI_CTRL_ARDYTO3DIS_SHIFT);
    ctrl |= (ebiInit->blEnable << _EBI_CTRL_BL3_SHIFT);
    ctrl |= (ebiInit->noIdle << _EBI_CTRL_NOIDLE3_SHIFT);
    if ( ebiInit->enable)
    {
      ctrl |= EBI_CTRL_BANK3EN;
    }
  }
#else
  ctrl &= ~(_EBI_CTRL_MODE_MASK
            | _EBI_CTRL_ARDYEN_MASK
            | _EBI_CTRL_ARDYTODIS_MASK
            | _EBI_CTRL_BANK0EN_MASK
            | _EBI_CTRL_BANK1EN_MASK
            | _EBI_CTRL_BANK2EN_MASK
            | _EBI_CTRL_BANK3EN_MASK);
  if ( ebiInit->enable)
  {
    if ( ebiInit->banks & EBI_BANK0 )
    {
      ctrl |= EBI_CTRL_BANK0EN;
    }
    if ( ebiInit->banks & EBI_BANK1 )
    {
      ctrl |= EBI_CTRL_BANK1EN;
    }
    if ( ebiInit->banks & EBI_BANK2 )
    {
      ctrl |= EBI_CTRL_BANK2EN;
    }
    if ( ebiInit->banks & EBI_BANK3 )
    {
      ctrl |= EBI_CTRL_BANK3EN;
    }
  }
  ctrl |= ebiInit->mode;
  ctrl |= (ebiInit->ardyEnable << _EBI_CTRL_ARDYEN_SHIFT);
  ctrl |= (ebiInit->ardyDisableTimeout << _EBI_CTRL_ARDYTODIS_SHIFT);
#endif

  /* Configure timing */
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  EBI_BankReadTimingSet(ebiInit->banks,
                        ebiInit->readSetupCycles,
                        ebiInit->readStrobeCycles,
                        ebiInit->readHoldCycles);
  EBI_BankReadTimingConfig(ebiInit->banks,
                           ebiInit->readPageMode,
                           ebiInit->readPrefetch,
                           ebiInit->readHalfRE);
  EBI_BankWriteTimingSet(ebiInit->banks,
                         ebiInit->writeSetupCycles,
                         ebiInit->writeStrobeCycles,
                         ebiInit->writeHoldCycles);
  EBI_BankWriteTimingConfig(ebiInit->banks,
                            ebiInit->writeBufferDisable,
                            ebiInit->writeHalfWE);
  EBI_BankAddressTimingSet(ebiInit->banks,
                           ebiInit->addrSetupCycles,
                           ebiInit->addrHoldCycles);
  EBI_BankAddressTimingConfig(ebiInit->banks,
                              ebiInit->addrHalfALE);
#else
  EBI_ReadTimingSet(ebiInit->readSetupCycles,
                    ebiInit->readStrobeCycles,
                    ebiInit->readHoldCycles);
  EBI_WriteTimingSet(ebiInit->writeSetupCycles,
                     ebiInit->writeStrobeCycles,
                     ebiInit->writeHoldCycles);
  EBI_AddressTimingSet(ebiInit->addrSetupCycles,
                       ebiInit->addrHoldCycles);
#endif

  /* Activate new configuration */
  EBI->CTRL = ctrl;

  /* Configure Adress Latch Enable */
  switch (ebiInit->mode)
  {
    case ebiModeD16A16ALE:
    case ebiModeD8A24ALE:
      /* Address Latch Enable */
      BUS_RegBitWrite(&(EBI->ROUTE), _EBI_ROUTE_ALEPEN_SHIFT, 1);
      break;
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
    case ebiModeD16:
#endif
    case ebiModeD8A8:
      /* Make sure Address Latch is disabled */
      BUS_RegBitWrite(&(EBI->ROUTE), _EBI_ROUTE_ALEPEN_SHIFT, 0);
      break;
  }
#if defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
  /* Limit pin enable */
  EBI->ROUTE = (EBI->ROUTE & ~_EBI_ROUTE_ALB_MASK) | ebiInit->aLow;
  EBI->ROUTE = (EBI->ROUTE & ~_EBI_ROUTE_APEN_MASK) | ebiInit->aHigh;
  /* Location */
  EBI->ROUTE = (EBI->ROUTE & ~_EBI_ROUTE_LOCATION_MASK) | ebiInit->location;

  /* Enable EBI BL pin if necessary */
  if(ctrl & (_EBI_CTRL_BL_MASK|_EBI_CTRL_BL1_MASK|_EBI_CTRL_BL2_MASK|_EBI_CTRL_BL3_MASK))
  {
    BUS_RegBitWrite(&(EBI->ROUTE), _EBI_ROUTE_BLPEN_SHIFT, ebiInit->blEnable);
  }
#endif
  /* Enable EBI pins EBI_WEn and EBI_REn */
  BUS_RegBitWrite(&(EBI->ROUTE), _EBI_ROUTE_EBIPEN_SHIFT, 1);

  /* Enable chip select lines */
  EBI_ChipSelectEnable(ebiInit->csLines, true);
}
/***************************************************************************//**
 * @brief
 *   Configure Alternate Address Map support
 *   Enables or disables 256MB address range for all banks
 *
 * @param[in] enable
 *   Set or clear address map extension
 ******************************************************************************/
void EBI_AltMapEnable(bool enable)
{
  BUS_RegBitWrite(&(EBI->CTRL), _EBI_CTRL_ALTMAP_SHIFT, enable);
}