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.

151 lines
3.8 KiB

#pragma once
#include "Arduino.h"
#include "ITimerChannel.h"
namespace TeensyTimerTool
{
class PIT_t;
class PITChannel : public ITimerChannel
{
public:
inline PITChannel(unsigned nr);
inline virtual ~PITChannel();
inline errorCode begin(callback_t cb, float tcnt, bool periodic) override;
//inline errorCode begin(callback_t cb, uint32_t tcnt, bool periodic) override;
inline errorCode start() override;
inline errorCode stop() override;
//inline errorCode trigger(uint32_t) override;
inline errorCode trigger(float) override;
inline errorCode setNextPeriod(float us) override;
inline errorCode setPeriod(float us) override;
inline float getMaxPeriod() const override;
bool isPeriodic;
protected:
//IMXRT_GPT_t* regs;
//uint32_t reload;
inline void isr();
PITChannel() = delete;
PITChannel(const PITChannel &) = delete;
const unsigned chNr;
callback_t callback = nullptr;
static uint32_t clockFactor;
friend PIT_t;
};
// IMPLEMENTATION ==============================================
PITChannel::PITChannel(unsigned nr)
: ITimerChannel(nullptr), chNr(nr)
{
callback = nullptr;
clockFactor = (CCM_CSCMR1 & CCM_CSCMR1_PERCLK_CLK_SEL) ? 24 : (F_BUS_ACTUAL / 1000000);
}
errorCode PITChannel::begin(callback_t cb, float micros, bool periodic)
{
isPeriodic = periodic;
callback = cb;
if (isPeriodic)
{
IMXRT_PIT_CHANNELS[chNr].TCTRL = 0;
IMXRT_PIT_CHANNELS[chNr].TFLG = 1;
setNextPeriod(micros);
// float tmp = micros * clockFactor;
// if (tmp > 0xFFFF'FFFF)
// {
// postError(errorCode::periodOverflow);
// IMXRT_PIT_CHANNELS[chNr].LDVAL = 0xFFFF'FFFE;
// } else
// {
// IMXRT_PIT_CHANNELS[chNr].LDVAL = (uint32_t)tmp - 1;
// }
}
return errorCode::OK;
}
errorCode PITChannel::start()
{
IMXRT_PIT_CHANNELS[chNr].TCTRL = PIT_TCTRL_TEN | PIT_TCTRL_TIE;
return errorCode::OK;
}
errorCode PITChannel::stop()
{
IMXRT_PIT_CHANNELS[chNr].TCTRL = 0;
return errorCode::OK;
}
errorCode PITChannel::setNextPeriod(float us)
{
float cts = us * clockFactor;
if (cts > 0xFFFF'FFFF)
{
postError(errorCode::periodOverflow);
IMXRT_PIT_CHANNELS[chNr].LDVAL = 0xFFFF'FFFE;
} else
{
IMXRT_PIT_CHANNELS[chNr].LDVAL = (uint32_t)cts - 1;
}
return errorCode::OK;
}
errorCode PITChannel::setPeriod(float us)
{
stop(); // need to stop/start timer to change current period (see ch 53.9.5.4)
setNextPeriod(us);
start();
return errorCode::OK;
}
void PITChannel::isr()
{
if (callback != nullptr)
{
callback();
if (!isPeriodic) IMXRT_PIT_CHANNELS[chNr].TCTRL = 0; // switch off timer
}
}
PITChannel::~PITChannel()
{
callback = nullptr;
}
errorCode PITChannel::trigger(float delay) //should be optimized somehow
{
IMXRT_PIT_CHANNELS[chNr].TCTRL = 0;
IMXRT_PIT_CHANNELS[chNr].TFLG = 1;
float tmp = delay * clockFactor;
if (tmp > 0xFFFF'FFFF)
{
postError(errorCode::periodOverflow);
IMXRT_PIT_CHANNELS[chNr].LDVAL = 0xFFFF'FFFE;
} else
IMXRT_PIT_CHANNELS[chNr].LDVAL = (uint32_t)tmp - 1;
start();
return errorCode::OK;
}
float PITChannel::getMaxPeriod() const
{
return (float)0xFFFF'FFFE / clockFactor / 1'000'000;
}
} // namespace TeensyTimerTool