tone04.c 3.2 KB

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