在DMA工作时,STM32F4 TIM6中断不会发生

时间:2016-12-21 17:42:47

标签: interrupt-handling dma openocd stm32f4

我使用STM32F4Discovery板,从Cube生成代码,SYSCLK为168MHz,APB1定时器时钟为42 MHz,TIM6有预分频器1000,并计数到62.我做了以下实验。

通过

启用TIM6中断
__HAL_TIM_ENABLE_IT(&htim6, TIM_IT_UPDATE);
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);

在正常模式下使用30个元素阵列启动DAC_DMA。

计算发生多少次计时器中断

void TIM6_DAC_IRQHandler(void) {

HAL_TIM_IRQHandler(&htim6);
tim6Counter++;
}

在此函数中设置断点:

void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac) {
    conversionCounter++;
}

我的期望:

1)HAL_DAC_ConvCpltCallbackCh1被调用一次(由于非圆形模式)。这是真的。

2)当它被称为tim6Counter时必须等于30,因为DAC数据缓冲区的长度为30.在实验中,tim6Counter为1.

3)DAC完成后,将断点设置为TIM6处理程序,并设置为main while(1)循环。问题是,它挂在TIM6处理程序中。

问题:

1)即使未启用TIM6中断,DMA也能工作。但是如果启用,为什么它只发生一次,而不是每个DMA请求?

2)为什么它会在计时器处理程序中挂起?

3)TIM6 SR寄存器不会被HAL宏或HAL_TIM_IRQHandler清除。我在openOCD中使用eclipse。这是工具的问题吗?还是因为挂在处理程序中?

1 个答案:

答案 0 :(得分:2)

问题是,在调试暂停期间,计时器仍会计数。通过

将定时器切换到调试模式后
void Main()
{
    var executor = new MyExecutor();
    executor.Execute(() => Console.WriteLine("Hello"));
    executor.Execute(() => Thread.Sleep(100));
    executor.Execute(() => Console.WriteLine(","));
    executor.Execute(() => { throw new Exception(); });
    executor.Execute(() => Console.WriteLine("World"));
    executor.Execute(() => Thread.Sleep(100));

    executor.WaitCurrent();

    Console.WriteLine($"{nameof(MyExecutor.Total)}:{executor.Total}");
    Console.WriteLine($"{nameof(MyExecutor.Finished)}:{executor.Finished}");
    Console.WriteLine($"{nameof(MyExecutor.Failed)}:{executor.Failed}");
}

public class MyExecutor
{
    private Task _current = Task.FromResult(0);
    private int _failed = 0;
    private int _finished = 0;
    private int _total = 0;
    private object _locker = new object();

    public void WaitCurrent()
    {
        _current.Wait();        
    }

    public int Total
    {
        get { return _total; }
    }

    public int Finished
    {
        get { return _finished; }
    }

    public int Failed
    {
        get { return _failed; }
    }

    public void Execute(Action action)
    {
        lock (_locker) // not sure that lock it is the best way here
        {
            _total++;
            _current = _current.ContinueWith(prev => SafeExecute(action));
        }
    }

    private void SafeExecute(Action action)
    {
        try
        {               
            action();
        }
        catch 
        {
            Interlocked.Increment(ref _failed);
        }
        finally 
        {
            Interlocked.Increment(ref _finished);
        }
    }
}

它运作正常。阅读时,我错过了参考手册的第20.3.4节。