/*----------------------------------------------------------------------------*/ static enum result channelSetFrequency(void *object, uint32_t frequency) { struct GpTimerPwm * const pwm = object; struct GpTimerPwmUnit * const unit = pwm->unit; LPC_TIMER_Type * const reg = unit->base.reg; const uint32_t clockFrequency = gpTimerGetClock((struct GpTimerBase *)unit); const uint32_t timerFrequency = frequency * unit->resolution; if (!timerFrequency || timerFrequency > clockFrequency) return E_VALUE; /* TODO Add scaling of timer match values */ reg->PR = clockFrequency / timerFrequency - 1; return E_OK; }
/*----------------------------------------------------------------------------*/ static void updateFrequency(struct GpTimer *timer, uint32_t frequency) { LPC_TIMER_Type * const reg = timer->base.reg; if (frequency) { const uint32_t baseClock = gpTimerGetClock((struct GpTimerBase *)timer); const uint32_t divisor = baseClock / frequency - 1; assert(frequency <= baseClock); assert(divisor <= getMaxValue(timer)); reg->PR = divisor; } else reg->PR = 0; timer->frequency = frequency; }
/*----------------------------------------------------------------------------*/ 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); }
/*----------------------------------------------------------------------------*/ static enum result tmrInit(void *object, const void *configBase) { const struct GpTimerConfig * const config = configBase; const struct GpTimerBaseConfig baseConfig = { .channel = config->channel }; struct GpTimer * const timer = object; enum result res; assert(config->event < GPTIMER_EVENT_END); timer->event = config->event ? config->event : GPTIMER_MATCH0; --timer->event; /* Call base class constructor */ if ((res = GpTimerBase->init(object, &baseConfig)) != E_OK) return res; timer->base.handler = interruptHandler; timer->callback = 0; /* Initialize peripheral block */ LPC_TIMER_Type * const reg = timer->base.reg; reg->TCR = TCR_CRES; reg->IR = reg->IR; /* Clear pending interrupts */ reg->CCR = 0; reg->CTCR = 0; reg->MCR = 0; updateFrequency(timer, config->frequency); /* Configure prescaler and default match value */ reg->MR[timer->event] = getMaxValue(timer); /* Enable external match to generate signals to other peripherals */ reg->EMR = EMR_CONTROL(timer->event, CONTROL_TOGGLE); #ifdef CONFIG_GPTIMER_PM if ((res = pmRegister(interface, powerStateHandler)) != E_OK) return res; #endif /* Timer is disabled by default */ reg->TCR = 0; irqSetPriority(timer->base.irq, config->priority); irqEnable(timer->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ static void tmrDeinit(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; irqDisable(timer->base.irq); reg->TCR = 0; #ifdef CONFIG_GPTIMER_PM pmUnregister(interface); #endif GpTimerBase->deinit(timer); } /*----------------------------------------------------------------------------*/ static void tmrCallback(void *object, void (*callback)(void *), void *argument) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; timer->callbackArgument = argument; timer->callback = callback; if (callback) { reg->IR = reg->IR; reg->MCR |= MCR_INTERRUPT(timer->event); } else reg->MCR &= ~MCR_INTERRUPT(timer->event); } /*----------------------------------------------------------------------------*/ static void tmrSetEnabled(void *object, bool state) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; /* Stop the timer */ reg->TCR = 0; /* Clear pending interrupt flags and direct memory access requests */ reg->IR = IR_MATCH_INTERRUPT(timer->event); if (state) { /* Clear match value to avoid undefined output level */ reg->EMR &= ~EMR_EXTERNAL_MATCH(timer->event); reg->TCR = TCR_CEN; } } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetFrequency(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; const uint32_t baseClock = gpTimerGetClock((const struct GpTimerBase *)timer); return baseClock / (reg->PR + 1); } /*----------------------------------------------------------------------------*/ static void tmrSetFrequency(void *object, uint32_t frequency) { updateFrequency(object, frequency); }
/*----------------------------------------------------------------------------*/ static enum Result tmrInit(void *object, const void *configBase) { const struct GpTimerConfig * const config = configBase; assert(config); const struct GpTimerBaseConfig baseConfig = { .channel = config->channel }; struct GpTimer * const timer = object; enum Result res; assert(config->event < GPTIMER_EVENT_END); /* Call base class constructor */ if ((res = GpTimerBase->init(timer, &baseConfig)) != E_OK) return res; timer->base.handler = interruptHandler; timer->callback = 0; timer->event = (config->event ? config->event : GPTIMER_MATCH0) - 1; /* Initialize peripheral block */ LPC_TIMER_Type * const reg = timer->base.reg; reg->TCR = TCR_CRES; reg->IR = reg->IR; /* Clear pending interrupts */ reg->CCR = 0; reg->CTCR = 0; timer->frequency = config->frequency; gpTimerSetFrequency(&timer->base, timer->frequency); /* Configure prescaler and default match value */ reg->MR[timer->event] = getMaxValue(timer); /* Reset the timer after reaching the match register value */ reg->MCR = MCR_RESET(timer->event); /* Enable external match to generate signals to other peripherals */ reg->EMR = EMR_CONTROL(timer->event, CONTROL_TOGGLE); #ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM if ((res = pmRegister(powerStateHandler, timer)) != E_OK) return res; #endif /* Clear timer reset flag, but do not enable */ reg->TCR = 0; irqSetPriority(timer->base.irq, config->priority); irqEnable(timer->base.irq); return E_OK; } /*----------------------------------------------------------------------------*/ #ifndef CONFIG_PLATFORM_NXP_GPTIMER_NO_DEINIT static void tmrDeinit(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; irqDisable(timer->base.irq); reg->TCR = 0; #ifdef CONFIG_PLATFORM_NXP_GPTIMER_PM pmUnregister(timer); #endif GpTimerBase->deinit(timer); } #endif /*----------------------------------------------------------------------------*/ static void tmrEnable(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; /* Clear pending interrupt flags and direct memory access requests */ reg->IR = IR_MATCH_INTERRUPT(timer->event); /* Clear match value to avoid undefined output level */ reg->EMR &= ~EMR_EXTERNAL_MATCH(timer->event); /* Start the timer */ reg->TCR = TCR_CEN; } /*----------------------------------------------------------------------------*/ static void tmrDisable(void *object) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; reg->TCR = 0; } /*----------------------------------------------------------------------------*/ static void tmrSetCallback(void *object, void (*callback)(void *), void *argument) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; timer->callbackArgument = argument; timer->callback = callback; if (callback) { reg->IR = reg->IR; reg->MCR |= MCR_INTERRUPT(timer->event); } else reg->MCR &= ~MCR_INTERRUPT(timer->event); } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetFrequency(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; const uint32_t baseClock = gpTimerGetClock(&timer->base); return baseClock / (reg->PR + 1); } /*----------------------------------------------------------------------------*/ static void tmrSetFrequency(void *object, uint32_t frequency) { struct GpTimer * const timer = object; timer->frequency = frequency; gpTimerSetFrequency(&timer->base, timer->frequency); } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetOverflow(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; return (reg->MR[timer->event] + 1) & getMaxValue(timer); } /*----------------------------------------------------------------------------*/ static void tmrSetOverflow(void *object, uint32_t overflow) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; assert(overflow <= getMaxValue(timer)); reg->MR[timer->event] = overflow - 1; } /*----------------------------------------------------------------------------*/ static uint32_t tmrGetValue(const void *object) { const struct GpTimer * const timer = object; const LPC_TIMER_Type * const reg = timer->base.reg; return reg->TC; } /*----------------------------------------------------------------------------*/ static void tmrSetValue(void *object, uint32_t value) { struct GpTimer * const timer = object; LPC_TIMER_Type * const reg = timer->base.reg; assert(value <= reg->MR[timer->event]); reg->PC = 0; reg->TC = value; }