CH32V307 LVGL SPI DMA无法进入DMA中断

void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)

{

    NVIC_InitTypeDef  NVIC_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  //使能DMA传输


  DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值

    DMA1_MEM_LEN=cndtr;

    DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA外设ADC基地址

    DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  //数据传输方向,从内存读取发送到外设

    DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA通道的DMA缓存的大小

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增

    DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_Byte  ;  //数据宽度为8位

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte   ; //数据宽度为8位

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式

    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输

    DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器



    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);  //使能DMA传输完成中断




/*************************************************************************************************************/


//    int32_t x;

//    int32_t y;

//    for(y = area->y1; y <= area->y2; y++) {

//        for(x = area->x1; x <= area->x2; x++) {

//            /*Put a pixel to the display. For example:*/

//            /*put_px(x, y, *color_p)*/

//            LCD_DrawPoint(x, y, color_p->full);

//            color_p++;

//        }

//    }


//    u16 height, width;

//    uint32_t y=0;

//        width = area->x2 -area->x1 + 1;

//        height = area->y2 -area->y1 + 1;

//        LCD_Address_Set(area->x1,area->y1,area->x2,area->y2);

//        for(y = 0; y

//                {

//            LCD_WR_DATA(color_p->full);

//                    color_p++;

//                }

    void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

    void DMA1_Channel3_IRQHandler(void);

      {

          if(DMA_GetITStatus(DMA1_IT_TC3))

          {

              printf("进入DMA中断\r\n");                     //无法打印

              lv_disp_flush_ready(disp_drv);

              DMA_ClearITPendingBit(DMA1_IT_TC3); //清除全部中断标志

          }

      }

    LCD_Fill(area->x1,area->y1,area->x2,area->y2,color_p->full);



/*************************************************************************************************************/


void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color)                 //LCD打印函数

{          

    u16 color1[1];

    u16 num;

    color1[0]=color;

    num=(xend-xsta+1)*(yend-ysta+1)*2;

    LCD_Address_Set(xsta,ysta,xend,yend);//设置显示范围

    LCD_CS_Clr();

    MYDMA_Config(DMA1_Channel3,(u32)&SPI1->DATAR,(u32)color1,num);

    SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);

    MYDMA_Enable(DMA1_Channel3);

    LCD_CS_Set();


}



/*************************************************************************************************************/

如果不用DMA,使用以下函数之一是可以打印的

//    int32_t x;

//    int32_t y;

//    for(y = area->y1; y <= area->y2; y++) {

//        for(x = area->x1; x <= area->x2; x++) {

//            /*Put a pixel to the display. For example:*/

//            /*put_px(x, y, *color_p)*/

//            LCD_DrawPoint(x, y, color_p->full);

//            color_p++;

//        }

//    }


//    u16 height, width;

//    uint32_t y=0;

//        width = area->x2 -area->x1 + 1;

//        height = area->y2 -area->y1 + 1;

//        LCD_Address_Set(area->x1,area->y1,area->x2,area->y2);

//        for(y = 0; y

//                {

//            LCD_WR_DATA(color_p->full);

//                    color_p++;

//                }


我在DMA中断初始化中加入了,

NVIC_EnableIRQ(DMA1_Channel3_IRQn);

但是还是没有触发中断打印。


程序里定时器中断是可以正常打印的。但是打印一段后停住了,应该是dma这个过程中有什么问题。我无法解决,已经困扰相当一段时间了。


我选择用其它的刷新函数了,虽然速度会慢。


您好,目前从你贴的代码暂时没看出什么问题,有几个点你可以注意一下:

1、检查一下工程文件的配置是否正确,如启动文件、ch32v30x.h文件中相关宏定义以及ld文件中FLASH、RAM大小的配置

2、程序中在初始化的时候建议将相关结构体清零,具体可参考附件例程;

3、程序中若使用到中断,建议初始化时将相关的中断标志位清零;

4、若无法打印,检查一下是不是因为没有调用相关头文件;

5、程序中若要修改DMA传输的数据长度,建议可参考一下附件例程的操作方式;

附件为一个SPI使用DMA驱屏的例程,你可以参考一下。若方便,可以把你的工程文件发到我的邮箱(lzs@wch.cn)这边具体看一下,后续问题的沟通也可以通过邮箱和我沟通。

icon_rar.gifCH32V307 硬件SPI_DMA LCD.zip



沁恒给的DMA中断仍旧是8位双发2次凑成16位数据

u8 SPI_WriteByte(SPI_TypeDef* SPIx,u8 Byte)

{

#if USE_DMA==1

? ? TxData[0] = Byte;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//往缓冲区中写入数据

? ? DMA1_Channel5->CNTR = 1;? ? ? ? ? ? ? ? ? ? ? ? ? //填写要传输的数据长度

? ? DMA_Cmd(DMA1_Channel5,ENABLE);? ? ? ? ? ? ? ? ? ? //开启DMA传输

? ? while( DMA_GetFlagStatus(DMA1_FLAG_TC5) == RESET);//等待传输完成

? ? DMA_Cmd(DMA1_Channel5,DISABLE);? ? ? ? ? ? ? ? ? ?//关闭DMA

? ? DMA_ClearFlag(DMA1_FLAG_TC5);? ? ? ? ? ? ? ? ? ? ?//清除标志

#else

? ? while((SPIx->STATR&SPI_I2S_FLAG_TXE)==RESET);? ? //等待发送区空

? ? SPIx->DATAR=Byte;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //发送一个byte

? ? while((SPIx->STATR&SPI_I2S_FLAG_RXNE)==RESET);? ?//等待接收完一个byte

? ? return SPIx->DATAR;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //返回收到的数据

#endif


#if USE_DMA==1

? ? return 0;

#endif

}


void Lcd_WriteData_16Bit(u16 Data)

{

? ? Lcd_WriteData(Data>>8);? ? ? ? ? ?//16位数据高8位先行

? ? Lcd_WriteData(Data);????????????????? ?//16位数据低8位,color_p->full为16位

}



这其实并没有给优化速度提高多少,以下是我的刷新函数

? ? u16 height, width;

? ? ? ? uint32_t y=0;

? ? ? ? ? ? width = area->x2-area->x1+1 ;

? ? ? ? ? ? height = area->y2-area->y1+1;

? ? ? ? ? ?Lcd_SetRegion(area->x1,area->y1,area->x2,area->y2);

? ? ? ? ? ? for(y = 0; y

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? Lcd_WriteData_16Bit(color_p->full);

? ? ? ? ? ? ? ? ? ? ? ? color_p++;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? lv_disp_flush_ready(disp_drv);

进入刷新函数里每次cpu都要执行y++,这和DMA初衷不符,当然也拖慢了运行速度。DMA的使用应该建造一个大数组,将存储地址赋给这个数组起始地址,然后执行数据传输,释放CPU。这种方法适合画大图,而不是单单打点。

当驱动240*320画面时,DMA的U16的数据的大小并不够。传递字节数应该是320*240*2,我想尝试分4次进行DMA传输,但失败了。我不知道是什么原因,难道也要进行数据移位吗?



另外还有一个有意思的是,我的系统时钟是144Mhz,我给SPI进行的2分频,那它的速度应该是72Mhz,而我看数据手册SPI时钟最高36Mhz。然而当我进行4分频的时候,也就是36Mhz,屏幕变成一片白,而72Mhz却没有问题。

1699466832185911.png

1699466832177428.png

1699466843195678.jpg


只有登录才能回复,可以选择微信账号登录