| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 | 
							- //tone04.c
 
- // use atmega timer4 as main tone timer instead of timer2
 
- // timer2 is used for System timer.
 
- #include "system_timer.h"
 
- #include "Configuration_prusa.h"
 
- #ifdef SYSTEM_TIMER_2
 
- #include "pins.h"
 
- #include "fastio.h"
 
- #include "macros.h"
 
- void timer4_init(void)
 
- {
 
- 	CRITICAL_SECTION_START;
 
- 	
 
- 	SET_OUTPUT(BEEPER);
 
- 	WRITE(BEEPER, LOW);
 
- 	
 
- 	SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
 
- 	
 
- 	// Set timer mode 9 (PWM,Phase and Frequency Correct)
 
- 	// Prescaler is CLK/1024
 
- 	// Output compare is disabled on all timer pins
 
- 	// Input capture is disabled
 
- 	// All interrupts are disabled
 
- 	TCCR4A = (1 << WGM40);
 
- 	TCCR4B = (1 << WGM43) | (1 << CS42) | (1 << CS40);
 
- 	OCR4A = 255;
 
- 	OCR4B = 255;
 
- 	OCR4C = 255;
 
- 	TIMSK4 = 0;
 
- 	
 
- 	CRITICAL_SECTION_END;
 
- }
 
- #ifdef EXTRUDER_0_AUTO_FAN_PIN
 
- void timer4_set_fan0(uint8_t duty)
 
- {
 
- 	if (duty == 0 || duty == 255)
 
- 	{
 
- 		// We use digital logic if the duty cycle is 0% or 100%
 
- 		TCCR4A &= ~(1 << COM4C1);
 
- 		OCR4C = 0;
 
- 		WRITE(EXTRUDER_0_AUTO_FAN_PIN, duty);
 
- 	}
 
- 	else
 
- 	{
 
- 		// Use the timer for fan speed. Enable the timer compare output and set the duty cycle.
 
- 		// This function also handles the impossible scenario of a fan speed change during a Tone.
 
- 		// Better be safe than sorry.
 
- 		CRITICAL_SECTION_START;
 
- 		// Enable the PWM output on the fan pin.
 
- 		TCCR4A |= (1 << COM4C1);
 
- 		OCR4C = (((uint32_t)duty) * ((uint32_t)((TIMSK4 & (1 << OCIE4A))?OCR4A:255))) / ((uint32_t)255);
 
- 		CRITICAL_SECTION_END;
 
- 	}
 
- }
 
- #endif //EXTRUDER_0_AUTO_FAN_PIN
 
- // Because of the timer mode change, we need two interrupts. We could also try to assume that the frequency is x2
 
- // and use a TOGGLE(), but this seems to work well enough so I left it as it is now.
 
- ISR(TIMER4_COMPA_vect)
 
- {
 
- 	WRITE(BEEPER, 1);
 
- }
 
- ISR(TIMER4_OVF_vect)
 
- {
 
- 	WRITE(BEEPER, 0);
 
- }
 
- void tone4(_UNUSED uint8_t _pin, uint16_t frequency)
 
- {
 
- 	//this ocr and prescalarbits calculation is taken from the Arduino core and simplified for one type of timer only
 
- 	uint8_t prescalarbits = 0b001;
 
- 	uint32_t ocr = F_CPU / frequency / 2 - 1;
 
- 	
 
- 	if (ocr > 0xffff)
 
- 	{
 
- 		ocr = F_CPU / frequency / 2 / 64 - 1;
 
- 		prescalarbits = 0b011;
 
- 	}
 
- 	
 
- 	CRITICAL_SECTION_START;
 
- 	// Set calcualted prescaler
 
- 	TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
 
- #ifdef EXTRUDER_0_AUTO_FAN_PIN
 
- 	// Scale the fan PWM duty cycle so that it remains constant, but at the tone frequency
 
- 	OCR4C = (((uint32_t)OCR4C) * ocr) / (uint32_t)((TIMSK4 & (1 << OCIE4A))?OCR4A:255);
 
- #endif //EXTRUDER_0_AUTO_FAN_PIN
 
- 	// Set calcualted ocr
 
- 	OCR4A = ocr;
 
- 	// Enable Output compare A interrupt and timer overflow interrupt
 
- 	TIMSK4 |= (1 << OCIE4A) | (1 << TOIE4);
 
- 	CRITICAL_SECTION_END;
 
- }
 
- void noTone4(_UNUSED uint8_t _pin)
 
- {
 
- 	CRITICAL_SECTION_START;
 
- 	// Revert prescaler to CLK/1024
 
- 	TCCR4B = (TCCR4B & 0b11111000) | (1 << CS42) | (1 << CS40);
 
- #ifdef EXTRUDER_0_AUTO_FAN_PIN
 
- 	// Scale the fan OCR back to the original value.
 
- 	OCR4C = (((uint32_t)OCR4C) * (uint32_t)255) / (uint32_t)((TIMSK4 & (1 << OCIE4A))?OCR4A:255);
 
- #endif //EXTRUDER_0_AUTO_FAN_PIN
 
- 	OCR4A = 255;
 
- 	// Disable Output compare A interrupt and timer overflow interrupt
 
- 	TIMSK4 &= ~((1 << OCIE4A) | (1 << TOIE4));
 
- 	CRITICAL_SECTION_END;
 
- 	// Turn beeper off if it was on when noTone was called
 
- 	WRITE(BEEPER, 0);
 
- }
 
- #endif //SYSTEM_TIMER_2
 
 
  |