硬汉嵌入式论坛

 找回密码
 立即注册
查看: 228|回复: 5
收起左侧

[DMA] 脉冲输出,例程更改为DMA1_Stream2,运行错误

[复制链接]

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2024-3-4 16:59:52 | 显示全部楼层 |阅读模式
本帖最后由 zztq 于 2024-3-4 17:04 编辑

    使用例程DMAMUX的定时器触+DMA双缓冲控制任意IO做PWM和脉冲数控制,可以正常运行,发脉冲也正确。现在我想把DMA1_Stream1更改为DMA1_Stream2,然后我发脉冲的的时候,就程序就卡在DMA1_Stream2_IRQHandler的中断服务函数里面了。

   我把程序里面用到的DMA1_Stream1都更改为DMA1_Stream2了,是不是还有哪些地方要修改的,但我我没有注意到的?
代码修改的地方:

__HAL_RCC_DMA1_CLK_ENABLE();
    DMA_Handle.Instance                 = DMA1_Stream2;            /* 使用的DMA1 Stream1    此处改为DMA1_Stream2*/
    DMA_Handle.Init.Request             = DMA_REQUEST_GENERATOR0;  /* 请求类型采用的DMAMUX请求发生器通道0 */  
    DMA_Handle.Init.Direction           = DMA_MEMORY_TO_PERIPH;    /* 传输方向是从存储器到外设 */  
    DMA_Handle.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外设地址自增禁止 */
    DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;         /* 存储器地址自增使能 */  
    DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;     /* 外设数据传输位宽选择字,即32bit */     
    DMA_Handle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;     /* 存储器数据传输位宽选择字,即32bit */   
    DMA_Handle.Init.Mode                = DMA_CIRCULAR;            /* 循环模式 */   
    DMA_Handle.Init.Priority            = DMA_PRIORITY_LOW;        /* 优先级低 */  
    DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;    /* 禁止FIFO*/
    DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* 禁止FIFO此位不起作用,用于设置阀值 */
    DMA_Handle.Init.MemBurst            = DMA_MBURST_SINGLE;       /* 禁止FIFO此位不起作用,用于存储器突发 */
    DMA_Handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;       /* 禁止FIFO此位不起作用,用于外设突发 */

    /* 初始化DMA */
    if(HAL_DMA_DeInit(&DMA_Handle) != HAL_OK)
    {
                /* DMA处于忙状态,直接终止DMA */
                if(HAL_DMA_Abort_IT(&DMA_Handle) != HAL_OK)
                {
                   Error_Handler(__FILE__, __LINE__);                     
                }                  
    }

    /* 初始化DMA */
    if(HAL_DMA_Init(&DMA_Handle) != HAL_OK)
    {
                Error_Handler(__FILE__, __LINE__);     
    }

    /* 开启DMA1 Stream1的中断 */
    HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 1, 0);  //此处改为DMA1_Stream2_IRQn
    HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);




void DMA1_Stream2_IRQHandler(void)     //此处改为DMA1_Stream2_IRQn
{
        u8 i;
        /* 传输完成中断 */
        if((DMA1->LISR & DMA_FLAG_TCIF1_5) != RESET)
        {
                /* 清除标志 */
                DMA1->LIFCR = DMA_FLAG_TCIF1_5;
               
                HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7); //LED0输出电平翻转

                /* 当前使用的缓冲0 */
                if((DMA1_Stream2->CR & DMA_SxCR_CT) == RESET)   //此处改为DMA1_Stream2
                {
                        /*
                                1、当前正在使用缓冲0,此时可以动态修改缓冲1的数据。
                                   比如缓冲区0是IO_Toggle,缓冲区1是IO_Toggle1,那么此时就可以修改IO_Toggle1。
                                2、变量所在的SRAM区已经通过MPU配置为WT模式,更新变量IO_Toggle会立即写入。
                                3、不配置MPU的话,也可以通过Cahce的函数SCB_CleanDCache_by_Addr做Clean操作。
                        */
                        #ifdef UsedGPIOFMC       

                        if(PulseOutF1)
                        {
                                        for(i=0;i<Buff_MAX;i++)
                                        {
                                                IO_Toggle1=0x00800000U;
                                        }
                                       
                                        DMA_pos_cnt1 = 0;
                                        PulseOutF1 = 0;
                        }
                       
//                        if(PulseOutF1)
//                        {
//                               
//                                DMA_pos_cnt1++;
//                        }
//                               
                         
                        #else
                               
                        #endif
                }
                /* 当前使用的缓冲1 */
                else
                {
                         /*
                           1、当前正在使用缓冲1,此时可以动态修改缓冲0的数据。
                                  比如缓冲区0是IO_Toggle,缓冲区1是IO_Toggle1,那么此时就可以修改IO_Toggle。
                           2、变量所在的SRAM区已经通过MPU配置为WT模式,更新变量IO_Toggle会立即写入。
                           3、不配置MPU的话,也可以通过Cahce的函数SCB_CleanDCache_by_Addr做Clean操作。
                        */
                        #ifdef UsedGPIOFMC       
//               
       
                        if(DMA_pos_cnt >=DMA_pos_MAX)
                        {
                                PulseOutF = 0;
                                for(i=0;i<Buff_MAX;i++)
                                {
                                        IO_Toggle=0x00800000U;
                                }
                       
//                       
                               
                                DMA_pos_cnt = 0;
//                                HAL_DMAEx_DisableMuxRequestGenerator(&DMA_Handle);
                        }
                        #else
                               
                        #endif
                        if(PulseOutF)
                        {
                               
                                DMA_pos_cnt++;
                        }
                       
                       
                }
        }

        /* 半传输完成中断 */   
        if((DMA1->LISR & DMA_FLAG_HTIF1_5) != RESET)
        {
                /* 清除标志 */
                DMA1->LISR = DMA_FLAG_HTIF1_5;
        }

        /* 传输错误中断 */
        if((DMA1->LISR & DMA_FLAG_TEIF1_5) != RESET)
        {
                /* 清除标志 */
                DMA1->LISR = DMA_FLAG_TEIF1_5;
        }

        /* 直接模式错误中断 */
        if((DMA1->LISR & DMA_FLAG_DMEIF1_5) != RESET)
        {
                /* 清除标志 */
                DMA1->LISR = DMA_FLAG_DMEIF1_5;
        }
       
//        HAL_DMA_IRQHandler(&DMA_Handle);
}





回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
 楼主| 发表于 2024-3-4 18:14:23 | 显示全部楼层
好像解决了,是因为中断服务函数里面的中断标志位没有清对,DMA_FLAG_TCIF1_5不是直接对应DMA1_Stream2的标志位
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
 楼主| 发表于 2024-3-4 18:17:00 | 显示全部楼层
好像解决了,是因为中断服务函数里面的标志位没有清对,传输完成中断DMA_FLAG_TCIF4不是对应DMA1_Stream4。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2024-3-5 11:46:11 | 显示全部楼层
zztq 发表于 2024-3-4 18:14
好像解决了,是因为中断服务函数里面的中断标志位没有清对,DMA_FLAG_TCIF1_5不是直接对应DMA1_Stream2的标 ...

对,就是这个,移植的时候容易忽视。
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
 楼主| 发表于 2024-3-5 17:09:28 | 显示全部楼层
eric2013 发表于 2024-3-5 11:46
对,就是这个,移植的时候容易忽视。

我还有一个问题,就是我发送的脉冲数,有时候会多一个。
中断处理的代码如下:
u16 DMA_pos_S = 0;
u16 DMA_pos_cnt = 0,DMA_pos_cnt1,DMA_pos_MAX = 20;
u32 DMA_FLAG_TCIF4 =0x00000020u;  //DMA1_Stream4传输完成中断
u32 DMA_FLAG_HTIF4 =0x00000010u;  //DMA1_Stream4半传输完成中断
u32 DMA_FLAG_TEIF4 =0x00000008u;   //DMA1_Stream4 传输错误中断
u32 DMA_FLAG_DMEIF4 = 0x00000004u;  //DMA1_Stream4 直接模式错误错误中断
void DMA1_Stream4_IRQHandler(void)
{
        u8 i;
        /* 传输完成中断 */
//        if((DMA1->LISR & DMA_FLAG_TCIF1_5) != RESET)
                if((DMA1->HISR & DMA_FLAG_TCIF4) != RESET)
        {
                /* 清除标志 */
//                DMA1->LIFCR = DMA_FLAG_TCIF1_5;
                DMA1->HIFCR = DMA_FLAG_TCIF4;
               
                HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7); //LED0输出电平翻转

                /* 当前使用的缓冲0 */
                if((DMA1_Stream4->CR & DMA_SxCR_CT) == RESET)
                {
                        /*
                                1、当前正在使用缓冲0,此时可以动态修改缓冲1的数据。
                                   比如缓冲区0是IO_Toggle,缓冲区1是IO_Toggle1,那么此时就可以修改IO_Toggle1。
                                2、变量所在的SRAM区已经通过MPU配置为WT模式,更新变量IO_Toggle会立即写入。
                                3、不配置MPU的话,也可以通过Cahce的函数SCB_CleanDCache_by_Addr做Clean操作。
                        */
                        #ifdef UsedGPIOFMC       

                if(DMA_pos_cnt1 >=DMA_pos_MAX)
                        {
//                                PulseOutF = 0;       
//                        if(PulseOutF1)
                        {
                                        for(i=0;i<Buff_MAX;i++)
                                        {
//                                                IO_Toggle1=0x00800000U;
                                                IO_Toggle=0x00800000U;
                                        }
                                       
//                                        DMA_pos_cnt1 = 0;
//                                        PulseOutF1 = 0;
                        }
                       

                       
                       
                }
                        if(PulseOutF1)//发送使能标志
                        {
                               
                                DMA_pos_cnt1++;
                        }
                       
                       

//                               
                         
                        #else
                               
                        #endif
                }
                /* 当前使用的缓冲1 */
                else
                {
                         /*
                           1、当前正在使用缓冲1,此时可以动态修改缓冲0的数据。
                                  比如缓冲区0是IO_Toggle,缓冲区1是IO_Toggle1,那么此时就可以修改IO_Toggle。
                           2、变量所在的SRAM区已经通过MPU配置为WT模式,更新变量IO_Toggle会立即写入。
                           3、不配置MPU的话,也可以通过Cahce的函数SCB_CleanDCache_by_Addr做Clean操作。
                        */
                        #ifdef UsedGPIOFMC       
//               
//                for(i=0;i<Buff_MAX;i++)
//                                        {
//                                                IO_Toggle1=0x00800000U;
//                                        }
                       
                        if(DMA_pos_cnt1 >=DMA_pos_MAX)
                        {
                                PulseOutF1 = 0;
                                DMA_pos_cnt1 = 0;
                                PulseOutF = 0;
                                for(i=0;i<Buff_MAX;i++)
                                {
                                        IO_Toggle=0x00800000U;
                                        IO_Toggle1=0x00800000U;
                                }
                       
//                       
                               
                                DMA_pos_cnt = 0;
//                                HAL_DMAEx_DisableMuxRequestGenerator(&DMA_Handle);
                        }
                        #else
                               
                        #endif
//                        if(PulseOutF)
//                        {
//                               
//                                DMA_pos_cnt++;
//                        }
                       
                       
                       
                       
                }
        }

        /* 半传输完成中断 */   
//        if((DMA1->LISR & DMA_FLAG_HTIF1_5) != RESET)
        if((DMA1->HISR & DMA_FLAG_HTIF4) != RESET)
        {
                /* 清除标志 */
                        DMA1->HISR =  DMA_FLAG_HTIF4;
//                DMA1->LISR = DMA_FLAG_HTIF1_5;
        }

        /* 传输错误中断 */
//        if((DMA1->LISR & DMA_FLAG_TEIF1_5) != RESET)
        if((DMA1->HISR & DMA_FLAG_TEIF4) != RESET)
        {
                /* 清除标志 */
                DMA1->HISR = DMA_FLAG_TEIF4;
//                DMA1->LISR = DMA_FLAG_TEIF1_5;
        }

        /* 直接模式错误中断 */
//        if((DMA1->LISR & DMA_FLAG_DMEIF1_5) != RESET)
        if((DMA1->HISR & DMA_FLAG_DMEIF4) != RESET)       
        {
                /* 清除标志 */
//                DMA1->LISR = DMA_FLAG_DMEIF1_5;
                DMA1->HISR = DMA_FLAG_DMEIF4;
        }
       
//        HAL_DMA_IRQHandler(&DMA_Handle);
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2024-3-6 09:25:23 | 显示全部楼层
zztq 发表于 2024-3-5 17:09
我还有一个问题,就是我发送的脉冲数,有时候会多一个。
中断处理的代码如下:
u16 DMA_pos_S = 0;

DMA双缓冲方式,只要配置的对,是不会发送多余脉冲的。

注意MPU Cache问题和中断里面的脉冲值修改问题。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-28 12:02 , Processed in 0.231142 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表