找回密码
 立即注册
查看: 68|回复: 0

64-QSPI-Flash_DMA_P2P_SPI_TFT_显示视频级动画效果程序,STC32G144K246实验箱演示程

[复制链接]
  • 打卡等级:常住居民I
  • 打卡总天数:78
  • 最近打卡:2026-07-21 13:27:09
已绑定手机

231

主题

168

回帖

1069

积分

版主

积分
1069
发表于 2026-7-3 15:48:19 | 显示全部楼层 |阅读模式
64-QSPI-Flash_DMA_P2P_SPI_TFT_显示视频级动画效果程序,STC32G144K246实验箱演示程序
主程序main.C代码如下(汇编版本在附件中):


/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com  -----------------------------------------*/
/*---------------------------------------------------------------------*/

/*************  功能说明    **************

本例程基于STC32G144K246为主控芯片的实验箱进行编写测试。

使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。

edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。

QSPI DMA + SPI DMA驱动液晶屏程序

按住P3.3后上电,芯片进入FLASH下载模式,使用6.94P以后版本的ISP下载软件中的“串行Flash编程器”

工具将多幅图片下载到实验箱的Flash中,然后重新上电(P3.3不要按),即可进入动画显示模式

显示时QSPI 读取Flash图片数据,通过P2P DMA直接发送数据到SPI-LCD显示。

QSPI读取Flash与LCD显示DMA的数据长度设置38400字节。

SPI LCD 接口:
sbit P_LCD_CLK  =   P2^5;    //D0    SPI or II2 的时钟脚
sbit P_LCD_SDA  =   P2^3;    //D1    SPI or II2 的数据脚
sbit P_LCD_RST  =   P2^4;    //RES   复位脚, 低电平复位
sbit P_LCD_DC   =   P2^2;    //DC    数据或命令脚
sbit P_LCD_CS   =   P2^6;    //CS    片选脚

QSPI Flash 接口:
sbit CS         =   P7^5;
sbit SDI_IO0    =   P7^0;
sbit SDO_IO1    =   P7^2;
sbit SCK        =   P7^1;
sbit WP_IO2     =   P7^3;
sbit HLD_IO3    =   P7^4;

下载时, 选择IRC频率 48MHz,主时钟使用 PLL 60MHz 时钟频率.

本实验使用的1.3寸240*240的SPI接口彩屏

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

#include "config.h"
#include "qspi.h"
#include "w25qxx.h"
#include "tft.h"
#include "usbcdc.h"
#include "timer.h"

#define IMG_SIZE            (240UL * 240 * 2)
#define DMA_AMT_LEN         (38400UL)
#define DMA_CNT             (IMG_SIZE / DMA_AMT_LEN)

void SYS_Init(void);
void QSPI2TFT_Start();
void QSPI2TFT_Next();

typedef struct
{
    char strSign[4];
    DWORD dwCount;
    DWORD dwAddress[62];
} FAT;

FAT     Fat;                            //文件分配表
DWORD   dwOffset;                       //图片数据的偏移地址
int     nIndex;                         //图片索引
int     nCount;                         //图片数据装载次数
BOOL    fLoading;                       //装载数据标志

void main()
{
    EAXFR = 1;  // 扩展寄存器(XFR)访问使能
    CKCON = 1;  //避免 DMA 与 CPU 同时访问 xdata 时产生总线冲突

    P0M0 = 0x00; P0M1 = 0x00;
    P1M0 = 0x00; P1M1 = 0x00;
    P2M0 = 0x00; P2M1 = 0x00;
    P3M0 = 0x00; P3M1 = 0x00;
    P4M0 = 0xC0; P4M1 = 0x00;
    P5M0 = 0x00; P5M1 = 0x00;
   
    P3PU |= 0x0c;   //使能P3.2,P3.3内部上拉电阻
   
    SYS_Init();
    TIMER0_Init();
    QSPI_Init();
    SPI_Init();
    LCD_Init();
   
    EA = 1;

    W25Q_Enable_QE();                   //使能QSPI FLASH的4线读写模式
   
    if (!P33)                           //按住P3.3复位,进入图片数据下载模式
    {
        CDC_Init();
        CDC_WaitStable();               //等待USB-CDC配置完成
        while (1)
        {
            CDC_Process();              //CDC接口处理图片数据
        }
    }
   
    W25Q_FastRead_6B(0, (BYTE *)&Fat, 256);     //从FLASH第一页读取FAT
   
    nIndex = 0;                         //从第一幅图片开始显示
    while (1)
    {
        if (f100ms)
        {
            f100ms = 0;
            
            QSPI2TFT_Start();           //每隔100ms自动显示下一幅图片
        }
    }
}

void SYS_Init(void)
{
#if(HPLL_SEL==SEL_HPLL2)
    WTST = 1;           //通过WTST增加等待时钟控制Flash读取速度在33MHz以内, 主时钟:480MHz/2/4=60MHz, 读Flash速度:60MHz/(1+1)=30MHz

    HPLLCR |= 0x80;     //使能HPLL(高速外设默认使用HPLL时钟,切换到HPLL2前要先使能HPLL,切换完再关闭HPLL)

                        //首先需要将HIRC主频调节到48MHz
    HPLL2CR &= ~0x10;   //选择HPLL2输入时钟源为HIRC
//    HPLL2CR |= 0x10;    //选择HPLL2输入时钟源为IRCM
    HPLL2PDIV = 8;      //设置HPLL2输入时钟预分频为8(HPLL输入频率必须为6MHz)
//    HPLL2CR |= 0x00;    //HPLL2=6MHz*52=312MHz
//    HPLL2CR |= 0x01;    //HPLL2=6MHz*54=324MHz
//    HPLL2CR |= 0x02;    //HPLL2=6MHz*56=336MHz
//    HPLL2CR |= 0x03;    //HPLL2=6MHz*58=348MHz
//    HPLL2CR |= 0x04;    //HPLL2=6MHz*60=360MHz
//    HPLL2CR |= 0x05;    //HPLL2=6MHz*62=372MHz
//    HPLL2CR |= 0x06;    //HPLL2=6MHz*64=384MHz
//    HPLL2CR |= 0x07;    //HPLL2=6MHz*66=396MHz
//    HPLL2CR |= 0x08;    //HPLL2=6MHz*68=408MHz
//    HPLL2CR |= 0x09;    //HPLL2=6MHz*70=420MHz
//    HPLL2CR |= 0x0a;    //HPLL2=6MHz*72=432MHz
//    HPLL2CR |= 0x0b;    //HPLL2=6MHz*74=444MHz
//    HPLL2CR |= 0x0c;    //HPLL2=6MHz*76=456MHz
//    HPLL2CR |= 0x0d;    //HPLL2=6MHz*78=468MHz
    HPLL2CR |= 0x0e;    //HPLL2=6MHz*80=480MHz
//    HPLL2CR |= 0x0f;    //HPLL2=6MHz*82=492MHz
    HPLL2CR |= 0x20;    //高速外设时钟选择 HPLL2/2
    HPLL2CR |= 0x80;    //使能HPLL2

    HPLLCR &= ~0x80;    //关闭HPLL(高速外设默认使用HPLL时钟,切换到HPLL2前要先使能HPLL,切换完再关闭HPLL)
   
    CLKDIV = 4;         //系统时钟 = 主时钟源/2 = HPLL2/2/4 = 60MHz
    CLKSEL = 0x08;      //选择HPLL2/2作为主时钟源

#else
    WTST = 1;           //通过WTST增加等待时钟控制Flash读取速度在33MHz以内, 主时钟:480MHz/2/4=60MHz, 读Flash速度:60MHz/(1+1)=30MHz
                        //首先需要将HIRC主频调节到48MHz
    HPLLCR &= ~0x10;    //选择HPLL输入时钟源为HIRC
//    HPLLCR |= 0x10;     //选择HPLL输入时钟源为IRCM
    HPLLPDIV = 8;       //设置HPLL输入时钟预分频为8(HPLL输入频率必须为6MHz)
//    HPLLCR |= 0x00;     //HPLL=6MHz*52=312MHz
//    HPLLCR |= 0x01;     //HPLL=6MHz*54=324MHz
//    HPLLCR |= 0x02;     //HPLL=6MHz*56=336MHz
//    HPLLCR |= 0x03;     //HPLL=6MHz*58=348MHz
//    HPLLCR |= 0x04;     //HPLL=6MHz*60=360MHz
//    HPLLCR |= 0x05;     //HPLL=6MHz*62=372MHz
//    HPLLCR |= 0x06;     //HPLL=6MHz*64=384MHz
//    HPLLCR |= 0x07;     //HPLL=6MHz*66=396MHz
//    HPLLCR |= 0x08;     //HPLL=6MHz*68=408MHz
//    HPLLCR |= 0x09;     //HPLL=6MHz*70=420MHz
//    HPLLCR |= 0x0a;     //HPLL=6MHz*72=432MHz
//    HPLLCR |= 0x0b;     //HPLL=6MHz*74=444MHz
//    HPLLCR |= 0x0c;     //HPLL=6MHz*76=456MHz
//    HPLLCR |= 0x0d;     //HPLL=6MHz*78=468MHz
    HPLLCR |= 0x0e;     //HPLL=6MHz*80=480MHz
//    HPLLCR |= 0x0f;     //HPLL=6MHz*82=492MHz
    HPLL2CR &= ~0x60;   //高速外设时钟选择 HPLL/2
    HPLLCR |= 0x80;     //使能HPLL

    CLKDIV = 4;         //系统时钟=主时钟源/2 = HPLL/2/4 = 60MHz
    CLKSEL = 0x04;      //选择HPLL/2作为主时钟源
#endif

//    P5M0 |= 0x10; P5M1 &= ~0x10;//设置P5.4口为推挽输出
//    P5SR &= ~0x10;              //设置P5.4口为快速模式
//    HIRCCR |= 0x10;             //输出系统时钟
//    MCLKOCR = 10;               //系统时钟 10 分频到P5.4
}

void QSPI_DMA_Isr() interrupt DMA_QSPI_VECTOR
{
    DMA_QSPI_STA = 0x00;
    QSPI2TFT_Next();                    //DMA传输下一包数据
}

void QSPI2TFT_Start()
{
    if (fLoading)                       //如果正在装载图片,则退出
        return;

    if (nIndex >= Fat.dwCount)          //如果图片索引达到最大值
        nIndex = 0;                     //则从第一幅图片开始循环

    dwOffset = Fat.dwAddress[nIndex++]; //获取当前图片的偏移地址
    nCount = 0;                         //初始化图片数据装载次数
   
    while (QSPI_CheckBusy());           //检测忙状态
    QSPI_SetReadMode();                 //读模式
    QSPI_SetDataLength(DMA_AMT_LEN-1);  //设置数据长度
    QSPI_SetAddressSize(2);             //设置地址宽度为24位(2+1字节)
    QSPI_SetDummyCycles(8);             //设置DUMMY时钟
    QSPI_NoInstruction();               //设置无指令模式(防止误触发)
    QSPI_NoAddress();                   //设置无地址模式(防止误触发)
    QSPI_NoAlternate();                 //无间隔字节
    QSPI_DataQuadMode();                //设置数据为四线模式
    QSPI_SetInstruction(0x6B);          //设置指令
    QSPI_InstructionSingMode();         //设置指令为单线模式
    QSPI_NoAddress();                   //设置无地址模式(防止误触发)
    QSPI_SetAddress(dwOffset);          //设置地址
    QSPI_AddressSingMode();             //设置地址为单线模式
//    QSPI_SetClockDivider(5);           //设置QSPI时钟为系统时钟/(n+1),设置数据传输速度,如果速度太快SPI输出跟不上会导致传输异常

    TFT_ShowStart();                    //开始TFT彩屏显示

    DMA_P2P1_SRC = P2P_SRC_QSPIRX;
    DMA_P2P1_DEST = P2P_DEST_SPI1TX;
    DMA_QSPI_CFG = 0xa0;                //使能DMA读取操作
    DMA_QSPI_STA = 0x00;                //清除DMA状态
    DMA_QSPI_AMT = (DMA_AMT_LEN-1);     //设置DMA数据长度
    DMA_QSPI_AMTH = (DMA_AMT_LEN-1) >> 8;

    DMA_QSPI_CR = 0xa1;                 //启动DMA并触发QSPI读操作
   
    P47 = 0;
   
    fLoading = TRUE;
}

void QSPI2TFT_Next()
{
    dwOffset += DMA_AMT_LEN;            //更新偏移地址
    nCount++;                           //装载次数+1
   
    if (nCount < DMA_CNT)               //判断图片数据装载次数
    {
        QSPI_NoAddress();               //设置无地址模式(防止误触发)
        QSPI_SetAddress(dwOffset);      //设置地址
        QSPI_AddressSingMode();         //设置地址为单线模式
        
        DMA_QSPI_CR = 0xa1;             //启动DMA并触发QSPI读操作
    }
    else
    {
        P47 = 1;

        fLoading = FALSE;               //图片数据装载完成
        DMA_QSPI_CR = 0x00;             //停止QSPI_DMA
        DMA_QSPI_CFG = 0x00;
        DMA_P2P1_SRC = 0;
        DMA_P2P1_DEST = 0;
        
        TFT_ShowEnd();                  //结束TFT彩屏显示数据输入
    }
}

void delay_ms(WORD ms)
{
    WORD i;
   
    do
    {
        i = MAIN_Fosc / 6000;
        while(--i);
    } while(--ms);
}


64-QSPI-Flash_DMA_P2P_SPI_TFT_显示视频级动画效果程序.zip (1.13 MB, 下载次数: 1)
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-7-22 10:20 , Processed in 0.066519 second(s), 42 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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