1

我有 STM32F7 Disco 板和 STM32F723IEK MCU。尝试从定时器触发 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);
    }
}
4

1 回答 1

2

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

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

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

于 2017-07-26T15:05:31.077 回答