tone04.c 3.4 KB

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