You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.8 KiB

#pragma once
#include "Arduino.h"
#include "FTM_ChannelInfo.h"
#include "FTM_Info.h"
#include "ITimerChannel.h"
namespace TeensyTimerTool
{
class FTM_Channel : public ITimerChannel
{
public:
inline FTM_Channel(FTM_r_t *regs, FTM_ChannelInfo *ci);
inline virtual ~FTM_Channel();
inline float getMaxPeriod() const override;
inline errorCode begin(callback_t cb, float period, bool periodic) { return doBegin(cb, period, periodic); } ///hacky improve in later version
inline errorCode begin(callback_t cb, uint32_t period, bool periodic) { return doBegin(cb, period, periodic); };
inline errorCode trigger(float tcnt) override FASTRUN;
inline errorCode triggerDirect(uint32_t reload) override FASTRUN;
inline errorCode getTriggerReload(float delay, uint32_t *reload) override;
inline errorCode start() override;
inline errorCode stop() override;
inline uint16_t ticksFromMicros(float micros);
// inline void setPeriod(uint32_t) {}
protected:
FTM_ChannelInfo *ci;
FTM_r_t *regs;
callback_t *pCallback = nullptr;
template <typename period_t>
inline errorCode doBegin(callback_t cb, period_t period, bool periodic);
};
// IMPLEMENTATION ==============================================
FTM_Channel::FTM_Channel(FTM_r_t *regs, FTM_ChannelInfo *channelInfo)
: ITimerChannel(nullptr)
{
this->regs = regs;
this->ci = channelInfo;
}
template <typename period_t>
errorCode FTM_Channel::doBegin(callback_t callback, period_t period, bool periodic)
{
ci->isPeriodic = periodic;
ci->reload = ticksFromMicros(period);
ci->callback = callback;
return errorCode::OK;
}
errorCode FTM_Channel::start()
{
ci->chRegs->CV = regs->CNT + ci->reload; // compare value (current counter + pReload)
ci->chRegs->SC &= ~FTM_CSC_CHF; // reset timer flag
ci->chRegs->SC = FTM_CSC_MSA | FTM_CSC_CHIE; // enable interrupts
return errorCode::OK;
}
errorCode FTM_Channel::stop()
{
ci->chRegs->SC &= ~FTM_CSC_CHIE; // enable interrupts
ci->chRegs->SC &= ~FTM_CSC_CHF; // reset timer flag
return errorCode::OK;
}
errorCode FTM_Channel::getTriggerReload(float delay, uint32_t *reload)
{
*reload = ticksFromMicros(delay);
return errorCode::OK;
}
errorCode FTM_Channel::trigger(float delay)
{
return triggerDirect(ticksFromMicros(delay));
}
errorCode FTM_Channel::triggerDirect(uint32_t reload)
{
uint32_t cv = regs->CNT + reload + 1; // calc early to minimize error
ci->chRegs->SC &= ~FTM_CSC_CHF; // Reset timer flag
//
regs->SC &= ~FTM_SC_CLKS_MASK; // need to switch off clock to immediately set new CV
ci->chRegs->CV = cv; // compare value (current counter + pReload)
regs->SC |= FTM_SC_CLKS(0b01); // restart clock
//
ci->chRegs->SC = FTM_CSC_MSA | FTM_CSC_CHIE; // enable interrupts
return errorCode::OK;
}
float FTM_Channel::getMaxPeriod() const
{
return (0xFFFF * 1E-6f) / ci->ticksPerMicrosecond; // max period in seconds
}
uint16_t FTM_Channel::ticksFromMicros(float micros)
{
uint32_t rl = ci->ticksPerMicrosecond * micros;
if (rl > 0xFFFF)
{
postError(errorCode::periodOverflow); // warning only, continues with clipped value
rl = 0xFFFF;
}
return rl;
}
FTM_Channel::~FTM_Channel()
{
}
} // namespace TeensyTimerTool