OpenEdv-开源电子网

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

寄存器设置stm32H743串口2空闲中断+DMA传输完成中断接收数据会出现错误

[复制链接]

1

主题

2

帖子

0

精华

新手入门

积分
9
金钱
9
注册时间
2024-12-6
在线时间
2 小时
发表于 2025-5-25 00:34:04 | 显示全部楼层 |阅读模式
2金钱
各位大神,本人遇到了几个奇怪的问题,一个月了始终无法解决,特来求助:背景:(1)采用正点原子的stm32H743开发板,采用寄存器例程版本进行更改;
          (2)采用串口2空闲中断+DMA双循环传输完成中断,不间断通过串口传输几M图像数据;
          (3)mpu设置:保护整个AXI SRAM,共512K字节,禁止共用,允许cache,允许缓冲;保护外部SDRAM区域,共32M字节,禁止共用,禁止cache,禁止缓冲;
          (4)硬件电路有开发板和自己设计的电路,区别是外部SDRAM型号不一样,但是读写验证过了无问题。


问题1:仿照LCD显示样式,将DMA的目标地址设置为内部sram(AXI SRAM),DMA传输完成中断和串口空闲中断中将内部sram中的数据赋值到外部SDRAM中,在开发板中整个逻辑无问题。但是在自己的硬件中出现在后面的数据会偶尔出现错误,每一帧数据有几个字节数据会和传输的不一致。数据量一旦大就会出现传输错误。但是开发板未发现出现此问题。软件配置基本一样,只是外部SDRAM型号不一样,单独读写验证无问题,不知道具体问题。


问题2:将DMA的目标地址设置为外部SDRAM,由于外部SDRAM区域,禁止共用,禁止cache,禁止缓冲,我理解理论上不会出现cache数据不一致的问题。在开发板上无问题,传输数据无问题,但是在自己设计的硬件中数据始终不一致(传输的数据和目标地址接收的数据一直不一致)。

问题3:每次接收数据时,总会触发一次DMA接收完成中断,哪怕是传输一个数据,而DMA传输完成数据为100,也会触发DMA接收完成中断。和硬件无关。

问题4:初始化完成后会触发一次空闲中断和DMA传输完成中断。和硬件无关。

疑惑:目前自己设计的硬件除了外部SDRAM型号和开发板不一样以外,也不涉及到其他硬件,软件基本一样,只是更改了外部SDRAM的驱动。但是自己设计硬件要么不符合逻辑,要么存在错数。哪位大神能指点迷津。

附程序源码:
//初始化IO 串口2
//pclk1CLK1时钟频率(Mhz)
//bound:波特率
void USART2_Init(u32 pclk1,u32 bound)
{           
        u32 temp;
        temp=(pclk1*1000000+bound/2)/bound;        //得到USARTDIV@OVER8=0,采用四舍五入计算       
//        u16 mantissa;
//        u16 fraction;          
////        temp=(float)(pclk1*1000000)/(bound*16);//得到USARTDIV,OVER8设置为0
////        mantissa=temp;                                                         //得到整数部分
////        fraction=(temp-mantissa)*16;                         //得到小数部分,OVER8设置为0         
////    mantissa<<=4;
////        mantissa+=fraction;
        RCC->AHB4ENR|=1<<0;                                           //使能PORTA口时钟  
        RCC->APB1LENR|=1<<17;                                          //使能串口2时钟
        GPIO_Set(GPIOA,PIN2|PIN3,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_MID,GPIO_PUPD_PU);//PA2,PA3,复用功能,上拉输出
        GPIO_AF_Set(GPIOA,2,7);                                        //PA2,AF7
        GPIO_AF_Set(GPIOA,3,7);                                         //PA3,AF7            
        //波特率设置
        USART2->BRR=temp;         // 波特率设置       
        USART2->CR1=0;                         //清零CR1寄存器      //在对USART_CR1寄存器的TE位置位时,硬件会自动发送1个空闲帧出去
        USART2->CR1|=0<<28;                 //设置M1=0
        USART2->CR1|=0<<12;                 //设置M0=0&M1=0,选择8位字长
        USART2->CR1|=0<<15;         //设置OVER8=0,16倍过采样       
        USART2->CR1|=1<<3;          //串口发送使能         
        USART2->CR1|=1<<2;                             //串口接收使能
//        USART2->CR1|=1<<5;                          //接收缓冲区非空中断使能               
        MY_NVIC_Init(1,2,USART2_IRQn,2);//组2,最低优先级
        USART2->CR1|=1<<0;                            //串口使能

        USART2->CR1|=1<<4;                            //空闲使能         

        delay_ms(10);
}

//DMA配置
void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u8 chx,u32 paraddr,u32 mem0addr,u32 mem1addr,u16 ndtr)
{
        DMA_TypeDef *DMAx;
        DMAMUX_Channel_TypeDef *DMAMUXx;
        u8 streamx=0;
       
        if((u32)DMA_Streamx>(u32)DMA2)//得到当前stream是属于DMA2还是DMA1
        {
                DMAx=DMA2;
                RCC->AHB1ENR|=1<<1;//DMA2时钟使能
        }else
        {
                DMAx=DMA1;
                RCC->AHB1ENR|=1<<0;//DMA1时钟使能
        }
        RCC->D3AMR|=1<<0;                                          //DMAMUX时钟使能
       
        while(DMA_Streamx->CR&0X01);      //等待DMA可配置
        streamx=(((u32)DMA_Streamx-(u32)DMAx)-0X10)/0X18;                //得到stream通道号
       
        if((u32)DMA_Streamx>(u32)DMA2)
                streamx+=8;                                        //如果是DMA2,通道编号+8
        DMAMUXx=(DMAMUX_Channel_TypeDef *)(DMAMUX1_BASE+streamx*4);        //得到对应的DMAMUX通道控制地址
        DMAMUXx->CCR=chx&0XFF;                //通道选择

        if(streamx>=6)
                DMAx->HIFCR|=0X3D<<(6*(streamx-6)+16);        //清空之前该stream上的所有中断标志
        else if(streamx>=4)
                DMAx->HIFCR|=0X3D<<6*(streamx-4);    //清空之前该stream上的所有中断标志
        else if(streamx>=2)
                DMAx->LIFCR|=0X3D<<(6*(streamx-2)+16);//清空之前该stream上的所有中断标志
        else
                DMAx->LIFCR|=0X3D<<6*streamx;                                                //清空之前该stream上的所有中断标志       
//        delay_ms(10);
        DMA_Streamx->FCR=0x0000021;        //设置为默认值               
//        DMA_Streamx->FCR&=~(1<<2);        //不使用FIFO模式
//        DMA_Streamx->FCR&=~(3<<0);        //无FIFO 设置
       
        DMA_Streamx->AR=paraddr;                   //DMA外设地址
        DMA_Streamx->M0AR=mem0addr;                 //DMA 存储器0地址
        DMA_Streamx->M1AR=mem1addr;           //DMA 存储器1地址
        DMA_Streamx->NDTR=ndtr;                     //DMA 个数
        DMA_Streamx->CR=0;                                  //先全部复位CR寄存器值
        DMA_Streamx->CR|=0<<6;                     //0:外设到存储器模式                1:存储器模式到外设
        DMA_Streamx->CR|=1<<8;                     //0:非循环模式(即使用普通模式)      1:循环模式
        DMA_Streamx->CR|=0<<9;                     //0:外设非增量模式
        DMA_Streamx->CR|=1<<10;                     //1:存储器增量模式
        DMA_Streamx->CR|=0<<11;                     //外设数据长度:8位
        DMA_Streamx->CR|=0<<13;                     //存储器数据长度:8位
        DMA_Streamx->CR|=2<<16;                     //中等优先级
        DMA_Streamx->CR|=0<<21;                    //外设突发单次传输
        DMA_Streamx->CR|=0<<23;                    //存储器突发单次传输

        if(mem1addr)                                                //双缓冲的时候,才需要开启
        {
                DMA_Streamx->CR|=1<<18;                                //双缓冲模式

                MY_NVIC_Init(0,2,DMA1_Stream5_IRQn,2);//抢占1,子优先级3,组2
          DMA_Streamx->CR|=1<<4;                                //开启传输完成中断               
        }
        else
        {       
                DMA_Streamx->CR|=0<<18;                                //单模式
                MY_NVIC_Init(0,2,DMA1_Stream5_IRQn,2);//抢占1,子优先级3,组2
                DMA_Streamx->CR|=1<<4;                                //开启传输完成中断               
        }

        //DMA_Streamx->FCR=0X21;        //FIFO控制寄存器
}

//串口中断处理函数
void USART2_IRQHandler(void)
{
        u8 res=0;
        u16 rlen;                        //剩余数据长度
        u8 *pbuf;
        u16 i;
        u32 Frame_Head_Data=0;
        u32 Frame_Tail_Data=0;

        if(USART2->ISR&(1<<4))//空闲中断       
        {
                //清除中断
                USART2->ISR;  
          USART2->RDR;       
                USART2->ICR |= USART_ICR_IDLECF;       
          SCB_CleanInvalidateDCache();        //清除无效的D-Cache               
                DMA1_Stream5->CR&=~(1<<0);                              //停止当前传输
                while(DMA1_Stream5->CR&0X01);
                rlen=DMA_Buf_Size-DMA1_Stream5->NDTR;    //得到剩余数据长度       
               
//    printf("khx:%d\r\n",khx++);                       
    printf("B:Usart2_DMA_Time:%d\r\n",Usart2_DMA_Time);       
                printf("BB:RxData_Sdram_Len:%d\r\n",RxData_Sdram_Len);               
                if(Usart2_DMA_Time>0)
                {
                        RxData_Sdram_Len=RxData_Sdram_Len-DMA_Buf_Size;
                        Usart2_DMA_Time=0;
//                        printf("RxData_Sdram_Len:%d\r\n",RxData_Sdram_Len);
                }
                SCB_CleanInvalidateDCache();        //清除无效的D-Cache
                printf("B:RxData_Sdram_Len:%d\r\n",RxData_Sdram_Len);
                if(RxData_End_flag==0x99)
                {
                        pbuf=RxData_Sdram_Buf+RxData_Sdram_Len ;        //偏移到有效数据末尾,继续添加                               
                }
                else
                {
                        pbuf=RxData_Order_Buf;
                }
                if(DMA1_Stream5->CR&(1<<19))
                {
                        for(i=0;i<rlen;i++)
                        {
                                pbuf[i]=RxData_DMA_Buf[1][i];//读取buf1里面的剩余数据       
//                                RxData_DMA_Buf[1][i]=0;
                        }                       
                }
                else
                {
                        for(i=0;i<rlen;i++)
                        {
                                pbuf[i]=RxData_DMA_Buf[0][i];//读取buf0里面的剩余数据       
//                                RxData_DMA_Buf[0][i]=0;                               
                        }                       
                }

}






//DMA数据接收回调函数
void DMA_Rx_Callback(u8 mode)
{  
        u16 i;
        u8 *pbuf;
       
        if(RxData_End_flag==0x99)
        {
                pbuf=RxData_Sdram_Buf+RxData_Sdram_Len ;        //偏移到有效数据末尾,继续添加                               
        }
        else
        {
                pbuf=RxData_Order_Buf+RxData_Sdram_Len;
        }

        if(mode)
        {
                if(DMA1_Stream5->CR&(1<<19))//buf0已满,当前是buf1
                {
                        for(i=0;i<DMA_Buf_Size;i++)
                        {
                                pbuf[i]=RxData_DMA_Buf[0][i];//读取buf0里面的剩余数据       
//        RxData_DMA_Buf[0][i]=0;                               
                        }
                        RxData_Sdram_Len+=DMA_Buf_Size;//偏移
                }
                else //buf1已满,当前是buf0
                {
                        for(i=0;i<DMA_Buf_Size;i++)
                        {
                                pbuf[i]=RxData_DMA_Buf[1][i];//读取buf1里面的剩余数据       
//                                RxData_DMA_Buf[1][i]=0;//读取buf1里面的剩余数据                                       
                        }
                        RxData_Sdram_Len+=DMA_Buf_Size;//偏移
                }        
        }
        else
        {
                for(i=0;i<DMA_Buf_Size;i++)
                {
                        pbuf[i]=RxData_DMA_Buf[0][i];//读取buf0里面的剩余数据                                                               
                }
                RxData_Sdram_Len+=DMA_Buf_Size;//偏移       
        }

}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

2

帖子

0

精华

新手入门

积分
9
金钱
9
注册时间
2024-12-6
在线时间
2 小时
 楼主| 发表于 2025-5-26 15:53:37 | 显示全部楼层
有人遇到么?或者配置一样无此现象
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-5 12:26

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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