Exemplo n.º 1
0
/**
 * @brief   Enables a PWM channel.
 * @pre     The PWM unit must have been activated using @p pwmStart().
 * @post    The channel is active using the specified configuration.
 * @note    The function has effect at the next cycle start.
 * @note    Channel notification is not enabled.
 *
 * @param[in] pwmp      pointer to a @p PWMDriver object
 * @param[in] channel   PWM channel identifier (0...channels-1)
 * @param[in] width     PWM pulse width as clock pulses number
 *
 * @notapi
 */
void pwm_lld_enable_channel(PWMDriver *pwmp,
                            pwmchannel_t channel,
                            pwmcnt_t width) {
#if NRF5_PWM_USE_GPIOTE_PPI
  const PWMChannelConfig *cfg_channel = &pwmp->config->channels[channel];
  const uint8_t  gpiote_channel = cfg_channel->gpiote_channel;
  const uint8_t *ppi_channel    = cfg_channel->ppi_channel;
  
  uint32_t outinit;
  switch(cfg_channel->mode & PWM_OUTPUT_MASK) {
  case PWM_OUTPUT_ACTIVE_LOW : outinit = GPIOTE_CONFIG_OUTINIT_Low;  break;
  case PWM_OUTPUT_ACTIVE_HIGH: outinit = GPIOTE_CONFIG_OUTINIT_High; break;
  case PWM_OUTPUT_DISABLED   : /* fall-through */
  default                    : goto no_output_config;
  }

  /* Deal with corner case: 0% and 100% */
  if ((width <= 0) || (width >= pwmp->period)) {
      /* Disable GPIOTE/PPI task */
    NRF_GPIOTE->CONFIG[gpiote_channel] = GPIOTE_CONFIG_MODE_Disabled;
    NRF_PPI->CHENCLR = ((1 << ppi_channel[0]) | (1 << ppi_channel[1]));
    /* Set Line */
    palWriteLine(cfg_channel->ioline,
           ((width <= 0) ^
            ((cfg_channel->mode & PWM_OUTPUT_MASK) == PWM_OUTPUT_ACTIVE_HIGH)));

  /* Really doing PWM */
  } else {
    const uint32_t gpio_pin = PAL_PAD(cfg_channel->ioline);
    const uint32_t polarity = GPIOTE_CONFIG_POLARITY_Toggle;

    /* Program tasks (one for duty cycle, one for periode) */
    NRF_PPI->CH[ppi_channel[0]].EEP =
      (uint32_t)&pwmp->timer->EVENTS_COMPARE[channel];
    NRF_PPI->CH[ppi_channel[0]].TEP =
      (uint32_t)&NRF_GPIOTE->TASKS_OUT[gpiote_channel];
    NRF_PPI->CH[ppi_channel[1]].EEP =
      (uint32_t)&pwmp->timer->EVENTS_COMPARE[pwmp->channels];
    NRF_PPI->CH[ppi_channel[1]].TEP =
      (uint32_t)&NRF_GPIOTE->TASKS_OUT[gpiote_channel];
    NRF_PPI->CHENSET = ((1 << ppi_channel[0]) | (1 << ppi_channel[1]));

    /* Something Old, something New */
    const uint32_t old_width = pwmp->timer->CC[channel];
    const uint32_t new_width = width;

    /* Check GPIOTE state */
    const bool gpiote = (NRF_GPIOTE->CONFIG[gpiote_channel] &
                   GPIOTE_CONFIG_MODE_Msk) != GPIOTE_CONFIG_MODE_Disabled;

    /* GPIOTE is currently running */
    if (gpiote) {
      uint32_t current;
      while (true) {
        pwmp->timer->TASKS_CAPTURE[PWM_GPIOTE_PPI_CC] = 1;
        current = pwmp->timer->CC[PWM_GPIOTE_PPI_CC];

        if (pwm_within_safe_margins(pwmp, current, old_width) &&
            pwm_within_safe_margins(pwmp, current, new_width))
          break;
      }
      if (((old_width <= current) && (current < new_width)) ||
          ((new_width <= current) && (current < old_width))) {
        NRF_GPIOTE->TASKS_OUT[gpiote_channel] = 1;
      }

    /* GPIOTE need to be restarted */
    } else {
      /* Create GPIO Task */
      NRF_GPIOTE->CONFIG[gpiote_channel] =
        (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
        ((gpio_pin << GPIOTE_CONFIG_PSEL_Pos    ) & GPIOTE_CONFIG_PSEL_Msk    )|
        ((polarity << GPIOTE_CONFIG_POLARITY_Pos) & GPIOTE_CONFIG_POLARITY_Msk)|
        ((outinit  << GPIOTE_CONFIG_OUTINIT_Pos ) & GPIOTE_CONFIG_OUTINIT_Msk );

      pwmp->timer->TASKS_CAPTURE[PWM_GPIOTE_PPI_CC] = 1;
      if (pwmp->timer->CC[PWM_GPIOTE_PPI_CC] > width)
        NRF_GPIOTE->TASKS_OUT[gpiote_channel] = 1;
    }
  }

 no_output_config:
#endif

  pwmp->timer->CC[channel] = width;
}
Exemplo n.º 2
0
static void sp100_spi_start(int n) {
    spi_cfg.ssport = PAL_PORT(sp100_ss[n]);
    spi_cfg.sspad  = PAL_PAD(sp100_ss[n]);
    spiStart(sp100_spid, &spi_cfg);
}