Teensy 4.1 core updated for C++20
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.

187 satır
6.1KB

  1. /* Copyright (c) 2013 Daniel Gilbert, loglow@gmail.com
  2. Permission is hereby granted, free of charge, to any person obtaining a copy of
  3. this software and associated documentation files (the "Software"), to deal in the
  4. Software without restriction, including without limitation the rights to use, copy,
  5. modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
  6. and to permit persons to whom the Software is furnished to do so, subject to the
  7. following conditions:
  8. The above copyright notice and this permission notice shall be included in all
  9. copies or substantial portions of the Software.
  10. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  11. INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  12. PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  13. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  14. OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  15. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  16. #include "IntervalTimer.h"
  17. // ------------------------------------------------------------
  18. // static class variables need to be reiterated here before use
  19. // ------------------------------------------------------------
  20. bool IntervalTimer::PIT_enabled;
  21. bool IntervalTimer::PIT_used[];
  22. IntervalTimer::ISR IntervalTimer::PIT_ISR[];
  23. // ------------------------------------------------------------
  24. // these are the ISRs (Interrupt Service Routines) that get
  25. // called by each PIT timer when it fires. they're defined here
  26. // so that they can auto-clear themselves and so the user can
  27. // specify a custom ISR and reassign it as needed
  28. // ------------------------------------------------------------
  29. void pit0_isr() { PIT_TFLG0 = 1; IntervalTimer::PIT_ISR[0](); }
  30. void pit1_isr() { PIT_TFLG1 = 1; IntervalTimer::PIT_ISR[1](); }
  31. void pit2_isr() { PIT_TFLG2 = 1; IntervalTimer::PIT_ISR[2](); }
  32. void pit3_isr() { PIT_TFLG3 = 1; IntervalTimer::PIT_ISR[3](); }
  33. // ------------------------------------------------------------
  34. // this function inits and starts the timer, using the specified
  35. // function as a callback and the period provided. must be passed
  36. // the name of a function taking no arguments and returning void.
  37. // make sure this function can complete within the time allowed.
  38. // attempts to allocate a timer using available resources,
  39. // returning true on success or false in case of failure.
  40. // period is specified as number of bus cycles
  41. // ------------------------------------------------------------
  42. bool IntervalTimer::beginCycles(ISR newISR, uint32_t newValue) {
  43. // if this interval timer is already running, stop it
  44. if (status == TIMER_PIT) {
  45. stop_PIT();
  46. status = TIMER_OFF;
  47. }
  48. // store callback pointer
  49. myISR = newISR;
  50. // attempt to allocate this timer
  51. if (allocate_PIT(newValue)) status = TIMER_PIT;
  52. else status = TIMER_OFF;
  53. // check for success and return
  54. if (status != TIMER_OFF) return true;
  55. return false;
  56. }
  57. // ------------------------------------------------------------
  58. // stop the timer if it's currently running, using its status
  59. // to determine what hardware resources the timer may be using
  60. // ------------------------------------------------------------
  61. void IntervalTimer::end() {
  62. if (status == TIMER_PIT) stop_PIT();
  63. status = TIMER_OFF;
  64. }
  65. // ------------------------------------------------------------
  66. // enables the PIT clock bit, the master PIT reg, and sets flag
  67. // ------------------------------------------------------------
  68. void IntervalTimer::enable_PIT() {
  69. SIM_SCGC6 |= SIM_SCGC6_PIT;
  70. PIT_MCR = 0;
  71. PIT_enabled = true;
  72. }
  73. // ------------------------------------------------------------
  74. // disables the master PIT reg, the PIT clock bit, and unsets flag
  75. // ------------------------------------------------------------
  76. void IntervalTimer::disable_PIT() {
  77. PIT_MCR = 1;
  78. SIM_SCGC6 &= ~SIM_SCGC6_PIT;
  79. PIT_enabled = false;
  80. }
  81. // ------------------------------------------------------------
  82. // enables the PIT clock if not already enabled, then checks to
  83. // see if any PITs are available for use. if one is available,
  84. // it's initialized and started with the specified value, and
  85. // the function returns true, otherwise it returns false
  86. // ------------------------------------------------------------
  87. bool IntervalTimer::allocate_PIT(uint32_t newValue) {
  88. // enable clock to the PIT module if necessary
  89. if (!PIT_enabled) enable_PIT();
  90. // check for an available PIT, and if so, start it
  91. for (uint8_t id = 0; id < NUM_PIT; id++) {
  92. if (!PIT_used[id]) {
  93. PIT_id = id;
  94. start_PIT(newValue);
  95. PIT_used[id] = true;
  96. return true;
  97. }
  98. }
  99. // no PIT available
  100. return false;
  101. }
  102. // ------------------------------------------------------------
  103. // configuters a PIT's registers, function pointer, and enables
  104. // interrupts, effectively starting the timer upon completion
  105. // ------------------------------------------------------------
  106. void IntervalTimer::start_PIT(uint32_t newValue) {
  107. // point to the correct registers
  108. PIT_LDVAL = &PIT_LDVAL0 + PIT_id * 4;
  109. PIT_TCTRL = &PIT_TCTRL0 + PIT_id * 4;
  110. IRQ_PIT_CH = IRQ_PIT_CH0 + PIT_id;
  111. // point to the correct PIT ISR
  112. PIT_ISR[PIT_id] = myISR;
  113. // write value to register and enable interrupt
  114. *PIT_TCTRL = 0;
  115. *PIT_LDVAL = newValue;
  116. *PIT_TCTRL = 3;
  117. NVIC_SET_PRIORITY(IRQ_PIT_CH, nvic_priority);
  118. NVIC_ENABLE_IRQ(IRQ_PIT_CH);
  119. }
  120. // ------------------------------------------------------------
  121. // stops an active PIT by disabling its interrupt, writing to
  122. // its control register, and freeing up its state for future use.
  123. // also, if no PITs remain in use, disables the core PIT clock
  124. // ------------------------------------------------------------
  125. void IntervalTimer::stop_PIT() {
  126. // disable interrupt and PIT
  127. NVIC_DISABLE_IRQ(IRQ_PIT_CH);
  128. *PIT_TCTRL = 0;
  129. // free PIT for future use
  130. PIT_used[PIT_id] = false;
  131. // check if we're still using any PIT
  132. for (uint8_t id = 0; id < NUM_PIT; id++) {
  133. if (PIT_used[id]) return;
  134. }
  135. // none used, disable PIT clock
  136. disable_PIT();
  137. }