tone04.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. //tone04.c
  2. // use atmega timer4 as main tone timer instead of timer2
  3. // timer2 is used for System timer.
  4. #include "system_timer.h"
  5. #include "Configuration_prusa.h"
  6. #ifdef SYSTEM_TIMER_2
  7. #include "pins.h"
  8. #include "fastio.h"
  9. #include "macros.h"
  10. void timer4_init(void)
  11. {
  12. CRITICAL_SECTION_START;
  13. SET_OUTPUT(BEEPER);
  14. WRITE(BEEPER, LOW);
  15. SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
  16. // Set timer mode 9 (PWM,Phase and Frequency Correct)
  17. // Prescaler is CLK/1024
  18. // Output compare is disabled on all timer pins
  19. // Input capture is disabled
  20. // All interrupts are disabled
  21. TCCR4A = (1 << WGM40);
  22. TCCR4B = (1 << WGM43) | (1 << CS42) | (1 << CS40);
  23. OCR4A = 255;
  24. OCR4B = 255;
  25. OCR4C = 255;
  26. TIMSK4 = 0;
  27. CRITICAL_SECTION_END;
  28. }
  29. #ifdef EXTRUDER_0_AUTO_FAN_PIN
  30. void timer4_set_fan0(uint8_t duty)
  31. {
  32. if (duty == 0 || duty == 255)
  33. {
  34. // We use digital logic if the duty cycle is 0% or 100%
  35. TCCR4A &= ~(1 << COM4C1);
  36. OCR4C = 0;
  37. WRITE(EXTRUDER_0_AUTO_FAN_PIN, duty);
  38. }
  39. else
  40. {
  41. // Use the timer for fan speed. Enable the timer compare output and set the duty cycle.
  42. // This function also handles the impossible scenario of a fan speed change during a Tone.
  43. // Better be safe than sorry.
  44. CRITICAL_SECTION_START;
  45. // Enable the PWM output on the fan pin.
  46. TCCR4A |= (1 << COM4C1);
  47. OCR4C = (((uint32_t)duty) * ((uint32_t)((TIMSK4 & (1 << OCIE4A))?OCR4A:255))) / ((uint32_t)255);
  48. CRITICAL_SECTION_END;
  49. }
  50. }
  51. #endif //EXTRUDER_0_AUTO_FAN_PIN
  52. // Because of the timer mode change, we need two interrupts. We could also try to assume that the frequency is x2
  53. // and use a TOGGLE(), but this seems to work well enough so I left it as it is now.
  54. ISR(TIMER4_COMPA_vect)
  55. {
  56. WRITE(BEEPER, 1);
  57. }
  58. ISR(TIMER4_OVF_vect)
  59. {
  60. WRITE(BEEPER, 0);
  61. }
  62. void tone4(_UNUSED uint8_t _pin, uint16_t frequency)
  63. {
  64. //this ocr and prescalarbits calculation is taken from the Arduino core and simplified for one type of timer only
  65. uint8_t prescalarbits = 0b001;
  66. uint32_t ocr = F_CPU / frequency / 2 - 1;
  67. if (ocr > 0xffff)
  68. {
  69. ocr = F_CPU / frequency / 2 / 64 - 1;
  70. prescalarbits = 0b011;
  71. }
  72. CRITICAL_SECTION_START;
  73. // Set calcualted prescaler
  74. TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
  75. #ifdef EXTRUDER_0_AUTO_FAN_PIN
  76. // Scale the fan PWM duty cycle so that it remains constant, but at the tone frequency
  77. OCR4C = (((uint32_t)OCR4C) * ocr) / (uint32_t)((TIMSK4 & (1 << OCIE4A))?OCR4A:255);
  78. #endif //EXTRUDER_0_AUTO_FAN_PIN
  79. // Set calcualted ocr
  80. OCR4A = ocr;
  81. // Enable Output compare A interrupt and timer overflow interrupt
  82. TIMSK4 |= (1 << OCIE4A) | (1 << TOIE4);
  83. CRITICAL_SECTION_END;
  84. }
  85. void noTone4(_UNUSED uint8_t _pin)
  86. {
  87. CRITICAL_SECTION_START;
  88. // Revert prescaler to CLK/1024
  89. TCCR4B = (TCCR4B & 0b11111000) | (1 << CS42) | (1 << CS40);
  90. #ifdef EXTRUDER_0_AUTO_FAN_PIN
  91. // Scale the fan OCR back to the original value.
  92. OCR4C = (((uint32_t)OCR4C) * (uint32_t)255) / (uint32_t)((TIMSK4 & (1 << OCIE4A))?OCR4A:255);
  93. #endif //EXTRUDER_0_AUTO_FAN_PIN
  94. OCR4A = 255;
  95. // Disable Output compare A interrupt and timer overflow interrupt
  96. TIMSK4 &= ~((1 << OCIE4A) | (1 << TOIE4));
  97. CRITICAL_SECTION_END;
  98. // Turn beeper off if it was on when noTone was called
  99. WRITE(BEEPER, 0);
  100. }
  101. #endif //SYSTEM_TIMER_2