123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
- #include "TeensyStepFTM.h"
- #include "config.h"
- namespace TeensyStepFTM
- {
- namespace // private
- {
- bool isConfigured = false;
- IDelayHandler *callbacks[maxChannel];
- }
- void begin()
- {
- if (!isConfigured)
- {
- if (USE_TIMER == TIMER_TPM1)
- { // enable clocks for tpm timers (ftm clocks are enabled by teensyduino)
- SIM_SCGC2 |= SIM_SCGC2_TPM1;
- SIM_SOPT2 |= SIM_SOPT2_TPMSRC(2);
- }
- else if (USE_TIMER == TIMER_TPM2)
- {
- SIM_SCGC2 |= SIM_SCGC2_TPM2;
- SIM_SOPT2 |= SIM_SOPT2_TPMSRC(2);
- }
- // Default Mode for FTM is (nearly) TPM compatibile
- timer->SC = FTM_SC_CLKS(0b00); // Disable clock
- timer->MOD = 0xFFFF; // Set full counter range
- for (unsigned i = 0; i < maxChannel; i++)
- { // turn off all channels which were enabled by teensyduino for PWM generation
- if (isFTM)
- { // compiletime constant, compiler optimizes conditional and not valid branch completely away
- timer->CH[i].SC &= ~FTM_CSC_CHF; // FTM requires to clear flag by setting bit to 0
- }
- else
- {
- timer->CH[i].SC |= FTM_CSC_CHF; // TPM requires to clear flag by setting bit to 1
- }
- timer->CH[i].SC &= ~FTM_CSC_CHIE; // Disable channel interupt
- timer->CH[i].SC = FTM_CSC_MSA;
- //timer->CH[i].SC = 0; // disable channel
- }
- timer->SC = FTM_SC_CLKS(0b01) | FTM_SC_PS(prescale); // Start clock
- NVIC_ENABLE_IRQ(irq); // Enable interrupt request for selected timer
- isConfigured = true;
- }
- }
- unsigned addDelayChannel(IDelayHandler *handler)
- {
- for (unsigned ch = 0; ch < maxChannel; ch++)
- {
- if (callbacks[ch] == 0)
- {
- callbacks[ch] = handler; //Just store the callback function, the rest is done in Trigger function
- return ch;
- }
- }
- return maxChannel;
- }
- void removeDelayChannel(unsigned chNr)
- {
- if (chNr < maxChannel)
- {
- noInterrupts();
- timer->CH[chNr].SC &= ~FTM_CSC_CHIE; // disable channel
- callbacks[chNr] = nullptr;
- interrupts();
- }
- }
- } // namespace TeensyDelay2
- //-------------------------------------------------------------------------------------------
- // Interupt service routine of the timer selected in config.h.
- // The code doesn't touch the other FTM/TPM ISRs so they can still be used for other purposes
- //
- // Unfortunately we can not inline the ISR because inlinig will generate a "weak" function?.
- // Since the original ISR (dummy_isr) is also defined weak the linker
- // is allowed to choose any of them. In this case it desided to use dummy_isr :-(
- // Using a "strong" (not inlined) function overrides the week dummy_isr
- //--------------------------------------------------------------------------------------------
- using namespace TeensyStepFTM;
- #if USE_TIMER == TIMER_FTM0
- void ftm0_isr(void)
- #elif USE_TIMER == TIMER_FTM1
- void ftm1_isr(void)
- #elif USE_TIMER == TIMER_FTM2
- void ftm2_isr(void)
- #elif USE_TIMER == TIMER_FTM3
- void ftm3_isr(void)
- #elif USE_TIMER == TIMER_TPM1
- void tpm1_isr(void)
- #elif USE_TIMER == TIMER_TPM2
- void tpm2_isr(void)
- #endif
- {
- for (unsigned i = 0; i < maxChannel; i++)
- {
- if ((timer->CH[i].SC & (FTM_CSC_CHIE | FTM_CSC_CHF)) == (FTM_CSC_CHIE | FTM_CSC_CHF)) // only handle if channel is active (CHIE set) and overflowed (CHF set)
- {
- timer->CH[i].SC &= ~FTM_CSC_CHIE; // We want one shot only. (Make sure to reset the CHF flag before re-activating interrupt in trigger function)
- callbacks[i]->delayISR(i); // invoke callback function for the channel
- }
- }
- }
- #endif
|