tone04.c 3.2 KB

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