TeensyStepFTM.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
  2. #include "TeensyStepFTM.h"
  3. #include "config.h"
  4. namespace TeensyStepFTM
  5. {
  6. namespace // private
  7. {
  8. bool isConfigured = false;
  9. IDelayHandler *callbacks[maxChannel];
  10. }
  11. void begin()
  12. {
  13. if (!isConfigured)
  14. {
  15. if (USE_TIMER == TIMER_TPM1)
  16. { // enable clocks for tpm timers (ftm clocks are enabled by teensyduino)
  17. SIM_SCGC2 |= SIM_SCGC2_TPM1;
  18. SIM_SOPT2 |= SIM_SOPT2_TPMSRC(2);
  19. }
  20. else if (USE_TIMER == TIMER_TPM2)
  21. {
  22. SIM_SCGC2 |= SIM_SCGC2_TPM2;
  23. SIM_SOPT2 |= SIM_SOPT2_TPMSRC(2);
  24. }
  25. // Default Mode for FTM is (nearly) TPM compatibile
  26. timer->SC = FTM_SC_CLKS(0b00); // Disable clock
  27. timer->MOD = 0xFFFF; // Set full counter range
  28. for (unsigned i = 0; i < maxChannel; i++)
  29. { // turn off all channels which were enabled by teensyduino for PWM generation
  30. if (isFTM)
  31. { // compiletime constant, compiler optimizes conditional and not valid branch completely away
  32. timer->CH[i].SC &= ~FTM_CSC_CHF; // FTM requires to clear flag by setting bit to 0
  33. }
  34. else
  35. {
  36. timer->CH[i].SC |= FTM_CSC_CHF; // TPM requires to clear flag by setting bit to 1
  37. }
  38. timer->CH[i].SC &= ~FTM_CSC_CHIE; // Disable channel interupt
  39. timer->CH[i].SC = FTM_CSC_MSA;
  40. //timer->CH[i].SC = 0; // disable channel
  41. }
  42. timer->SC = FTM_SC_CLKS(0b01) | FTM_SC_PS(prescale); // Start clock
  43. NVIC_ENABLE_IRQ(irq); // Enable interrupt request for selected timer
  44. isConfigured = true;
  45. }
  46. }
  47. unsigned addDelayChannel(IDelayHandler *handler)
  48. {
  49. for (unsigned ch = 0; ch < maxChannel; ch++)
  50. {
  51. if (callbacks[ch] == 0)
  52. {
  53. callbacks[ch] = handler; //Just store the callback function, the rest is done in Trigger function
  54. return ch;
  55. }
  56. }
  57. return maxChannel;
  58. }
  59. void removeDelayChannel(unsigned chNr)
  60. {
  61. if (chNr < maxChannel)
  62. {
  63. noInterrupts();
  64. timer->CH[chNr].SC &= ~FTM_CSC_CHIE; // disable channel
  65. callbacks[chNr] = nullptr;
  66. interrupts();
  67. }
  68. }
  69. } // namespace TeensyDelay2
  70. //-------------------------------------------------------------------------------------------
  71. // Interupt service routine of the timer selected in config.h.
  72. // The code doesn't touch the other FTM/TPM ISRs so they can still be used for other purposes
  73. //
  74. // Unfortunately we can not inline the ISR because inlinig will generate a "weak" function?.
  75. // Since the original ISR (dummy_isr) is also defined weak the linker
  76. // is allowed to choose any of them. In this case it desided to use dummy_isr :-(
  77. // Using a "strong" (not inlined) function overrides the week dummy_isr
  78. //--------------------------------------------------------------------------------------------
  79. using namespace TeensyStepFTM;
  80. #if USE_TIMER == TIMER_FTM0
  81. void ftm0_isr(void)
  82. #elif USE_TIMER == TIMER_FTM1
  83. void ftm1_isr(void)
  84. #elif USE_TIMER == TIMER_FTM2
  85. void ftm2_isr(void)
  86. #elif USE_TIMER == TIMER_FTM3
  87. void ftm3_isr(void)
  88. #elif USE_TIMER == TIMER_TPM1
  89. void tpm1_isr(void)
  90. #elif USE_TIMER == TIMER_TPM2
  91. void tpm2_isr(void)
  92. #endif
  93. {
  94. for (unsigned i = 0; i < maxChannel; i++)
  95. {
  96. 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)
  97. {
  98. 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)
  99. callbacks[i]->delayISR(i); // invoke callback function for the channel
  100. }
  101. }
  102. }
  103. #endif