TIMER32

Сброс флагов

Описание

Сброс флагов IC_INT_CHx, OC_INT_CHx, UDF_INT и OVF_INT происходит в конце счёта таймера, во время которого была запись в регистр INT_CLEAR. По этой причине возможен повторный вход в обработчик прерываний при низкой частоте счёта таймера.

timer32 flags multiple ic
Рисунок 1. Повторная установка флага IC_INT_CHx, захват сигнала IC_CHx_IN по фронту

Обход

Отключение прерывания по захвату и повторное включение в основном цикле после того как флаг был очищен

#include "mik32_hal.h"
#include "mik32_hal_timer32.h"
#include "mik32_hal_irq.h"

TIMER32_HandleTypeDef htimer32;
TIMER32_CHANNEL_HandleTypeDef htimer32_channel;

void SystemClock_Config(void);
static void Timer32_Init(void);

int main()
{
    __HAL_PCC_EPIC_CLK_ENABLE();

    Timer32_Init();

    HAL_Timer32_Value_Clear(&htimer32);

    HAL_Timer32_Capture_Start_IT(&htimer32, &htimer32_channel);

    HAL_EPIC_MaskLevelSet(HAL_EPIC_TIMER32_2_MASK);

    HAL_IRQ_EnableInterrupts();

    while (1)
    {
        /* Разрешить прерывание после того как флаг был сброшен. */
        if ((htimer32.Instance->INT_FLAGS & TIMER32_INT_IC_M(htimer32_channel.ChannelIndex)) == 0)
        {
            htimer32.Instance->INT_MASK |= TIMER32_INT_IC_M(htimer32_channel.ChannelIndex);
        }
    }
}

static void Timer32_Init(void)
{
    htimer32.Instance = TIMER32_2;
    htimer32.Top = 6;
    htimer32.Clock.Source = TIMER32_SOURCE_PRESCALER;
    htimer32.Clock.Prescaler = 32000000;
    htimer32.CountMode = TIMER32_COUNTMODE_FORWARD;
    HAL_Timer32_Init(&htimer32);

    htimer32_channel.TimerInstance = htimer32.Instance;
    htimer32_channel.ChannelIndex = TIMER32_CHANNEL_0;
    htimer32_channel.PWM_Invert = TIMER32_CHANNEL_NON_INVERTED_PWM;
    htimer32_channel.Mode = TIMER32_CHANNEL_MODE_CAPTURE;
    htimer32_channel.CaptureEdge = TIMER32_CHANNEL_CAPTUREEDGE_RISING;
    htimer32_channel.OCR = 0;
    htimer32_channel.Noise = TIMER32_CHANNEL_FILTER_OFF;
    HAL_Timer32_Channel_Init(&htimer32_channel);
}

__attribute__((noinline, interrupt, section(".trap_text"))) void raw_trap_handler()
{
    uint32_t interrupt_status = HAL_Timer32_InterruptFlags_Get(&htimer32);
    uint32_t interrupt_mask = htimer32.Instance->INT_MASK;

    if ((interrupt_status & TIMER32_INT_IC_M(htimer32_channel.ChannelIndex)) & interrupt_mask)
    {
        // Очистить флаг и отключить прерывание по захвату.
        htimer32.Instance->INT_MASK &= ~TIMER32_INT_IC_M(htimer32_channel.ChannelIndex);
        htimer32.Instance->INT_CLEAR = TIMER32_INT_IC_M(htimer32_channel.ChannelIndex);
    }
}