新手入门
- 积分
- 9
- 金钱
- 9
- 注册时间
- 2024-12-6
- 在线时间
- 2 小时
|
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
//pclk1 CLK1时钟频率(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;//偏移
}
}
|
|