首页 文章

在STM32F7上,由APB1定时器触发的DMA失败

提问于
浏览
0

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

根据数据表,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);
    }
}

1 回答

  • 1

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

    查看总线矩阵,可以清楚地看到DMA1的外围总线仅连接到APB1 . 它实际上根本不是矩阵的一部分 . 这可能意味着DMA1只能处理来自/到APB1外设的传输 . 由于GPIO是AHB外设,因此无法从DMA1访问它 . 这也适用于其他APB2(例如SPI1)和AHB外设(例如OTGFS) . 通常,从DMA1访问AHB或APB2外设没有意义,因为它们的请求不会路由到DMA1 . 但是,计时器可能需要像GPIO这样的复杂情况 .

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

相关问题