☰
基于OV7670和FIFO的TFT实时预览:嵌入式显示调试实战
2026/10/13 5:53:41 网站建设 项目流程

最近在调一个Camera demo project for testing TFT preview,说白了,就是让摄像头把画面实时送到TFT彩屏上显示。这个项目听起来不像什么大工程,但真做起来,从摄像头输出格式、FIFO缓冲、SPI传输到屏幕刷新,每一环都能让你磨掉一整天。我这次用的是一块国产低功耗MCU、一颗非常经典的OV7670摄像头模块,以及一块SPI接口的小尺寸TFT屏。整个调试过程几乎把嵌入式常见的坑都踩了一遍,所以这篇文章不只是记录demo怎么跑起来,更想把我选型时怎么想、驱动怎么拆、故障怎么定位的思路完整理一遍。如果你手里也有类似的“摄像头显示”需求,不管是从零开始,还是想把一个半成品调通,这份经验应该都能帮上忙。

1. 为什么会有这个Demo:从测试工装到TFT预览

1.1 项目需求是怎么来的

这年头给产品加屏幕已经不是什么新鲜事,但屏幕这一块“能不能稳定显示”往往不是芯片厂商给你一个参考例程就能解决的。尤其是TFT彩屏,走SPI接口的屏便宜、好用,但一旦刷新帧率上不去、颜色不对、图像撕裂,排查起来非常痛苦。我手上的项目并不是直接做一个相机产品,而是一个硬件测试工装,需要在产线上通过屏幕显示摄像头采集的画面,用来快速判断摄像头模组是否正常、TFT屏的显示链路是否通。

说白了,这是一个“供测试使用的TFT预览工程”。它不追求高帧率、不追求漂亮的UI,核心目标是:一条确定的图像链路——摄像头采集、数据缓存、SPI送屏——能不能稳定跑起来,跑起来之后还有多少余量可以给上层应用用。在这个目标下,我把它拆成了一个最小的Camera demo project,只保留最基础的拍照、取图、显示逻辑,但把驱动层全部铺开,方便后续调整任何一段硬件。

1.2 Demo要解决的核心问题

既然是“for testing TFT preview”,那首当其冲的是验证TFT屏本身。新贴的屏幕、新画的PCB、新接的背光,都可能因为焊接虚焊、信号线过长、SPI时序不匹配导致显示异常。如果用了一个复杂的摄像头实时预览程序,一旦屏幕花了,你根本分不清是摄像头的问题还是TFT的问题。所以我第一步先让一个纯色块或简单的测试画面在屏幕上跑通,确认TFT驱动没问题之后,再把摄像头数据接进来。

这套流程看上去迂回,但确实能大幅缩小排查范围。很多第一次做摄像头预览的人,总想一口气把摄像头和屏幕全部打通,结果花屏之后只能干瞪眼。我这次在验证完TFT之后才去初始化摄像头,后面图像的每一步都有参照物,排查效率高很多。

1.3 这个Demo适合谁参考

如果你是嵌入式开发的新手,想学习怎么驱动SPI TFT屏幕,或者怎么读一个并行摄像头模块,这个项目可以作为一个入门到进阶的完整案例;如果你已经做过单屏或单摄像头,但一直没把两者串起来,也可以参考这里的数据通路设计。尤其是那些不想用昂贵开发板,想用低端MCU做低分辨率图像显示的场景,这篇文章里的选型和优化思路会很有价值。

2. 硬件选型:为什么用OV7670+FIFO模块和HC32L072

2.1 摄像头:经典OV7670带FIFO模块

摄像头这一环,很多人第一反应是OV2640、OV5640这一类高分辨率Sensor,但对于一个TFT预览测试项目,我推荐OV7670,而且是带FIFO缓冲的模块版本。原因有三。

第一,OV7670数据手册非常公开,寄存器说明齐全,网上成功案例多,哪怕你之前完全没碰过摄像头驱动,也能找到大量参考资料。第二,OV7670的输出可以在RGB565、RGB444、YUV等格式间切换,分辨率可以做到320x240的QVGA,刚好和常见的1.8寸、2.4寸TFT屏匹配。第三,也是最关键的,很多卖家配套的模块上集成了AL422B FIFO芯片。

AL422B是一个384K字节的FIFO。有了它,摄像头可以连续地把图像像素写入FIFO,MCU不需要实时跟踪每一个像素时钟,而是可以等一帧写完后再慢慢读出来。这等于把“实时采集”变成了“按帧搬砖”,大大降低了对MCU性能和实时性的要求。没有FIFO的裸摄像头虽然也可以做,但需要MCU有足够的DMA资源并且严格同步像素时钟,调试难度会直线上升。

2.2 MCU:HC32L072够不够用

很多读者看到HC32L072可能会问,这不是一颗低功耗控制型MCU吗,用来做图像显示是不是太勉强了?确实,如果做实时显示、人脸识别之类的应用,这颗芯片肯定不合适。但我们这里的目标是“测试TFT预览”,不是“流畅视频播放”,所以只要能实现一帧一帧读取、刷新,任务就完成了。

HC32L072主频最高可以到64MHz左右(不同封装和型号略有差异),SRAM从8KB到几十KB可选。如果直接缓存一整帧QVGA RGB565数据,3202402=153600字节,那得选大封装高配置版本。为了让普通型号也能跑,我实际操作时没有在MCU里缓存完整帧,而是直接从FIFO读数、边读边往TFT发送。这样MCU只需要一块很小的行缓冲,甚至可以不缓存整帧,从而绕开SRAM不足的问题。

同时HC32L072自带硬件SPI、DMA、定时器和多个通用GPIO,SPI发送可以用DMA减轻CPU负担。对一颗只做预览的MCU来说,这个配置算很均衡了。如果换到STM32F103这种经典MCU,其实思路也完全一样,只是寄存器配置不同。

2.3 TFT屏幕:ST7735S和ILI9341怎么选

TFT屏幕我用了两块,一块1.8寸ST7735S,一块2.4寸ILI9341,都是SPI接口。ST7735S最大分辨率一般是128x160,ILI9341是320x240,刚好匹配OV7670输出QVGA。做测试时,我建议先上128x160的ST7735S,因为它像素少,刷新压力小,调通后可以放大画面到2.4寸屏。这样能避免一开始就卡在高分辨率刷新率上,分不清是驱动问题还是性能问题。

有一点要注意:ST7735S和ILI9341即使是同一厂家同型号,初始化命令序列也可能因为封装批次不同而有细微差异。所以拿到屏幕的第一件事,不是写代码,而是确认屏的具体型号、驱动IC版本,然后去原厂或者靠谱渠道找初始化序列。

我把硬件连接整理成一张表,方便你在选型时对照:

外设引脚/信号接MCU引脚说明
摄像头模块SIOC / SIODI2C时钟/数据OV7670寄存器配置
摄像头模块VSYNCGPIO输入帧同步信号
摄像头模块FIFO WRSTGPIO输出FIFO写指针复位
摄像头模块FIFO RRSTGPIO输出FIFO读指针复位
摄像头模块FIFO OEGPIO输出FIFO输出使能
摄像头模块FIFO RCLKGPIO输出FIFO读时钟
摄像头模块DOUT[7:0]GPIO输入像素并行数据
TFT屏SCKSPI时钟硬件SPI时钟
TFT屏MOSISPI主机输出数据线
TFT屏CSGPIO输出片选
TFT屏DCGPIO输出数据/命令选择
TFT屏RSTGPIO输出复位
TFT屏BLKGPIO/PWM背光

2.4 为什么不用带DVP接口的MCU

很多有一定资源的MCU会直接带DVP数字摄像头接口,可以自动把摄像头并行数据搬进内存。HC32L072没有DVP,STM32F4系列很多型号也没有DVP。如果你一定想用DVP,那得换STM32H7、NXP i.MX RT等等。但是在我们这个测试场景里,DVP不是必需品。

DVP虽然省心,但它会引入另一个问题:MCU需要专门的DMA通道去接收像素数据,还要处理VSYNC、HREF、PCLK时序,而且如果摄像头分辨率太高,DMA带宽会变得很紧张。而FIFO方案把摄像头“排队”的活交给了AL422B,MCU只要在空闲时慢慢读数据就行,这让调试难度下降了一个档次。所以我个人强烈建议,除非你的产品必须实时预览且帧率要求高,否则测试阶段优先选FIFO模块。

3. 打通TFT屏:初始化序列与SPI刷屏的五个细节

3.1 SPI时钟极性、相位与速率

TFT屏的SPI接口一般比较宽容,但ST7735S和ILI9341官方手册都要求SPI Mode 0或Mode 3。我这次用的是SPI Mode 0:CPOL=0、CPHA=0,也就是时钟空闲为低、数据在上升沿采样。如果选错,屏幕大概率白屏或者出现随机噪点。

速率方面,理论上ST7735S可以跑很高,但受限于MCU的硬件SPI模块以及PCB布线,实际跑20MHz左右比较稳妥。我用HC32L072的硬件SPI时,会把分频系数配置成使SPI时钟尽量接近20MHz。速率太高会出噪声,太低会导致刷新一帧太久,刷新慢到能肉眼看到屏幕从下往上扫描,体验极差。

3.2 初始化序列:要的是稳定不是花哨

TFT屏幕的初始化代码并不难,但必须严格按顺序发送指定命令。以ST7735S为例,通常先复位、然后SLPOUT、等待足够时间,再设置帧率格式、颜色格式、显示方向、Gamma曲线、点亮显示等。

我见过很多新手把初始化序列直接从网上复制,发现显示颜色不对之后,第一反应是改代码里的颜色宏,但其实是初始化时序里某个Delay时间不够。ST7735S和ILI9341内部的DCDC和时序校准都需要时间,尤其是SLPOUT之后,至少要等待120ms,否则后续命令不生效。我有一次调试时屏幕一直白屏,最后发现就是Reset信号拉长后没有等足够久,导致初始化序列没能正确写入。

3.3 像素格式和颜色字节序

TFT屏和摄像头都有颜色格式的设置。ST7735S支持RGB565和RGB666等格式,OV7670也可以输出RGB565。看起来都是RGB565,但只要端序不一致,显示画面就会偏蓝偏红甚至发绿。最典型的坑是:OV7670输出的RGB565是大端序,即高字节在前;而有些TFT屏默认希望SPI先收到高字节,再收到低字节。如果两端都配置成同一格式,问题不大;如果摄像头配置成了RGB565小端,屏幕那边又按大端解析,颜色就全乱了。

我建议在设计驱动时,把像素字节序统一封装成一个宏,后面调试颜色时只需要改一处。比如:

#define PIXEL_FORMAT_RGB565 1 #define RGB565(r, g, b) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | ((b) >> 3))

刷屏时,先发高字节,再发低字节,这样与大多数SPI TFT的预期一致。

3.4 窗口地址和扫描方向

窗口地址是TFT屏最容易出问题的地方。如果你没有正确设置Column Address和Row Address,而是直接往显存里写数据,那么画面会出现整体偏移、错位或者呈斜线状分布。比如ILI9341的CASET、RASET命令,写完之后还要把X、Y坐标范围转成对应的5位或8位参数,不同驱动IC的坐标习惯可能还不一样。

还有扫描方向。竖屏、横屏、镜像、旋转,分别对应MX、MY、MV这几个bit的组合。在做摄像头显示时,最好把屏幕扫描方向设置成和摄像头输出的图像方向一致,否则你还要额外做一次坐标旋转,不仅浪费MCU时间,还容易在调试时把人绕晕。我的做法是先固定TFT横屏,然后旋转摄像头模块,让它输出的画面朝上和屏幕显示方向匹配,避免软件旋转。

3.5 DMA刷屏:别让CPU等像素

SPI刷一帧数据,ST7735S 128x160=20480个像素,RGB565就是40960字节,如果SPI是20MHz,理论传输时间约16.4ms。但如果你用while循环一个字节一个字节发,每个字节还要查询发送完成标志位,实际耗时可能是理论值的3倍以上。因此最好用DMA方式发送。

HC32L072的DMA配置不复杂,把SPI发送缓冲地址设为源地址,把要发送的数据放内存,然后触发DMA传输。DMA传输完成中断里再置一个标志,这样CPU可以在DMA搬运数据的同时去读取FIFO里的下一段数据。不过我这里提醒一句:DMA传输过程中,源数据内存不能变,所以要么分配一块缓冲区,要么用行缓冲分两次刷。我的做法是定义一个uint16_t的行缓冲,每次读一行像素,然后用DMA发送一行。

4. 摄像头初始化与FIFO读取:从寄存器配置到一帧数据落盘

4.1 OV7670关键寄存器配置

OV7670寄存器配置算是个体力活,但核心只要抓住几个方面:输出格式、分辨率、时钟分频、以及同步信号极性。下面是我在项目里实际用到的关键配置思路。

  • 分辨率:设置COM7寄存器,将输出分辨率改为QVGA 320x240。这里还要注意,OV7670的寄存器很多是银行分组式的,改分辨率时可能要同时调整HREF、VTS、HTS等时序寄存器,不能只改COM7。
  • 输出格式:设置RGB565格式。RGB565在OV7670里通常通过COM7和RGB444等寄存器组合配置。
  • 像素时钟分频:CLKRC寄存器可以控制PCLK频率。使用FIFO模块时,PCLK不需要和MCU严格同步,所以可以适当降低PCLK,减少FIFO写入压力。
  • 帧率:VSYNC需要作为帧同步信号,通常配置成60fps还是30fps取决于寄存器里的VTS_HI和VTS_LO。我们最后要一帧一帧读,所以30fps就够。

初始化的代码风格大致长这样:

void ov7670_init(void) { // 复位 ov7670_write_reg(REG_COM7, 0x80); // 软件复位 delay_ms(10); // 设置为QVGA RGB565 ov7670_write_reg(REG_COM7, 0x06); // QVGA, RGB模式 ov7670_write_reg(REG_COM15, 0xC0); // RGB565输出 // 后续还需要根据具体模组配置HSTART/HSTOP等寄存器 }

这里我不逐条贴完整的寄存器表,因为不同模块差异太大。但你可以在系统里把寄存器配置和屏的初始化序列一样,做成一张表驱动,方便随时增删。

4.2 AL422B FIFO的工作流程

AL422B这个FIFO值得一提。它的容量是384KB,写入端和读出端各自有独立的时钟和使能。摄像头把像素并行数据通过WCLK写入FIFO,MCU通过RCLK和RRST来读出数据。

在我们的模块上,FIFO通常已经和摄像头接好了:摄像头的D7..D0连到FIFO的DIN7..D0,摄像头的PCLK连到FIFO的WCLK,只要WRST拉低再拉高,FIFO写指针复位,然后摄像头就开始往FIFO里写。这里有个关键点:并不是只要上电摄像头就会不断往FIFO写,因为FIFO模块上通常有一个自动写使能机制,或者需要通过VSYNC来控制写使能。大多数模块默认是摄像头PCLK一有数据,FIFO就写,但如果你想只捕获一帧,就需要在VSYNC有效后再让摄像头开始写,然后等一帧写完后禁用写使能。

我画一下我实现的状态机思路:

  1. 等待VSYNC下降沿,代表新一帧开始。
  2. 拉低FIFO WRST,复位写指针。
  3. 拉高FIFO WRST,摄像头PCLK开始把本帧数据写入FIFO。
  4. 等待VSYNC下降沿再次到来,说明一帧已经写完,或者用定时器估算时间。
  5. 之后禁止FIFO继续写入(具体取决于模块,有的模块没有独立写使能,那就在读的时候停下PCLK,或者用WRST保持复位状态)。

需要注意的是,AL422B的读指针和写指针是独立的。读指针复位需要RRST先低后高。每次读取一帧前都要先RRST,然后才开始读,否则指针会停留在上一次读取结束的位置,画面就会错位。

4.3 MCU端读取一帧并送屏

由于MCU的SRAM可能不够缓存整帧,我采用“边读边刷”的方式:读取FIFO的一行像素,然后把这一行像素通过SPI DMA发送到TFT屏幕。

代码逻辑大致是:

void display_one_frame(void) { // 等待一帧写入FIFO完成 wait_vsync(); // 复位FIFO读指针 fifo_rrst_low(); delay_us(1); fifo_rrst_high(); // 在TFT上设置显示窗口 tft_set_window(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1); // 逐行读取并刷新 for (int y = 0; y < DISPLAY_HEIGHT; y++) { for (int x = 0; x < DISPLAY_WIDTH; x++) { uint16_t pixel = read_fifo_pixel(); row_buffer[x] = pixel; } tft_send_pixels(row_buffer, DISPLAY_WIDTH); } }

这里read_fifo_pixel需要精确控制FIFO的RCLK:先拉高,读取并行数据,再拉低,生成一次读时钟。如果你的MCU能做到8位并行读取,那一次可以拿到8位数据,再读一次拿到高8位,拼成一个16位像素。

要注意的是,OV7670输出RGB565时,FIFO里存的是两个字节,所以读取顺序是:第一个字节可能是高字节,第二个是低字节。具体顺序取决于OV7670的RGB565输出格式配置以及FIFO模块的接线。这里可以用软件灵活调整,输出到屏幕之前把两个字节交换就行。

4.4 摄像头时钟的注意事项

OV7670的XCLK输入需要外部时钟源,一般接MCU的定时器输出或晶振。XCLK典型值是12MHz到24MHz。我用HC32L072的定时器产生一个方波,通过TO引脚输出,接摄像头的XCLK。频率不太需要精确,但最好稳定在12MHz左右,因为OV7670内部的分频和PCLK都是基于XCLK的。如果XCLK波动过大,图像会出现横条纹。

另外,如果模块上已经有晶振,那你就不用额外提供XCLK。但我的模块没有,所以这一点要特别提醒。

5. 联调中的花屏、移位与闪屏:问题排查全过程

5.1 第一版上电,屏幕全白:先别改代码

我遇到过很多次,新板子上电,屏幕白得发亮。第一反应千万不要去翻代码,而是先量电源。TFT背光需要的电流很大,如果LDO选小了,背光一开电压就被拉垮。我那次就是背光供电引脚和逻辑供电引脚共用同一路3.3V,屏幕一开,3.3V掉到2.7V,MCU处于半复位状态,SPI通信自然失败。后来给背光单独供电,问题立刻消失。

所以我把这条放在第一位:TFT的VCC和背光驱动,尽量分开,或者至少保证电源余量足够。白屏排查顺序应该是电压、复位引脚电平、SPI波形、初始化时序,最后才是代码逻辑。

5.2 画面彩虹条纹:SPI极性不对

如果屏幕能显示内容,但出现类似彩虹一样的彩色条纹,或者整个画面像被涂抹过,那大概率是SPI Mode不匹配。ST7735S和ILI9341支持Mode 0和Mode 3,但如果你初始化用的是Mode 0,后续刷屏时不小心把SPI设置成了Mode 3,就会出现数据采样窗口错误,最终显示的颜色完全错乱。

还有一点,很多MCU的SPI外设支持在传输过程中动态修改CPOL/CPHA,但修改之后可能不会立刻生效,需要重新禁用SPI再使能。我记得用HC32L072时,如果只改寄存器而没有重新enable,SPI行为会很怪异。所以在初始化SPI时,就把模式固定下来,后面不要随便改。

5.3 颜色不对:R和B交换

最经典的一张调试截图是:画面里的红色变成蓝色,蓝色变成红色,整个图像像是用了反色滤镜。出现这种现象,原因就是RGB565的字节序反了。

排查方法很简单,先在屏幕上画一个纯红色块,如果TFT显示出来是蓝色,说明TFT端或MCU端的颜色打包方式有误。这里不是摄像头的问题,因为纯色块是直接写入屏幕的,绕过摄像头。修好TFT颜色之后,再接入摄像头,如果颜色又反了,那就是摄像头输出字节序不对。两个环节最好分开验证。

5.4 图像上下颠倒或者左右镜像

这个多半是摄像头安装方向或者TFT扫描方向导致的。你可以改TFT的坐标映射方向,也可以调整OV7670寄存器中的镜像和翻转配置,还可以把摄像头模块旋转180度。我个人建议物理调整优先,因为软件翻转会额外增加CPU开销,在这个Demo里不划算。

5.5 图像错位、出现斜切条纹:FIFO读指针没有复位

如果图像像是被剪切成好几段,每一段之间有明显错位,最常见的原因是读取前没有正确复位FIFO读指针。FIFO的读指针如果不复位,上一帧读到一半的位置会继续被读走,下一帧的数据就从错误位置开始。所以每次读取一帧前,RRST都要执行一次完整的低-高脉冲,而且低电平持续时间要满足AL422B手册要求,我用的是至少400ns。

另外,如果在读取过程中没有正确控制OE(输出使能),数据总线上会同时出现多个数据源竞争,也会导致错位。OE通常拉低即可,只有在需要释放总线时才拉高。

5.6 屏幕闪烁和撕裂:帧率与背光的博弈

屏幕闪烁有两个常见来源。一是刷新帧率过低,比如一帧刷新耗时80ms,人眼已经能明显看到刷新过程,这种属于性能上限,只能通过减小分辨率或提升SPI速率来解决;二是背光PWM频率太低,比如用几百Hz的PWM调光,人眼能感知到频闪。区分方法很简单:把背光亮度调到最大,如果还闪,那就是刷新帧率问题;如果最大亮度不闪、半亮时闪,那基本是背光PWM问题。

撕裂感则是因为屏幕在刷新过程中,FIFO还没完全读完一帧,下一帧又开始了,导致同一画面里上半部分是旧数据、下半部分是新数据。解决思路是“等一帧写完后马上读”,并且读取过程中不再响应新的VSYNC,或者在硬件上把FIFO写使能锁住,直到整帧读完再释放。我在状态机里加了一个busy标志,读帧期间忽略VSYNC中断,撕裂问题就消失了。

6. 帧率瓶颈与优化思路:这个Demo还能怎么改

6.1 量化当前性能:一帧到底要多久

我用的TFT是128x160 ST7735S,一帧RGB565数据量为1281602=40960字节。SPI时钟跑到20MHz,理论上传输需要约16.4ms。但实际操作中,每一行都需要设置窗口地址?这里要注意,如果连续刷整屏,不需要每行都设置窗口,只需要在一开始设置一次完整窗口,然后连续发送所有像素数据。否则每行都发CASET、RASET,开销会占掉30%以上。

按照我的实现,读取一行像素需要128次FIFO读操作,每次读两个字节,需要多次GPIO翻转,这部分很耗时。实测下来整帧显示时间大概在50ms左右,即约20fps。但这个数字还不够理想,因为MCU在等待SPI DMA完成时没有做其他事,浪费了带宽。

6.2 优化一:DMA双缓冲,让SPI和FIFO读取并行

默认代码是:读一行像素,放进行缓冲,DMA发送这一行,CPU等待DMA完成,再读下一行。这样SPI发送时CPU是空闲的,而FIFO读取时SPI是空闲的,两者串行。

改进方式是使用两个行缓冲:CPU往bufferA里读像素,同时SPI DMA正在发送bufferB。等两者都完成后交换缓冲。这样SPI和FIFO读取能部分重叠,整体帧率能提升10%~20%。不过这个优化需要DMA中断和主循环之间的配合,要小心缓冲区覆盖问题。

6.3 优化二:降低分辨率,从QVGA到QQVGA

如果显示目标不需要320x240全分辨率,可以把OV7670输出改为160x120(QQVGA),TFT也开一个160x120的窗口,只显示中间部分。那数据量降到原来的四分之一,即使SPI时钟不变,帧率也能翻倍。这个在“测试模式”下非常实用,先看整体画面,再切到高分辨率细看。

6.4 优化三:局部刷新

TFT屏测试工装上,很多时候画面变化范围并不大,比如产线上只关心摄像头画面中心的某个区域。这时候可以只把窗口设置在感兴趣的区域,只刷新那一小块。ILI9341的窗口刷新指令天然支持这种操作,ST7735S也支持。当然,这只适用于特定场景,如果要求全屏视频级预览,这个优化帮不上什么忙。

6.5 后续还能扩展什么

这个Camera demo project for testing TFT preview已经打通了“采集-缓存-显示”的完整链路,后续想加功能就方便了:比如加一个按键切换颜色格式,在RGB565和灰度之间切换,用来看图像处理算法;或者加一个定时截屏,把当前帧写入SD卡;如果想做更高帧率的预览,可以换用带DVP接口的MCU,或者改用并口TFT屏。

就我个人经验来说,这类Demo最重要的不是跑得多快,而是保留足够的调试接口。我在代码里留了几个全局变量,用来显示当前帧时间、FIFO读次数、DMA发送次数,这样后面优化性能时能直接量化效果,不用靠猜。

最后再分享一个小技巧:如果你在调试过程中觉得屏幕上总有若有若无的横纹,试着把摄像头的XCLK和TFT的SPI时钟错开,比如XCLK用12MHz,SPI用18MHz,不要让它们成整数倍关系。两个时钟之间如果产生差频干扰,会在图像上形成周期性条纹,错开频率往往立竿见影。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询