Пример #1
0
/***************************************************************************//**
 * @brief
 *   Set the mode for a GPIO pin.
 *
 * @param[in] port
 *   The GPIO port to access.
 *
 * @param[in] pin
 *   The pin number in the port.
 *
 * @param[in] mode
 *   The desired pin mode.
 *
 * @param[in] out
 *   Value to set for pin in DOUT register. The DOUT setting is important for
 *   even some input mode configurations, determining pull-up/down direction.
 ******************************************************************************/
void GPIO_PinModeSet(GPIO_Port_TypeDef port,
                     unsigned int pin,
                     GPIO_Mode_TypeDef mode,
                     unsigned int out)
{
  EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));

  /* If disabling pin, do not modify DOUT in order to reduce chance for */
  /* glitch/spike (may not be sufficient precaution in all use cases) */
  if (mode != gpioModeDisabled)
  {
    if (out)
    {
      GPIO_PinOutSet(port, pin);
    }
    else
    {
      GPIO_PinOutClear(port, pin);
    }
  }

  /* There are two registers controlling the pins for each port. The MODEL
   * register controls pins 0-7 and MODEH controls pins 8-15. */
  if (pin < 8)
  {
    BUS_RegMaskedWrite(&GPIO->P[port].MODEL,
                       0xF << (pin * 4),
                       mode << (pin * 4));
  }
  else
  {
    BUS_RegMaskedWrite(&GPIO->P[port].MODEH,
                       0xF << ((pin - 8) * 4),
                       mode << ((pin - 8) * 4));
  }

  if (mode == gpioModeDisabled)
  {
    if (out)
    {
      GPIO_PinOutSet(port, pin);
    }
    else
    {
      GPIO_PinOutClear(port, pin);
    }
  }
}
Пример #2
0
/***************************************************************************//**
 * @brief
 *   Sets the drive strength for a GPIO port.
 *
 * @param[in] port
 *   The GPIO port to access.
 *
 * @param[in] strength
 *   Drive strength to use for port.
 ******************************************************************************/
void GPIO_DriveStrengthSet(GPIO_Port_TypeDef port,
                           GPIO_DriveStrength_TypeDef strength)
{
  EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_STRENGHT_VALID(strength));
  BUS_RegMaskedWrite(&GPIO->P[port].CTRL,
                     _GPIO_P_CTRL_DRIVESTRENGTH_MASK | _GPIO_P_CTRL_DRIVESTRENGTHALT_MASK,
                     strength);
}
Пример #3
0
/***************************************************************************//**
 * @brief
 *   Configure USART operating in synchronous mode to use a given baudrate
 *   (or as close as possible to specified baudrate).
 *
 * @details
 *   The configuration will be set to use a baudrate <= the specified baudrate
 *   in order to ensure that the baudrate does not exceed the specified value.
 *
 *   Fractional clock division is suppressed, although the HW design allows it.
 *   It could cause half clock cycles to exceed specified limit, and thus
 *   potentially violate specifications for the slave device. In some special
 *   situations fractional clock division may be useful even in synchronous
 *   mode, but in those cases it must be directly adjusted, possibly assisted
 *   by USART_BaudrateCalc():
 *
 * @param[in] usart
 *   Pointer to USART peripheral register block. (Cannot be used on UART
 *   modules.)
 *
 * @param[in] refFreq
 *   USART 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.
 ******************************************************************************/
void USART_BaudrateSyncSet(USART_TypeDef *usart, uint32_t refFreq, uint32_t baudrate)
{
#if defined(_USART_CLKDIV_DIV_MASK) && (_USART_CLKDIV_DIV_MASK >= 0x7FFFF8UL)
  uint64_t clkdiv;
#else
  uint32_t clkdiv;
#endif

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

  /*
   * CLKDIV in synchronous mode is given by:
   *
   * CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1)
   */

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

#if defined(_USART_CLKDIV_DIV_MASK) && (_USART_CLKDIV_DIV_MASK >= 0x7FFFF8UL)
  /* Calculate and set CLKDIV without fractional bits */
  clkdiv = 2 * baudrate;
  clkdiv = (0x100ULL * (uint64_t)refFreq) / clkdiv;

  /* Round up by not subtracting 256 and mask off fractional part */
  clkdiv &= ~0xFF;
#else
  /* Calculate and set CLKDIV with fractional bits */
  clkdiv  = 2 * refFreq;
  clkdiv += baudrate - 1;
  clkdiv /= baudrate;
  clkdiv -= 4;
  clkdiv *= 64;
  /* Make sure we don't use fractional bits by rounding CLKDIV */
  /* up (and thus reducing baudrate, not increasing baudrate above */
  /* specified value). */
  clkdiv += 0xc0;
  clkdiv &= 0xffffff00;
#endif

  /* Verify that resulting clock divider is within limits */
  EFM_ASSERT(!(clkdiv & ~_USART_CLKDIV_DIV_MASK));

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

  BUS_RegMaskedWrite(&usart->CLKDIV, _USART_CLKDIV_DIV_MASK, clkdiv);
}
Пример #4
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);
}
Пример #5
0
/***************************************************************************//**
 * @brief
 *   Send the data from the Message Object message.
 *
 * @details
 *   If message is configured as tx and remoteTransfer = 0, calling this function
 *   will send the data of this Message Object if its parameters are correct.
 *   If message is tx and remoteTransfer = 1, this function will set the data of
 *   message to the RAM and exit, the data will be automatically sent after
 *   reception of a remote frame.
 *   If message is rx and remoteTransfer = 1, this function will send a remote
 *   frame to the corresponding id.
 *   If message is rx and remoteTransfer = 0, the user shouldn't call this
 *   function. It will also send a remote frame.
 *
 * @param[in] can
 *   Pointer to CAN peripheral register block.
 *
 * @param[in] interface
 *   Indicate which Message Interface Register to use.
 *
 * @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_SendMessage(CAN_TypeDef *can,
                     uint8_t interface,
                     const CAN_MessageObject_TypeDef *message,
                     bool wait)
{
  CAN_MIR_TypeDef * mir = &can->MIR[interface];

  /* Make sure msgNum is in the correct range */
  EFM_ASSERT((message->msgNum > 0) && (message->msgNum <= 32));
  /* Make sure dlc is in the correct range */
  EFM_ASSERT(message->dlc <= _CAN_MIR_CTRL_DLC_MASK);

  CAN_ReadyWait(can, interface);

  /* Set LEC to unused value to be sure it is reset to 0 after sending */
  BUS_RegMaskedWrite(&can->STATUS, _CAN_STATUS_LEC_MASK, 0x7);

  /* 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_DATAA
                  | CAN_MIR_CMDMASK_DATAB;

  /* If tx = 1 and remoteTransfer = 1, nothing is sent */
  if ( ((mir->CTRL & _CAN_MIR_CTRL_RMTEN_MASK) == 0)
       || ((mir->ARB & _CAN_MIR_ARB_DIR_MASK) == _CAN_MIR_ARB_DIR_RX)) {
    mir->CTRL |= CAN_MIR_CTRL_TXRQST;
    /* DATAVALID is set only if it is not sending a remote message */
    if ((mir->CTRL & _CAN_MIR_CTRL_RMTEN_MASK) == 0) {
      mir->CTRL |= CAN_MIR_CTRL_DATAVALID;
    }
  }

  /* Set the Data length Code */
  mir->CTRL = (mir->CTRL & ~_CAN_MIR_CTRL_DLC_MASK)
              | message->dlc;

  /* 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_MASK))
               | (uint32_t)(0x1 << _CAN_MIR_ARB_MSGVAL_SHIFT)
               | (message->id << _CAN_MIR_ARB_STD_ID_SHIFT)
               | CAN_MIR_ARB_XTD_STD;
  }

  /* Set the data */
  CAN_WriteData(can, interface, message);

  /* Send writing request */
  CAN_SendRequest(can, interface, message->msgNum, wait);
}
Пример #6
0
/***************************************************************************//**
 * @brief
 *   Set I2C bus frequency.
 *
 * @details
 *   The bus frequency is only of relevance when acting as a master. The bus
 *   frequency should not be set higher than the max frequency accepted by the
 *   slowest device on the bus.
 *
 *   Notice that due to asymmetric requirements on low and high I2C clock
 *   cycles by the I2C specification, the actual max frequency allowed in order
 *   to comply with the specification may be somewhat lower than expected.
 *
 *   Please refer to the reference manual, details on I2C clock generation,
 *   for max allowed theoretical frequencies for different modes.
 *
 * @param[in] i2c
 *   Pointer to I2C peripheral register block.
 *
 * @param[in] freqRef
 *   I2C reference clock frequency in Hz that will be used. If set to 0,
 *   then HFPER clock is used. Setting it to a higher than actual configured
 *   value only has the consequence of reducing the real I2C frequency.
 *
 * @param[in] freqScl
 *   Bus frequency to set (actual bus speed may be lower due to integer
 *   prescaling). Safe (according to I2C specification) max frequencies for
 *   standard, fast and fast+ modes are available using I2C_FREQ_ defines.
 *   (Using I2C_FREQ_ defines requires corresponding setting of @p type.)
 *   Slowest slave device on bus must always be considered.
 *
 * @param[in] i2cMode
 *   Clock low to high ratio type to use. If not using i2cClockHLRStandard,
 *   make sure all devices on the bus support the specified mode. Using a
 *   non-standard ratio is useful to achieve higher bus clock in fast and
 *   fast+ modes.
 ******************************************************************************/
void I2C_BusFreqSet(I2C_TypeDef *i2c,
                    uint32_t freqRef,
                    uint32_t freqScl,
                    I2C_ClockHLR_TypeDef i2cMode)
{
  uint32_t n, minFreq;
  int32_t div;

  /* Avoid divide by 0 */
  EFM_ASSERT(freqScl);
  if (!freqScl)
  {
    return;
  }

  /* Set the CLHR (clock low to high ratio). */
  i2c->CTRL &= ~_I2C_CTRL_CLHR_MASK;
  BUS_RegMaskedWrite(&i2c->CTRL,
                     _I2C_CTRL_CLHR_MASK,
                     i2cMode <<_I2C_CTRL_CLHR_SHIFT);

  if (!freqRef)
  {
    freqRef = CMU_ClockFreqGet(cmuClock_HFPER);
  }

    /* Check minumum HF peripheral clock */
  minFreq = UINT_MAX;
  if (i2c->CTRL & I2C_CTRL_SLAVE)
  {
    switch(i2cMode)
    {
      case i2cClockHLRStandard:
#if defined( _SILICON_LABS_32B_PLATFORM_1 )
        minFreq = 4200000; break;
#elif defined( _SILICON_LABS_32B_PLATFORM_2 )
        minFreq = 2000000; break;
#endif
      case i2cClockHLRAsymetric:
#if defined( _SILICON_LABS_32B_PLATFORM_1 )
        minFreq = 11000000; break;
#elif defined( _SILICON_LABS_32B_PLATFORM_2 )
        minFreq = 5000000; break;
#endif
      case i2cClockHLRFast:
#if defined( _SILICON_LABS_32B_PLATFORM_1 )
        minFreq = 24400000; break;
#elif defined( _SILICON_LABS_32B_PLATFORM_2 )
        minFreq = 14000000; break;
#endif
    }
  }
  else
  {
    /* For master mode, platform 1 and 2 share the same
       min frequencies */
    switch(i2cMode)
    {
      case i2cClockHLRStandard:
        minFreq = 2000000; break;
      case i2cClockHLRAsymetric:
        minFreq = 9000000; break;
      case i2cClockHLRFast:
        minFreq = 20000000; break;
    }
  }

  /* Frequency most be larger-than */
  EFM_ASSERT(freqRef > minFreq);

  /* SCL frequency is given by
   * freqScl = freqRef/((Nlow + Nhigh) * (DIV + 1) + I2C_CR_MAX)
   *
   * Thus
   * DIV = ((freqRef - (I2C_CR_MAX * freqScl))/((Nlow + Nhigh) * freqScl)) - 1
   *
   * More details can be found in the reference manual,
   * I2C Clock Generation chapter.  */

  /* n = Nlow + Nhigh */
  n = (uint32_t)(i2cNSum[i2cMode]);
  div = ((freqRef - (I2C_CR_MAX * freqScl)) / (n * freqScl)) - 1;
  EFM_ASSERT(div >= 0);
  EFM_ASSERT((uint32_t)div <= _I2C_CLKDIV_DIV_MASK);

  /* Clock divisor must be at least 1 in slave mode according to reference */
  /* manual (in which case there is normally no need to set bus frequency). */
  if ((i2c->CTRL & I2C_CTRL_SLAVE) && !div)
  {
    div = 1;
  }
  i2c->CLKDIV = (uint32_t)div;
}