打印
[STM32F2]

DMA不再起作用

[复制链接]
1609|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
supernan|  楼主 | 2021-8-14 19:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM32F205使用定时器8的TIM_DMA_Update 事件循环触发DMA2搬运,从 test_data 每次搬运五个数据到 dest_arr 中。
使用DMA2_Stream1_Channel7 ,在主程序中启动这两个函数,配置DMA和TIM8,然后观察test_data的值变为了0x06030444,
延时一段时间后清零 test_data,定时器可以正常进入中断,但DMA不再起作用, test_data始终是零

使用特权

评论回复
沙发
jlyuan| | 2021-8-14 19:17 | 只看该作者

楼主程序可以公开吗?贴程序看下吧,这么说看不出什么原因

使用特权

评论回复
板凳
supernan|  楼主 | 2021-8-14 19:19 | 只看该作者
unsigned int dest_arr;
unsigned int test_data[5] = {0x06030440,0x06030441,0x06030442,0x06030443,0x06030444};
/*DMA配置函数*/
void DMA_Auto_Config(void)
{   
        DMA_InitTypeDef DMA_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);         

        DMA_DeInit(DMA2_Stream1);
        while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}                                // 等待DMA可配置

        DMA_InitStructure.DMA_Channel = DMA_Channel_7;                                        // 通道选择
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(test_data);                 // DMA外设地址(SOURCE ADDR)
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(&dest_arr);                 // DMA 存储器0地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;                           // 内存到内存

        DMA_InitStructure.DMA_BufferSize = 5;                                                          // 数据传输量
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;                 // 外设增量模式
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;                      // 存储器非增量模式
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;   // 外设数据长度:32位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;         // 存储器数据长度:32位
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                      // 不使用循环模式
        DMA_InitStructure.DMA_Priority  = DMA_Priority_High;                                    // 优先级
        DMA_InitStructure.DMA_FIFOMode  = DMA_FIFOMode_Disable;         

        DMA_InitStructure.DMA_FIFOThreshold  = DMA_FIFOThreshold_Full;
        DMA_InitStructure.DMA_MemoryBurst    = DMA_MemoryBurst_Single;                        // 存储器突发单次传输
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;                     // 外设突发单次传输
        DMA_Init(DMA2_Stream1, &DMA_InitStructure);
        
        DMA_Cmd(DMA2_Stream1, ENABLE);

}
/*timer8配置函数*/
void timer8_init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;        
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
        
        TIM_TimeBaseStructure.TIM_Period = 100-1;                                                                                       
        TIM_TimeBaseStructure.TIM_Prescaler = 60000-1;                                                                                
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);

        NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_TIM13_IRQn;                                                  
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
        NVIC_Init(&NVIC_InitStructure);  
        
        TIM_ClearFlag(TIM8,TIM_FLAG_Update);
        TIM_ITConfig(TIM8, TIM_IT_Update, ENABLE);                                                                                                 // 开中断
        TIM8->CR2 |= TIM_CR2_CCDS;

        TIM_DMACmd(TIM8,TIM_DMA_Update,ENABLE);
        TIM_Cmd(TIM8,ENABLE);
}
/*主函数*/
int main(void)
{        
        uart5_init();
        timer8_init();                                                               
        DMA_Auto_Config();                                       
        delay_ms(100);
        test_arr = 0;               
        
        while(1)
        {               
                delay_ms(100);
                printf("dest_arr = 0x%x\n",dest_arr);
        }
        return 0;
}
/*TIM8中断函数*/
void TIM8_UP_TIM13_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM8,TIM_IT_Update)==SET)                                                                  // 溢出中断
        {
                TIM_Cmd(TIM8, DISABLE);
                TIM_ClearITPendingBit(TIM8,TIM_IT_Update);                                                                // 清除中断标志位
                printf("TIMER_8 IRQ IRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQ!\n");
                delay_ms(100);
                TIM_Cmd(TIM8, ENABLE);
        }
}

打印输出结果:(循环输出如下,dest_arr始终为0)

                dest_arr = 0x0
                TIMER_8 IRQ IRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQ!
                TIMER_8 IRQ IRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQ!
                TIMER_8 IRQ IRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQ!
                dest_arr= 0x0
                TIMER_8 IRQ IRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQ!
                TIMER_8 IRQ IRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQ!
                TIMER_8 IRQ IRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQ!
                dest_arr= 0x0

使用特权

评论回复
地板
huwr| | 2021-8-14 19:21 | 只看该作者
提醒下,Memory to memory的DMA传输无须外设触发事件,另外它不支持循环模式。

使用特权

评论回复
5
supernan|  楼主 | 2021-8-14 19:23 | 只看该作者
如果想开启第二次传输,你先初始化下再做传输启动。

使用特权

评论回复
6
jlyuan| | 2021-8-14 19:25 | 只看该作者
我一下没找到F2的开发板,用STM32F4测试下,运行没什么问题。

使用特权

评论回复
7
jlyuan| | 2021-8-14 19:27 | 只看该作者

/* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
        
  /* USER CODE BEGIN 2 */
HAL_DMA_Start(&hdma_memtomem_dma2_stream0,(uint32_t)(&SrcAddress[0]),(uint32_t)(&DstAddress[0]), 8);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
               
                HAL_Delay(500);
                SrcAddress[0]++;  //for testing
                SrcAddress[7]++;  //for testing
               
                MX_DMA_Init();
                HAL_DMA_Start(&hdma_memtomem_dma2_stream0,(uint32_t)(&SrcAddress[0]),(uint32_t)(&DstAddress[0]), 8);
               
  }
  /* USER CODE END 3 */
}

使用特权

评论回复
8
supernan|  楼主 | 2021-8-14 19:31 | 只看该作者
改变了传输方式,选择内存到外设,但还是不能被定时器事件触发启动,

DMA_InitStructure.DMA_PeripheralBaseAddr         = (uint32_t)(&DMA2_Stream3->CR);        // DMA外设地址(SOURCE ADDR)
DMA_InitStructure.DMA_Memory0BaseAddr         = (uint32_t)(config_CR);        // DMA 存储器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                        // 内存到外设
不知道问题究竟在哪?

使用特权

评论回复
9
jiajs| | 2021-8-14 19:37 | 只看该作者
那应该是代码配置上哪里有问题,你好好检查下。

使用特权

评论回复
10
zwll| | 2021-8-14 19:38 | 只看该作者
如果可能话,最好使用stmcubeMx进行配置

使用特权

评论回复
11
huwr| | 2021-8-14 19:40 | 只看该作者
利用Cube库来开发,对于新手省很多事。

使用特权

评论回复
12
supernan|  楼主 | 2021-8-14 19:42 | 只看该作者
本帖最后由 supernan 于 2021-8-14 19:44 编辑

我再试试,找找问题。谢谢

使用特权

评论回复
13
supernan|  楼主 | 2021-8-14 19:45 | 只看该作者
经过几翻测试,最终实现了定时器触发DMA,实现DMA可控操作
下面提出最终的代码,供遇到问题的同仁参考。

/*
        程序实现内容:通过定时器触发DMA,实现DMA传输的可控性
        
        程序通过 定时器8 触发 DMA2_Stream1开启,DMA2_Stream1从内存到外设传递数据,每次传递数据的个数为5
        TIM8开启中断,每触发一次, DMA2_Stream1 开启一次传输,TIM8 触发100次后,关闭TIM8,清空 外设寄存器。
        
        主函数中循环打印外设寄存器的值,100次触发之内,外设寄存器的数据一直在更新,
        关闭定时器后,外设寄存器中的数据为0,表示TI8关闭后,DMA不再被触发。
        注:本测试总TIM8开启的了中断,用来观察和测试使用,实际应用中可以不开中断,TIM8同样会触发启动DMA.
*/


unsigned int timer8_times_count = 0;    // 计数用变量

unsigned int config_CR[5] = {0x06030440,0x06030446,0x06030442,0x06030448,0x06030444}; // 外部数据

/*
        通过 DMA2_Stream1_DMA_Channel_7 向  DMA2_Stream3的 CR 寄存器中搬运数据
        注:数据为测试数据,无实际意义,仅用于测试功能
*/

void DMA_Auto_Config_CR(void)
{   
        DMA_InitTypeDef DMA_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1|RCC_AHB1Periph_DMA2,ENABLE);         

        DMA_DeInit(DMA2_Stream1);
        while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}                                   // 等待DMA可配置

        DMA_InitStructure.DMA_Channel = DMA_Channel_7;                                            // 通道选择
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&DMA2_Stream3->CR);   // DMA外设地址(SOURCE ADDR)
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(config_CR);                       // DMA 存储器0地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                            // 内存到外设

        DMA_InitStructure.DMA_BufferSize = 5;                                                              // 数据传输量
        DMA_InitStructure.DMA_PeripheralInc        = DMA_PeripheralInc_Disable;                 // 外设增量模式
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                           // 存储器非增量模式
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;       // 外设数据长度:16位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;             // 存储器数据长度:16位
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                         // 使用循环模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                         // 优先级
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         

        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                    // 存储器突发单次传输
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;              // 外设突发单次传输
        DMA_Init(DMA2_Stream1, &DMA_InitStructure);
}
void hf_timer8_init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;        
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
        
        TIM_TimeBaseStructure.TIM_Period = 100-1;
        TIM_TimeBaseStructure.TIM_Prescaler = 60000-1;
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);

        NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_TIM13_IRQn;                    // 为方便观察,配置TIM8 UPDATE 中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
        NVIC_Init(&NVIC_InitStructure);  
        
        TIM_ClearFlag(TIM8,TIM_FLAG_Update);
        TIM_ITConfig(TIM8, TIM_IT_Update, ENABLE);                                        // 开中断便于观察
        TIM_SelectOutputTrigger(TIM8, TIM_TRGOSource_Update);

        TIM_DMACmd(TIM8,TIM_DMA_Update,ENABLE);                                     // 开启 TIM8 UPDATE 触发 DMA  ,即 DMA2_Stream1
        TIM_Cmd(TIM8,ENABLE);                                                                      // 开启 TIM8
        DMA_Cmd(DMA2_Stream1, ENABLE);                                                      // 开启 DMA
}

void TIM8_UP_TIM13_IRQHandler(void)                                                          // TIM8 UP 溢出中断
{
        if(TIM_GetITStatus(TIM8,TIM_IT_Update)==SET)
        {
                TIM_Cmd(TIM8, DISABLE);
                TIM_ClearITPendingBit(TIM8,TIM_IT_Update);                                  // 清除中断标志位

                printf("TIMER_8 update update update update update update update !\n");

                timer8_times_count++;
               
                if(timer8_times_count>=100)                                                         // 100次中断后,关闭定时,即停止TIM8 触发 DMA
                {
                        TIM_Cmd(TIM8, DISABLE);
                        DMA2_Stream3->CR = 0;                                                        // 清空外设寄存器
                }
                else                                                                                                // 100次以内,继续触发DMA
                {
                        TIM_Cmd(TIM8, ENABLE);
                }               
        }
}

int main(void)
{        
        uart5_init();
        DMA_Auto_Config_CR();                                                
        hf_timer8_init();                                                        

        while(1)
        {        
                printf("DMA2_Stream3->CR = 0x%x\n",DMA2_Stream3->CR);               
                delay_ms(10);        
        }
}

/*

打印结果:
                                        ......
                                         
        DMA2_Stream3->CR =        0x06030442;
        TIMER_8 update update update update update update update !
        TIMER_8 update update update update update update update !
        TIMER_8 update update update update update update update !
        
        DMA2_Stream3->CR =        0x06030444;
        TIMER_8 update update update update update update update !
        TIMER_8 update update update update update update update !
        TIMER_8 update update update update update update update !

        DMA2_Stream3->CR = 0;
        DMA2_Stream3->CR = 0;
        DMA2_Stream3->CR = 0;               
        DMA2_Stream3->CR = 0;
        DMA2_Stream3->CR = 0;
        DMA2_Stream3->CR = 0;
        DMA2_Stream3->CR = 0;
        DMA2_Stream3->CR = 0;
        DMA2_Stream3->CR = 0;
        DMA2_Stream3->CR = 0;
        .......        
*/

使用特权

评论回复
14
呐咯密密| | 2021-8-16 10:04 | 只看该作者
DMA的单次触发要是想循环启动,如果时间要求不高就重新初始化DMA,如果时间要求严格就先失能DMA,然后重新使能传输长度,然后再使能DMA,便可实现再一次启动,如果时间要求再严格就使用寄存器方式

使用特权

评论回复
15
zljiu| | 2021-9-6 14:14 | 只看该作者
重新初始化的话能好使吗

使用特权

评论回复
16
gwsan| | 2021-9-6 14:14 | 只看该作者
时间要求不高就重新初始化DMA

使用特权

评论回复
17
paotangsan| | 2021-9-9 10:27 | 只看该作者
这种搬运主要用在什么场合呢

使用特权

评论回复
18
renzheshengui| | 2021-9-9 10:29 | 只看该作者
这个是高级定时器吗

使用特权

评论回复
19
wakayi| | 2021-9-9 10:31 | 只看该作者
每次都要重新进行初始化吗

使用特权

评论回复
20
wowu| | 2021-9-9 10:34 | 只看该作者
有什么干扰了么 为什么还要再次初始化?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

730

主题

10412

帖子

6

粉丝