OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7792|回复: 15

stm32f429(HAL库)串口1 DMA双缓冲接收数据模仿录音实验,失败!!!

[复制链接]

80

主题

268

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
441
金钱
441
注册时间
2014-8-11
在线时间
84 小时
发表于 2016-11-19 14:01:20 | 显示全部楼层 |阅读模式
1金钱
相关的配置函数

//串口1接收DMA初始化配置
//DMA2 数据流5  通道2或5
void UART1RxDMA_Config(u8* buf0,u8 *buf1,u16 num,u8 width)
{
    u32 memwidth=0,perwidth=0;     
    switch(width)
    {
        case 0:      
            memwidth=DMA_MDATAALIGN_BYTE;
            perwidth=DMA_PDATAALIGN_BYTE;
            break;
        case 1:     
            memwidth=DMA_MDATAALIGN_HALFWORD;
            perwidth=DMA_PDATAALIGN_HALFWORD;
            break;
        case 2:      
            memwidth=DMA_MDATAALIGN_WORD;
            perwidth=DMA_PDATAALIGN_WORD;
            break;
            
    }
        //impinjbuf1=mymalloc(SRAMEX,IMPINJ_BUF_SIZE);
        //impinjbuf2=mymalloc(SRAMEX,IMPINJ_BUF_SIZE);
    __HAL_RCC_DMA2_CLK_ENABLE();                                
    __HAL_LINKDMA(&UART1_Handler,hdmarx,UART1RxDMA_Handler);      
    UART1RxDMA_Handler.Instance=DMA2_Stream5;                                          
    UART1RxDMA_Handler.Init.Channel=DMA_CHANNEL_4;                 
    UART1RxDMA_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY;        
    UART1RxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;           
    UART1RxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;               
    UART1RxDMA_Handler.Init.PeriphDataAlignment=perwidth;           
    UART1RxDMA_Handler.Init.MemDataAlignment=memwidth;            
    UART1RxDMA_Handler.Init.Mode=DMA_CIRCULAR;                       
    UART1RxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;           
    UART1RxDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;         
    UART1RxDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;            
    UART1RxDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;           
    HAL_DMA_DeInit(&UART1RxDMA_Handler);                           
    HAL_DMA_Init(&UART1RxDMA_Handler);                              
   
    HAL_DMAEx_MultiBufferStart(&UART1RxDMA_Handler,(u32)&USART1->DR,(u32)buf0,(u32)buf1,num);
    __HAL_DMA_DISABLE(&UART1RxDMA_Handler);                        
    delay_us(10);                                                
    __HAL_DMA_CLEAR_FLAG(&UART1RxDMA_Handler,DMA_FLAG_TCIF1_5);//清除传输完成中断标志位     
    __HAL_DMA_ENABLE_IT(&UART1RxDMA_Handler,DMA_IT_TC);    //开启传输完成中断         
   
    HAL_NVIC_SetPriority(DMA2_Stream5_IRQn,0,1);                 
    HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
}

void ImpinjRxDMA_Start(void)
{   
    __HAL_DMA_ENABLE(&UART1RxDMA_Handler);
}

void ImpinjRxDMA_Stop(void)
{
    __HAL_DMA_DISABLE(&UART1RxDMA_Handler);
}

void DMA2_Stream5_IRQHandler(void)
{  
    if(__HAL_DMA_GET_FLAG(&UART1RxDMA_Handler,DMA_FLAG_TCIF1_5)!=RESET) //DMA传输完成
    {
        __HAL_DMA_CLEAR_FLAG(&UART1RxDMA_Handler,DMA_FLAG_TCIF1_5);     //清除DMA传输完成中断标志位
        UART1RxDMA_callback();    //执行回调函数,读取数据等操作在这里面处理  
    }        
}

//这个回调函数里是切换传输完成内存块的地址
//我所用的双缓冲是在一个大缓存里取相邻的两个小缓存
void UART1RxDMA_callback(void)
{      
        sw_cnt=sw_cnt+1;
      if(sw_cnt/2==1)
        {
            sw_0=sw_0+1;
        }
        else
        {
            sw_1=sw_1+1;
        }            
        if(DMA2_Stream5->CR&(1<<19))
        {
            DMA2_Stream1->M0AR = (u32)&IPJ_BUF[sw_0*2*IPJ_miniBUF_SIZE];
            LED0=!LED0;
        }
        else
        {
            DMA2_Stream1->M1AR = (u32)&IPJ_BUF[IPJ_miniBUF_SIZE+sw_1*2*IPJ_miniBUF_SIZE];
            LED1=!LED1;
        }            
}

//初始化
IPJ_BUF_MALLOC();   //大缓存内存申请
UART1RxDMA_Config(IPJ_BUF,&IPJ_BUF[IPJ_miniBUF_SIZE],IPJ_miniBUF_SIZE,0);//开始采用大缓存的首地址和一个偏移地址,传输项目量为偏移地址大小即小缓存大小
ImpinjRxDMA_Start();//开启传输


问题:无法进入传输完成中断

最佳答案

查看完整内容[请看2#楼]

问题找到了 没有使能串口1的DMA传输 另外原子哥看下这个帖子http://www.openedv.com/thread-87508-1-1.html 里面的串口1接收DMA通道选择是不是不对:DMA_Streamx->CR|=(u32)chx
我是一只菜鸟,但我会大鹏展翅
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

80

主题

268

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
441
金钱
441
注册时间
2014-8-11
在线时间
84 小时
 楼主| 发表于 2016-11-19 14:01:21 | 显示全部楼层
正点原子 发表于 2016-11-20 19:22
先搞出来DMA接收数据(不用双缓冲)

问题找到了  没有使能串口1的DMA传输  
另外原子哥看下这个帖子http://www.openedv.com/thread-87508-1-1.html

里面的串口1接收DMA通道选择是不是不对:DMA_Streamx->CR|=(u32)chx<<25;  //通道选择

我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

80

主题

268

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
441
金钱
441
注册时间
2014-8-11
在线时间
84 小时
 楼主| 发表于 2016-11-19 14:02:53 | 显示全部楼层
回调函数应该都是DMA2_stream5,但问题还是一样的
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

80

主题

268

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
441
金钱
441
注册时间
2014-8-11
在线时间
84 小时
 楼主| 发表于 2016-11-20 10:10:01 | 显示全部楼层
寄存器状态

这是我配置完成后寄存器的状态

这是我配置完成后寄存器的状态
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

80

主题

268

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
441
金钱
441
注册时间
2014-8-11
在线时间
84 小时
 楼主| 发表于 2016-11-20 10:11:31 | 显示全部楼层
这是录音机实验接收DMA配置后寄存器状态

录音机实验录音DMA寄存器状态

录音机实验录音DMA寄存器状态
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

80

主题

268

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
441
金钱
441
注册时间
2014-8-11
在线时间
84 小时
 楼主| 发表于 2016-11-20 10:12:29 | 显示全部楼层
这个问题纠结了我两天两夜了,很是无语,配置都是对的,就是不工作
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165516
金钱
165516
注册时间
2010-12-1
在线时间
2116 小时
发表于 2016-11-20 19:22:07 | 显示全部楼层
先搞出来DMA接收数据(不用双缓冲)
回复

使用道具 举报

2

主题

11

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2016-11-23
在线时间
11 小时
发表于 2016-11-23 22:03:24 | 显示全部楼层
楼主你好,我最近也在弄HAL库DMA的双缓冲,为什么试了下按你的配置 ,DMA中断能进传输完成中断DMA_FLAG_TCIF1_5,再进了RxDMA_callback函数后,DMA却不能自动更换缓存区, 查询CR的标志位一直没变化,我用的是UART3的DMA1_Stream1通道4


//UART3RxDMA的通道配置
//从外设->存储器模式/8位数据宽度/外设增量模式
//DMA数据流MA1_Stream1
//DMA通道:  DMA_CHANNEL_4
void UART3RxDMA_init()
{
    __HAL_RCC_DMA1_CLK_ENABLE();                                        //DMA1时钟使能          
    __HAL_LINKDMA(&UART3_Handler,hdmarx,UART3RxDMA_Handler);            //将DMA与USART3联系起来(接收DMA)
   
    //Rx DMA配置
    UART3RxDMA_Handler.Instance=DMA1_Stream1;                           //数据流选择DMA1_Stream1
    UART3RxDMA_Handler.Init.Channel=DMA_CHANNEL_4;                      //通道选择  DMA_CHANNEL_4
    UART3RxDMA_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY;             //外设到存储器
    UART3RxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;                 //外设非增量模式
    UART3RxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;                     //存储器增量模式
    UART3RxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;    //外设数据长度:8位
    UART3RxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE;       //存储器数据长度:8位
    //UART3RxDMA_Handler.Init.Mode=DMA_NORMAL;                            //外设普通模式
        UART3RxDMA_Handler.Init.Mode=DMA_CIRCULAR;                          //外设普通模式
    UART3RxDMA_Handler.Init.Priority=DMA_PRIORITY_HIGH;                 //高等优先级
    UART3RxDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;              
    UART3RxDMA_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;      
    UART3RxDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;                 //存储器突发单次传输
    UART3RxDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;              //外设突发单次传输
    HAL_DMA_DeInit(&UART3RxDMA_Handler);   
    HAL_DMA_Init(&UART3RxDMA_Handler);
       
        HAL_DMAEx_MultiBufferStart(&UART3RxDMA_Handler,(u32)&USART3->DR,(u32)UART3_RX_BUF0,(u32)UART3_RX_BUF1,UART3_REC_LEN);
        __HAL_DMA_DISABLE(&UART3RxDMA_Handler);
        delay_us(10);
        __HAL_DMA_CLEAR_FLAG(&UART3RxDMA_Handler,DMA_FLAG_TCIF1_5);         //清除传输完成中断标志位

    __HAL_DMA_ENABLE_IT(&UART3RxDMA_Handler,DMA_IT_TC);                 //开启传输完成中断
       
        HAL_NVIC_SetPriority(DMA1_Stream1_IRQn,0,4);                 
    HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
       
        __HAL_DMA_ENABLE(&UART3RxDMA_Handler);

        HAL_UART_Receive_DMA(&UART3_Handler, UART3_RX_BUF0, UART3_REC_LEN);  //先开启DMA接收
        USART3->CR3 |= USART_CR3_DMAR;
}


//UART3RxDMA接收中断服务程序
void DMA1_Stream1_IRQHandler(void)
{
        printf("DMA1_Stream1_IRQHandler in!\r\n");
        if(__HAL_DMA_GET_FLAG(&UART3RxDMA_Handler,DMA_FLAG_TCIF1_5)!=RESET) //DMA传输完成
    {       
                printf("DMA_FLAG_TCIF1_5 != RESET!\r\n");
        __HAL_DMA_CLEAR_FLAG(&UART3RxDMA_Handler,DMA_FLAG_TCIF1_5);     //清除DMA传输完成中断标志位
        UART3RxDMA_callback();    //执行回调函数,读取数据等操作在这里面处理
    }   
}

//切换传输完成原始数据接收内存块的地址
void UART3RxDMA_callback(void)
{                 
         //if(DMA1_Stream1->CR&(1<<19))
                                if((DMA1_Stream1->CR & DMA_SxCR_CT) == RESET)
        {
            //DMA1_Stream1->M0AR = (u32)&UART3_RX_BUF0[UART3_REC_LEN];
                                                printf("DMA1_Stream1->M0AR\r\n");
        }
        else
        {
            //DMA1_Stream1->M1AR = (u32)&UART3_RX_BUF1[UART3_REC_LEN];
                                                printf("DMA1_Stream1->M1AR\r\n");
        }            
}

#define DMA_SxCR_CT  0x00080000U

(DMA1_Stream1->CR & DMA_SxCR_CT)的判断值永远不变化,缓冲不能替换,一直打印  printf("DMA1_Stream1->M0AR\r\n");
回复

使用道具 举报

80

主题

268

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
441
金钱
441
注册时间
2014-8-11
在线时间
84 小时
 楼主| 发表于 2016-11-24 20:59:50 | 显示全部楼层
我的寄存器CT值是交替变化的啊,你可以把你的project发我,我调试下看看
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

80

主题

268

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
441
金钱
441
注册时间
2014-8-11
在线时间
84 小时
 楼主| 发表于 2016-11-24 21:01:17 | 显示全部楼层
战舰水手 发表于 2016-11-24 20:59
我的寄存器CT值是交替变化的啊,你可以把你的project发我,我调试下看看

你跟踪下寄存器的值,peripherals控件选DMA1找对应数据流的CT
我是一只菜鸟,但我会大鹏展翅
回复

使用道具 举报

2

主题

11

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2016-11-23
在线时间
11 小时
发表于 2016-11-24 22:44:39 | 显示全部楼层
战舰水手 发表于 2016-11-24 21:01
你跟踪下寄存器的值,peripherals控件选DMA1找对应数据流的CT

现在能分别进入M0AR和M1AR切换了,但是第一包数据(很大的话)能两个MxAR多次切换成功,而第二包数据就不能再切换了, 今后再进入完成中断之后,CR的值好像就不变了,不知为何?
  我采用的是串口空闲中断+DMA双缓冲
回复

使用道具 举报

2

主题

11

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2016-11-23
在线时间
11 小时
发表于 2016-11-24 22:46:59 | 显示全部楼层
会不会是哪里还要清空一下   DMA接收中断里面我用的是HAL库里的 HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma);       
回复

使用道具 举报

2

主题

11

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2016-11-23
在线时间
11 小时
发表于 2016-11-24 22:53:48 | 显示全部楼层
mowenhui 发表于 2016-11-24 22:44
现在能分别进入M0AR和M1AR切换了,但是第一包数据(很大的话)能两个MxAR多次切换成功,而第二包数据就不 ...

说错了 不是CR寄存器的问题  我跟踪到应该是 DMA_SxCR_DBM这个寄存器的值没有被置位
导致

if(((hdma->Instance->CR) & (uint32_t)(DMA_SxCR_DBM)) != RESET)
      {
        /* Current memory buffer used is Memory 0 */
        if((hdma->Instance->CR & DMA_SxCR_CT) == RESET)
        {
            //自定义1号缓存函数
                        Memory1CpltCallback(hdma);
        }
        /* Current memory buffer used is Memory 1 */
        else
        {
                        //自定义0号缓存函数
                        Memory0CpltCallback(hdma);
        }
      }
      /* Disable the transfer complete interrupt if the DMA mode is not CIRCULAR */
      else if((hdma->Instance->CR) != RESET)
      {
        if((hdma->Instance->CR & DMA_SxCR_CIRC) == RESET)
        {
          /* Disable the transfer complete interrupt */
          hdma->Instance->CR  &= ~(DMA_IT_TC);

          /* Process Unlocked */
          __HAL_UNLOCK(hdma);

          /* Change the DMA state */
          hdma->State = HAL_DMA_STATE_READY;
        }

                RxDMA_callback(hdma);  //自定义DMA接收完成处理函数
      }
回复

使用道具 举报

2

主题

11

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2016-11-23
在线时间
11 小时
发表于 2016-11-24 23:40:11 | 显示全部楼层
现在貌似多包数据都可以正常切换存储地址了  原因估计是我用了串口空闲中断    空闲中断中处理完数据后  得再次初始化下DMA接收 调用下
HAL_DMA_Init 和 HAL_DMAEx_MultiBufferStart    这样我看打印信息跟踪的才对了   

第一包:
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
第二包:
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!

之前有问题的时候是:
第一包:
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
UART1RxDMA Memory0CpltCallback!
UART1RxDMA Memory1CpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!

第二包:
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
rx_len interrupt = 267
UART1RxDMA XferCpltCallback!
回复

使用道具 举报

3

主题

48

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1126
金钱
1126
注册时间
2017-2-16
在线时间
104 小时
发表于 2017-4-4 08:15:34 | 显示全部楼层
mowenhui 发表于 2016-11-24 23:40
现在貌似多包数据都可以正常切换存储地址了  原因估计是我用了串口空闲中断    空闲中断中处理完数据后  得 ...

我现在也在写DMA双缓冲+空闲中断,但写了几天没写出来,能看看你的工程吗,十分感谢!
回复

使用道具 举报

1

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
76
金钱
76
注册时间
2017-7-26
在线时间
19 小时
发表于 2018-3-30 02:06:58 | 显示全部楼层
mowenhui 发表于 2016-11-24 23:40
现在貌似多包数据都可以正常切换存储地址了  原因估计是我用了串口空闲中断    空闲中断中处理完数据后  得 ...

你好,我最近也被这个问题困惑住了,配置找检查过好多次了,但是还是进不了DMA中断,请问能把工程给我发一份看看吗?谢谢
▄︻┻┳═ 没有征程,哪有征服!—— Keep going~~~!
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-20 22:39

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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