#include "Arduino.h" #include "pins_arduino.h" #include "mik32_hal_timer16.h" #include "mik32_hal_irq.h" #include "wiring_LL.h" #define PRESCALERS_QTY 7 typedef struct { unsigned int frequency; uint8_t prescaler; uint32_t period_ticks; }FrequencyParams_t; FrequencyParams_t frequencyParams = {0, 0, 0}; // timer handler Timer16_HandleTypeDef htimer16_1; // timer_toggle_count: // > 0 - duration specified // = 0 - stopped // < 0 - infinitely (until noTone() called) volatile long timer_toggle_count; // tone pin params volatile int8_t timer_pin = -1; volatile GPIO_TypeDef* timer_pin_port = 0; volatile HAL_PinsTypeDef timer_pin_mask = (HAL_PinsTypeDef)0; bool timerIsOn = false; static void Timer16_Init(uint8_t prescaler) { htimer16_1.Instance = TIMER16_1; htimer16_1.Clock.Source = TIMER16_SOURCE_INTERNAL_SYSTEM; // prescaler depends on required frequency htimer16_1.Clock.Prescaler = prescaler; htimer16_1.CountMode = TIMER16_COUNTMODE_INTERNAL; htimer16_1.ActiveEdge = TIMER16_ACTIVEEDGE_RISING; htimer16_1.Preload = TIMER16_PRELOAD_AFTERWRITE; htimer16_1.Trigger.Source = 0; // timer triggers by software htimer16_1.Trigger.ActiveEdge = TIMER16_TRIGGER_ACTIVEEDGE_SOFTWARE; htimer16_1.Trigger.TimeOut = TIMER16_TIMEOUT_DISABLE; htimer16_1.Filter.ExternalClock = TIMER16_FILTER_NONE; htimer16_1.Filter.Trigger = TIMER16_FILTER_NONE; htimer16_1.Waveform.Enable = TIMER16_WAVEFORM_GENERATION_DISABLE; htimer16_1.Waveform.Polarity = TIMER16_WAVEFORM_POLARITY_NONINVERTED; htimer16_1.EncoderMode = TIMER16_ENCODER_DISABLE; HAL_Timer16_Init(&htimer16_1); } // calculate prescaler and period in timer ticks for required frequancy static void calcFrequencyParams(FrequencyParams_t* params, unsigned int newFrequency) { // limit the frequency to an acceptable range if (newFrequency < TONE_MIN_FREQUENCY_HZ) newFrequency = TONE_MIN_FREQUENCY_HZ; if (newFrequency > TONE_MAX_FREQUENCY_HZ) newFrequency = TONE_MAX_FREQUENCY_HZ; // go through the prescalers possible values ​to find the appropriate one. // prescaler is set to a value from 0 to 7 uint32_t tempPeriod; for (uint8_t prescaler = 0; prescaler < PRESCALERS_QTY; prescaler++) { // timer frequency is 2 times greater than the required signal frequency tempPeriod = F_CPU / ((1 << prescaler) * 2 * newFrequency); if (tempPeriod <= UINT16_MAX) { // if period is suitable save the current prescaler and period params->frequency = newFrequency; params->prescaler = prescaler; params->period_ticks = tempPeriod; break; } } } // start tone with frequency (in hertz) and duration (in milliseconds) void tone(uint8_t pin, unsigned int frequency, unsigned long duration) { if (!timerIsOn) // if tone is not generated at the moment { // calculate the parameters necessary to ensure a given frequency if the frequency has changed if (frequencyParams.frequency != frequency) calcFrequencyParams(&frequencyParams, frequency); // Calculate the toggle count if (duration > 0) timer_toggle_count = (duration * (F_CPU/(frequencyParams.period_ticks*(1< 0) timer_toggle_count--; } else { // turn off if the specified duration has passed GPIO_CLEAR_PIN((GPIO_TypeDef *)timer_pin_port, timer_pin_mask); TIM16_DISABLE(htimer16_1); EPIC_LEVEL_CLEAR_BY_MASK(HAL_EPIC_TIMER16_1_MASK); timerIsOn = false; } } // reset timer interrupt flags TIM16_CLEAR_INT_MASK(htimer16_1, 0xFFFFFFFF); }