Example #1
0
File: gppwm.c Project: stxent/halm
static void doubleEdgeDeinit(void *object)
{
  struct GpPwmDoubleEdge * const pwm = object;
  LPC_PWM_Type * const reg = pwm->unit->base.reg;

  reg->PCR &= ~PCR_OUTPUT_ENABLED(pwm->channel);
  unitReleaseChannel(pwm->unit, pwm->channel);
  unitReleaseChannel(pwm->unit, pwm->channel - 1);
}
Example #2
0
/*----------------------------------------------------------------------------*/
static enum result unitInit(void *object, const void *configBase)
{
  const struct GpTimerPwmUnitConfig * const config = configBase;
  const struct GpTimerBaseConfig baseConfig = {
      .channel = config->channel
  };
  struct GpTimerPwmUnit * const unit = object;
  enum result res;

  const uint32_t clockFrequency = gpTimerGetClock(object);
  const uint32_t timerFrequency = config->frequency * config->resolution;

  if (!timerFrequency || timerFrequency > clockFrequency)
    return E_VALUE;

  /* Call base class constructor */
  if ((res = GpTimerBase->init(object, &baseConfig)) != E_OK)
    return res;

  unit->matches = 0;
  unit->resolution = config->resolution;

  /* Should be invoked after object initialization completion */
  unit->current = gpTimerAllocateChannel(unit->matches);

  LPC_TIMER_Type * const reg = unit->base.reg;

  reg->TCR = 0;

  reg->IR = reg->IR; /* Clear pending interrupts */
  reg->PC = reg->TC = 0;
  reg->CTCR = 0;
  reg->CCR = 0;
  reg->EMR = 0;
  reg->PWMC = 0; /* Register is available only on specific parts */

  /* Configure timings */
  reg->PR = clockFrequency / timerFrequency - 1;
  reg->MR[unit->current] = unit->resolution - 1;
  reg->MCR = MCR_RESET(unit->current);

  /* Enable timer */
  reg->TCR = TCR_CEN;

  return E_OK;
}
/*----------------------------------------------------------------------------*/
static void unitDeinit(void *object)
{
  struct GpTimerPwmUnit * const unit = object;
  LPC_TIMER_Type * const reg = unit->base.reg;

  reg->TCR &= ~TCR_CEN;
  GpTimerBase->deinit(unit);
}
/*----------------------------------------------------------------------------*/
static enum result channelInit(void *object, const void *configBase)
{
  const struct GpTimerPwmConfig * const config = configBase;
  struct GpTimerPwm * const pwm = object;
  struct GpTimerPwmUnit * const unit = config->parent;
  enum result res;

  /* Initialize output pin */
  pwm->channel = gpTimerConfigMatchPin(unit->base.channel, config->pin);

  /* Allocate channel */
  if ((res = unitAllocateChannel(unit, pwm->channel)) != E_OK)
    return res;

  pwm->unit = unit;

  LPC_TIMER_Type * const reg = pwm->unit->base.reg;

  /* Calculate pointer to match register for fast access */
  pwm->value = reg->MR + pwm->channel;

  /* Set initial duration */
  channelSetDuration(pwm, 0);

  return E_OK;
}
/*----------------------------------------------------------------------------*/
static void channelDeinit(void *object)
{
  struct GpTimerPwm * const pwm = object;
  LPC_TIMER_Type * const reg = pwm->unit->base.reg;

  reg->PWMC &= ~PWMC_ENABLE(pwm->channel);
  unitReleaseChannel(pwm->unit, pwm->channel);
}
/*----------------------------------------------------------------------------*/
static uint32_t channelGetResolution(const void *object)
{
  return ((const struct GpTimerPwm *)object)->unit->resolution;
}
/*----------------------------------------------------------------------------*/
static void channelSetDuration(void *object, uint32_t duration)
{
  struct GpTimerPwm * const pwm = object;
  const uint32_t resolution = pwm->unit->resolution;

  if (duration)
  {
    if (duration > resolution)
      duration = resolution;

    /* The output is inverted */
    duration = resolution - duration;
  }
  else
  {
    /*
     * If match register is set to a value greater or equal to resolution,
     * then the output stays low during all cycle.
     */
    duration = resolution + 1;
  }

  /*
   * If a match register is set to zero, than output pin goes high
   * and will stay in this state continuously.
   */
  *pwm->value = duration;
}
/*----------------------------------------------------------------------------*/
static void channelSetEdges(void *object,
    uint32_t leading __attribute__((unused)), uint32_t trailing)
{
  /* Leading edge time is constant in the single edge mode */
  assert(leading == 0);

  channelSetDuration(object, trailing);
}
Example #3
0
File: gppwm.c Project: stxent/halm
/*----------------------------------------------------------------------------*/
static enum Result unitInit(void *object, const void *configBase)
{
  const struct GpPwmUnitConfig * const config = configBase;
  assert(config);
  assert(config->resolution >= 2);

  const struct GpPwmUnitBaseConfig baseConfig = {
      .channel = config->channel
  };
  struct GpPwmUnit * const unit = object;
  enum Result res;

  /* Call base class constructor */
  if ((res = GpPwmUnitBase->init(unit, &baseConfig)) != E_OK)
    return res;

  LPC_PWM_Type * const reg = unit->base.reg;

  reg->TCR = TCR_CRES;

  reg->IR = reg->IR; /* Clear pending interrupts */
  reg->CTCR = 0;
  reg->CCR = 0;
  reg->PCR = 0;

  /* Configure timings */
  unit->frequency = config->frequency;
  unit->resolution = config->resolution;
  unitSetFrequency(unit, unit->frequency * unit->resolution);

  unit->matches = 0;
  reg->MR0 = unit->resolution;
  reg->MCR = MCR_RESET(0);

#ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM
  if ((res = pmRegister(powerStateHandler, unit)) != E_OK)
    return res;
#endif

  /* Switch to the PWM mode and enable the timer */
  reg->TCR = TCR_CEN | TCR_PWM_ENABLE;

  return E_OK;
}
/*----------------------------------------------------------------------------*/
#ifndef CONFIG_PLATFORM_NXP_GPPWM_NO_DEINIT
static void unitDeinit(void *object)
{
  struct GpPwmUnit * const unit = object;
  LPC_PWM_Type * const reg = unit->base.reg;

  reg->TCR = 0;

#ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM
  pmUnregister(unit);
#endif

  GpPwmUnitBase->deinit(unit);
}
#endif
/*----------------------------------------------------------------------------*/
static enum Result singleEdgeInit(void *object, const void *configBase)
{
  const struct GpPwmConfig * const config = configBase;
  assert(config);

  struct GpPwm * const pwm = object;
  struct GpPwmUnit * const unit = config->parent;

  /* Initialize output pin */
  pwm->channel = configMatchPin(unit->base.channel, config->pin);

  /* Allocate channel */
  if (unitAllocateChannel(unit, pwm->channel))
  {
    LPC_PWM_Type * const reg = unit->base.reg;

    /* Select single edge mode */
    reg->PCR &= ~PCR_DOUBLE_EDGE(pwm->channel);

    pwm->unit = unit;
    pwm->latch = LER_ENABLE(pwm->channel);

    /* Calculate pointer to the match register */
    pwm->value = calcMatchChannel(reg, pwm->channel);

    return E_OK;
  }
  else
    return E_BUSY;
}
/*----------------------------------------------------------------------------*/
#ifndef CONFIG_PLATFORM_NXP_GPPWM_NO_DEINIT
static void singleEdgeDeinit(void *object)
{
  struct GpPwm * const pwm = object;
  LPC_PWM_Type * const reg = pwm->unit->base.reg;

  reg->PCR &= ~PCR_OUTPUT_ENABLED(pwm->channel);
  unitReleaseChannel(pwm->unit, pwm->channel);
}
#endif
/*----------------------------------------------------------------------------*/
static void singleEdgeEnable(void *object)
{
  struct GpPwm * const pwm = object;
  LPC_PWM_Type * const reg = pwm->unit->base.reg;

  reg->PCR |= PCR_OUTPUT_ENABLED(pwm->channel);
}
/*----------------------------------------------------------------------------*/
static void singleEdgeDisable(void *object)
{
  struct GpPwm * const pwm = object;
  LPC_PWM_Type * const reg = pwm->unit->base.reg;

  reg->PCR &= ~PCR_OUTPUT_ENABLED(pwm->channel);
}
/*----------------------------------------------------------------------------*/
static uint32_t singleEdgeGetResolution(const void *object)
{
  return ((const struct GpPwm *)object)->unit->resolution;
}
/*----------------------------------------------------------------------------*/
static void singleEdgeSetDuration(void *object, uint32_t duration)
{
  struct GpPwm * const pwm = object;
  LPC_PWM_Type * const reg = pwm->unit->base.reg;

  /*
   * If match register is set to a value greater than resolution,
   * than output stays high during all cycle.
   */
  *pwm->value = duration;
  reg->LER |= pwm->latch;
}
/*----------------------------------------------------------------------------*/
static void singleEdgeSetEdges(void *object,
    uint32_t leading __attribute__((unused)), uint32_t trailing)
{
  assert(leading == 0); /* Leading edge time must be zero */
  singleEdgeSetDuration(object, trailing);
}