【问题标题】:On STM32F7 DMA triggered by APB1 timers fails在 APB1 定时器触发的 STM32F7 DMA 上失败
【发布时间】:2018-01-01 03:32:33
【问题描述】:

我有带有 STM32F723IEK MCU 的 STM32F7 Disco 板。尝试从定时器触发 DMA 请求会导致 DMA 错误,但仅适用于连接到 DMA1 的 APB1 组(TIM2 到 TIM7 等)的定时器。对连接到 DMA2 的 TIM1 和 TIM8 执行相同操作可以正常工作。该错误表现为在相应的 DMA LISR 或 HISR 寄存器中设置了 TEIFx 标志,并且 DMA 在第一次事务处理后立即被禁用。 NDTR 寄存器减一。

根据数据表,TEIF 错误可能由“总线错误”触发。我将其理解为例如试图访问无法从 DMA 总线访问的外围设备。然而,同样的设置在使用 DMA2 和 TIM1/TIM8 时效果很好,无需更改 DMA 地址。所以问题似乎与 DMA 请求有关,而不是数据事务本身。鉴于为 DMA1 定义了很多定时器通道,这肯定可以工作。

我尝试改变 DMA 设置,但这并没有什么不同。测试程序的相关部分如下。完整版https://github.com/ak-hard/stm32-dma-tim/blob/master/main.c 只是稍大一些,除了CMSIS 和STM32 设备头之外没有依赖。

我想知道是否有人可以评论或重现此问题。

const struct
{
    TIM_TypeDef *tim;
    DMA_TypeDef *dma;
    DMA_Stream_TypeDef *stream;
    unsigned channel;
} CFG = {
// uncomment the needed combination below, only TIM1 and TIM8 work
//    TIM1, DMA2, DMA2_Stream5, 6
    TIM8, DMA2, DMA2_Stream1, 7
//    TIM2, DMA1, DMA1_Stream1, 3
//    TIM2, DMA1, DMA1_Stream7, 3
//    TIM3, DMA1, DMA1_Stream2, 5
//    TIM4, DMA1, DMA1_Stream6, 2
//    TIM5, DMA1, DMA1_Stream0, 6
//    TIM5, DMA1, DMA1_Stream6, 6
//    TIM6, DMA1, DMA1_Stream1, 7
//    TIM7, DMA1, DMA1_Stream2, 1
//    TIM7, DMA1, DMA1_Stream4, 1
};

enum
{
    DMA_SxCR_DIR_P2M = 0,
    DMA_SxCR_PSIZE_WORD = DMA_SxCR_PSIZE_1,
    DMA_SxCR_MSIZE_WORD = DMA_SxCR_MSIZE_1,
};

#define DMA_SxCR_CHSEL_NUM(ch) ((ch) << DMA_SxCR_CHSEL_Pos)

uint32_t buf;

void start(void)
{
    SysTick->LOAD = 0xffffffu;
    SysTick->VAL = 0;
    SysTick->CTRL = 5;

    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM8EN;
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM4EN | RCC_APB1ENR_TIM5EN
            | RCC_APB1ENR_TIM6EN | RCC_APB1ENR_TIM7EN;
    RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN | RCC_AHB1ENR_DMA2EN;

    LED_PORT->MODER   |= 1 << (2 * LED_PIN);
    LED_PORT->OSPEEDR |= 3 << (2 * LED_PIN); // fastest speed

    CFG.tim->CR1 |= TIM_CR1_ARPE;
    CFG.tim->ARR = 16;
    CFG.tim->PSC = 1000;
    CFG.tim->EGR = TIM_EGR_UG; // Generate Update Event to copy ARR to its shadow
    CFG.tim->DIER |= TIM_DIER_UDE;
    CFG.stream->CR |= DMA_SxCR_CHSEL_NUM(CFG.channel) | DMA_SxCR_DIR_P2M | DMA_SxCR_PSIZE_WORD | DMA_SxCR_MSIZE_WORD;
    CFG.stream->NDTR = 16;
    CFG.stream->PAR = (uint32_t) &GPIOA->IDR;
    CFG.stream->M0AR = (uint32_t) &buf;
    CFG.stream->CR |= DMA_SxCR_EN;
    CFG.tim->CR1 |= TIM_CR1_CEN;

    // wait until DMA state changes
    while (CFG.dma->LISR == 0 && CFG.dma->HISR == 0)
        delay_ms(1);

    // check for any TEIFx bits
    int error = (CFG.dma->LISR | CFG.dma->HISR) & 0x02080208;

    while (1)
    {
        LED_PORT->ODR ^= 1 << LED_PIN;
        delay_ms(error ? 100 : 500);
    }
}

【问题讨论】:

  • 已删除 - 不喜欢这种讨论。

标签: timer stm32 dma stm32f7


【解决方案1】:

这里曾经有一个答案,但由于某种原因它被删除了。不过感谢它的作者。

查看总线矩阵,很明显 DMA1 的外围总线连接到 APB1。它实际上根本不是矩阵的一部分。这可能意味着 DMA1 只能处理与 APB1 外设之间的传输。由于 GPIO 是 AHB 外设,因此无法从 DMA1 访问它。这也应该适用于其他 APB2(例如 SPI1)和 AHB 外设(例如 OTGFS)。通常,从 DMA1 访问 AHB 或 APB2 外设是没有意义的,因为它们的请求不会路由到 DMA1。但是,对于复杂的情况,例如定时器的 GPIO,可能需要它。

我个人认为这一点可以在文档中更加明显。

【讨论】:

  • 完全同意文档还有很多不足之处。我在 STM32H743 上遇到了同样的问题,但即使在进行内存到内存的传输时我也遇到了这种问题,并且还没有弄清楚如何解决它。 (最终,当来自HRTIM 的比较事件触发时,我想将 16 位写入GPIOE-&gt;ODR - 计时器工作并且事件触发但发生传输错误,并且我在从软件触发时看到相同的行为。)“图 1。系统架构..." 看起来 DMA1 基本上可以处理所有事情,所以我仍在摸不着头脑,只是盲目地尝试不同的东西:/
  • 啊哈!事实证明,您必须小心内存所在的位置。当我在我的代码中定义一个全局数组时,它被放置在DTCM (0x20000000 - 0x2001FFFF) 中。这篇文章帮我解决了问题:community.st.com/s/article/…
猜你喜欢
  • 2018-03-26
  • 2015-07-06
  • 1970-01-01
  • 2019-08-11
  • 2012-09-18
  • 2021-09-15
  • 2022-08-18
  • 1970-01-01
  • 2013-12-20
相关资源
最近更新 更多