使用BAM调制的CPLD上的LED面板的DIY控制器

前段时间,他参加了关于矩阵LED手表的DIY项目的讨论。
令我惊讶的是,步长为5毫米的古老单色8x8 LED矩阵被用作显示设备。 此外,还为它们繁育了复杂的印刷电路板,并做出了柔和的动态指示。 而这是一个现成的全彩64x32 LED面板(间距为3 mm)很早就以10到20美元的价格上市了。 这样的面板的总体种类非常大,像素间距为2至10 mm,几乎任何尺寸。

同时,在DIY设计中使用这种面板非常困难-现成的控制器要花很多钱,而且没有普通的API。 要在DIY中常用的微控制器上快速扫描面板是非常困难的。 此外,必须高精度地保持时间间隔-否则会出现明显的亮度不均。

Adafruit有很好的解决方案,但它们都非常昂贵且复杂。

经过一番思考,这个想法浮出水面-为什么不制造一种非常便宜的电路板,该电路板将成为像arduino这样的普通便士板和LED面板之间的桥梁? 经过几个月的大惊小怪,有些事情诞生了。

本文介绍了控制器的第二个改进版本。

挑战赛


作为一项基本任务,我希望能够控制总尺寸至少为64x64的面板,同时能够至少在Highcolor(RGB565)下工作,同时保持可接受的屏幕刷新率(至少50Hz)。 在控制器的第一个版本中,基本任务已被完全实现,但是出现了通过另一种很有前途的方法来执行任务的想法,第二个版本由此诞生。

典型LED面板设计的基本说明


输入HUB75界面:


在每个颜色输入处,都有一串HC595类型的寄存器(但用于LED的特殊16通道版本)。 有太多的寄存器足以容纳面板的宽度。 粉碎,并行引导和输出许可对于所有寄存器都是通用的。 输入ABCDE-这是系列的选择-转至常规解码器。

工作原理:

  • 将数据设置为RGB输入,单击CLK按钮。 重复直到加载整个行
  • 关闭输出OE = 1(这样就不会产生干扰)
  • 给解码器加载的行号
  • 单击并行加载LAT-将行数据传输到输出寄存器
    使能输出OE = 0
  • 对下一行重复

这是经典的动态指示。 显然,使用这种方法在一个这样的周期中,我们只能打开/关闭每个特定的LED。

为了获得经典PWM的亮度等级,必须将此类循环重复N-1次,其中N是亮度等级的数量(RGB888为256)。 而且鉴于它仍然在闪烁-所有这些必须非常非常快地完成。

有一种解决方法-位角调制(BAM)。 在这种情况下,每个周期的辉光时间与显示位的权重成正比。 也就是说,对于RGB888,您只需要8个显示周期。 这里稍微详细一点

控制器的第一个版本使用经典的PWM,它对扫描周期数施加了严格的限制。 在第二个版本中,实施了BAM,从而极大地提高了速度。

实作


很明显,传统的微控制器仅拉小面板-大面板根本没有足够的速度。 因此,CPLD或FPGA在这里是必不可少的-在物理上不可能在低成本微控制器上产生数十MB / s。

作为存储器,非常有趣的FIFO存储器Averlogic AL422B在IXBT论坛上向我推荐了该存储器,该存储器具有大约400 KB的存储器,并且可以在高达50MHz的频率下运行。

考虑到我的主要要求是最大程度地降低组件成本,以便自制制造商可以使用制成的围巾,因此选择了带有64个宏单元的Altera EPM3064-CPLD。 同时,如此少量的宏单元不允许制作可动态配置的板-必须将配置直接编译到CPLD中。

→结果电路就在这里

详细资料:

  • CPLD EPM3064ATC44-10-阿里的价格大约是每打$ 13-15
  • FIFO RAM AL422B-Ali的价格约为每打$ 15
  • 50MHz晶体振荡器。 该板可用于DIP14 / DIP8 / 7050机箱的安装。 阿里的价格大约是每打6-7美元
  • 采用SOT223封装的3.3V稳压器。 芯片和浸入式价格-每个40r
  • IDC-10MS连接器。 切片和浸洗的价格-3 p /件
  • IDC-16MS连接器。 切片和浸洗的价格-8转/片
  • IDC-14MS连接器。 切片和浸洗的价格-7 r /件
  • 电容器1微法拉0805-8件约1 r /件
  • 电容器0.1uF 0805-约1 r /件
  • 电阻10k 0805-一分钱

得到的详细总数为1.5 + 1.5 + 0.7 = $ 3.7和40 + 3 + 8 + 7 + 8 * 1 +1 = 67 p。 总计在5美元以内-一分钱。

→原始的木板图像在这里

→准备的Gerber 文件可订购

评估板已准备好用于第一个没有RE控制的版本。 要将其与第二个版本一起使用,必须在AL422B的端子23和24之间切下跳线,并将电线从EPM3064的端子28(带到端子块)连接到AL422B的端子24。

焊接电路板时,请勿忘记在电路板背面焊接电源跳线。





计算方式


所需参数的计算非常复杂。

事实是,在控制器中并行执行两个过程-加载下一行的数据/指示已经加载的行。

进程同时开始,但在不同时间结束,因此更快的进程会等待更长的进程的完成。

→制作了Excel数位板进行计算

源数据:

  • CRYSTAL_FRQ(MHz)-发生器频率(50 MHz)
  • PIXEL_COUNT-下载栏中的像素数。 在切换部分中有更多详细信息。
  • RGB_INPUTS-在所使用面板的HUB75E界面中使用的RGB输入数量。 1或2
  • BYTES_PER_PIXEL-每个像素字节。 在我们的情况下,始终为3-RGB888
  • SCAN_LINES-使用的面板中的扫描线数。 8/16/32

所选参数:

  • PRE_DELAY-从LAT信号到OE开启的延迟,以刻度为单位
  • 预分频器-主计数器的预分频器。 也就是说,如果价格表为8,当前位的权重为4,则OE将打开8 * 4 = 32个周期
  • POST_DELAY-从关闭OE到下一个LAT信号的最小延迟,以刻度为单位

例如,我们有一个32x32面板,其中包含8条扫描线和2个RGB输入。 这样的面板有两个HUB75E连接器,也就是说,实际上是两个32x16面板。 我们将这些面板串联连接,也就是说,从逻辑上讲,该面板看起来像64x16。

PRE_DELAY和POST_DELAY是输出使能(OE)之前和之后的消隐间隔,以便多路复用器可以切换输出和打开/关闭键。 没有它们,就会存在从燃烧像素到相邻行的“技巧”。 通过实验为特定面板选择值。 通常15个小节就足够了(按小节设置)。

这就提出了选择预分频器的问题-如何选择它。

低的预分频值会缩短帧显示时间,但会降低整体亮度。 预分频器的高值会增加帧的显示时间,即枚举时会闪烁屏幕。

让我们尝试PRESCALER = 1

我们得到:

OE_EFFICIENCY-8.3%,即面板将仅工作于最大可能亮度的8.3%
FRAMES_PER_SECOND-2034 fps-但图片的刷新率非常高-超过2000 fps。

亮度损失已经非常大。

让我们尝试PRESCALER = 16

我们得到:

OE_EFFICIENCY-72.9%,即面板将以可能的最大亮度的72.9%工作
FRAMES_PER_SECOND-1117-图片的刷新率非常好-超过1000 fps。
好吧,这很正常-效率超过50%是非常正常的,并且帧速率非常好。

一般的经验法则是PRESCALER大约比产品PIXEL_COUNT * RGB_INPUTS小8倍

好吧,继续计数和检查。

切换LED面板


所有面板均串联连接。 连接图:首先从右到左,然后从下到上。 也就是说,首先我们将水平线串联起来,然后将底行的输出从底端连接到第二行的入口,依此类推。 到第一行。

控制器紧贴右下面板。

有具有两个输入和两个输出连接器的面板。 这样的面板本质上仅是两个面板垂直的机械组装。 转换为两个独立的面板。

组装后,我们需要计算以像素为单位的链的总长度-为此,我们要查看-链中有多少个总面板,然后将此数字乘以面板的宽度(以像素为单位)。 然后,需要在CPLD配置期间将此数字驱动到PIXEL_COUNT值中,并将其驱动到时序计算器中。

FPGA固件


所有必需的文件都在github上 。 您需要直接通过文件夹下载。

注册后,您必须从Altera网站下载并安装Quartus II 13.0sp1 。 您需要下载完全与此版本-较新的版本不再支持MAX3000系列。 无需破坏它-Web版(免费)版本就足够了。 下载时,请确保选中MAX3000和Programmer支持框。 以防万一,我警告您-包裹很大,大约有两场演出。 您还将需要Altera USB Blaster-Ali的正常价格约为3美元。

打开al422_bam.qpf项目。 在左侧,打开文件选项卡,然后打开文件al422_bam.v-这是主项目文件。 在其中您需要配置参数:

一个面板上有多少个RGB输入-在具有HUB75输入的面板上可以有1个或2个RGB输入。 为了准确找出以这种方式可以输入的数量-我们垂直获取面板中的像素数。 将其除以扫描线的数量(例如,在面板名称中表示为8S)。 除以输入连接器的数量(1或2)。 例如-我有一个32x32面板,8S扫描和两个输入连接器-32/8/2 = 2-这意味着两个RGB输入。

`define RGB_outs 2 

面板上有多少条扫描线-由于支持HUB75E标准,因此最高可以达到32倍。 扫描行数通常在面板名称中分别为8S / 16S / 32S。

仅一行必须取消注释:

 `define SCAN_x8 1 //`define SCAN_x16 1 //`define SCAN_x32 1 

链中水平像素的总数。 在整个面板链中都考虑像素-请参见“切换LED面板”部分

 `define PIXEL_COUNT 64 

输出信号的相位。 最典型的配置是这样的:OE处于低电平活动状态(已删除注释),CLK正在前端运行(注释已打开),LAT处于高电平处于活动状态(注释已打开)。 各种奇怪的选择都是可能的。 通过实验或通过移除电路并搜索使用过的芯片的数据表,找出您只有哪一个。

 //`define LED_LAT_ACTIVE_LOW 1 `define LED_OE_ACTIVE_LOW 1 //`define LED_CLK_ON_FALL 1 

OE信号相对于主计数器的LAT和预分频器的前后延迟。 见上文。

 `define OE_PRESCALER 16 `define OE_PREDELAY 31 `define OE_POSTDELAY 31 

全部,按ctrl-L-项目已编译。 如果您未在任何地方拧紧它,将会有几个警告,但应该没有错误。 接下来,我们将焊接好的板子钩在USB Blaster上,并给该板子通电。 在Quartus中,转到工具-程序员。 在“硬件设置”中选择“ USB-blaster”,然后单击“启动”。 就是这样,CPLD已编程。

单片机部分


通常,输出到控制器的数据非常简单-我们重置写地址,然后顺序发出数据字节,并用WCLK信号对其进行抚摸。 看来,即使是平庸的arduinka也足以应付工作。 但是有两个问题:

a)需要很多内存。 即使是在RGB888模式下的小型32x32面板,也需要3kBytes的内存用于屏幕缓冲区。 基于Arduino的普通Atmega328仅包含2 KB的RAM。 当然,您可以使用基于Atmega2560的Mega板,其中包含多达8 kB的RAM,但是对于普通尺寸的面板来说,这还不够用-RGB565模式下的128x64面板需要16kB的内存。

b)在使用AL422B的过程中,出现了任何地方都未记录的故障-以小于2MB / s的速度写入数据时,地址计数器无法正常工作,并且“不在此处”写入数据。 也许这是我党的一个小故障。 也许不是。 但是必须避免这种故障。 鉴于AVR8的工作频率为16 MHz,几乎不可能以所需的速度从中获取数据。

提议的解决方案是基于32位STM32F103C8T6控制器的廉价围巾。 一条围巾的价格大约是阿里每条2.5美元,买一打时大约是1.7美元,这比Arduino Nano还要便宜。 同时,我们获得了功能强大的32位微控制器,工作频率为72 MHz,具有20 kB的RAM和64 kB的闪存(与Nano上的2kB / 8kB Atmega328相比)。

同时,此类板卡已在Arduino环境中成功编程。 关于这一点, 时钟上有一篇不错的文章,所以我不会重复。 通常,按照文章中所述进行所有操作。

在arduino环境中,选择通用STM32F103C,变体STM32F103C8板。 数据通过DMA,因此您可以使用任何优化选项。

切换发生如下:

牢牢地钉在图书馆里:
A0..A7→DI0..DI7 AL422B
B0→WCLK AL422B
B1→WRST AL422B

在草图中分配给控制器:
B10→我们AL422B

普通线:
G→地

好吧,不要忘记从面板向相应的控制器引脚提供5V / GND电源。

电路中取出控制器上连接器的引脚。



软件部分


由于任务是使所有内容尽可能简单和负担得起,因此所有软件都是针对Arduino环境制作的,并被设计为LED_PANEL库。

LED-PANEL库积极使用Adafruit GFX库,因此需要安装它。

我强烈建议不要将LED_PANEL库放在库目录中,而是将其保留在草图文件夹中。 事实是,有很多铁绑定的参数,如果要将工作转移到更“胖”的微控制器上,则必须在代码本身中进行很多更改。

初始化大致采用以下形式:

 #include "LED_PANEL.h" #define width 32 #define height 32 #define bpp 3 #define scan_lines 8 #define RGB_inputs 2 #define we_out_pin PB10 LED_PANEL led_panel = LED_PANEL(width, height, bpp, scan_lines, RGB_inputs, we_out_pin); 

也就是说,我们创建LED_PANEL类的实例,并为其指定参数:

width-面板的总宽度,以像素为单位(总计)
height-面板的总高度,以像素为单位(总计)
bpp-每个像素字节,对于RGB888为3。 BAM版本仅适用于RGB888
scan_lines-扫描线数为8/16/32。 它必须对应于闪烁到控制器中的模式。
RGB_inputs-HUB75连接器中RGB输入的数量为1/2。 它必须对应于闪烁到控制器中的模式。
we_out_pin-WE输出挂钩的引脚

请注意,在初始化期间,仅指定了WE引脚。 由于所有其他引脚都与使用的定时器和DMA通道绑定在一起,因此所有其他引脚都严格地注册在代码中,并且更改它们将对代码进行重大更改。

在设置部分启动和清除屏幕:

  led_panel.begin(); led_panel.clear(); 

开始将必要的引脚初始化为输出,连接计时器和DMA
清除清除缓冲区

对于绘图,您可以使用Adafruit GFX库的所有标准过程-从最简单的drawPixel到文本输出。 要输出绘制到缓冲区的程序,请使用:

 led_panel.show(); 

show以这种形式启动通过DMA到控制器的数据传输并立即返回控制。 在led_pa​​nel.OutIsFree()函数的帮助下确定传输是否已结束-如果说为true,则传输已结束。 有一个功能-如果您在传输尚未完成时致电show-它将被忽略。

 led_panel.show(false); 

与show()类似,但如果调用show(false),并且传输尚未完成,则该过程将等待传输完成,然后开始新的传输并返回控件:

 led_panel.show(true); 

类似于show(false),但如果调用show(true),则在新的传输开始之后,该过程在传输完成之前不会返回控制权。

一般来说,仅此而已。



关于软件的一些注意事项:

a)当使用ExpandColor函数从RGB565(库使用)重新计算颜色时,引入了伽玛校正。 在所有其他情况下,都使用线性传递函数,即亮度与该值成正比。
b)软件允许您将多个LED控制器连接到一个微控制器板上。 为此,将数据总线,RST和CLK线并行发送到控制器。 通过WE线选择所需的控制器。 在软件中,您需要为每个控制器创建一个单独的LED_PANEL类实例,并且每个实例在初始化期间必须具有不同的WE行(最后一个参数)。

要做


-处理相邻行中的花朵“拾取”。 面板本身的接线看上去很差(按键杂乱),但是您需要检查一下。 刚到一个新面板-我会检查;
-制作新版的电路板-带有已经离婚的RE并增加5V的输出电平转换器;
-创建META_LED_PANEL类,该类将允许将多个LED_PANEL组合到一个虚拟屏幕中-这将使创建具有多个控制器的超大屏幕成为可能;
-将来,请使用功能更强大的CPLD系列产品,例如CycloneIV。 这将在保持低成本的同时极大地扩展可能性(对于中国人而言,EP4CE6E22的成本约为5美元,而宏单元的数量增加了100倍,内部存储器约为32 kB)。 但是有一天我会做的。 如果我想。 由于这种发展需要太多时间。

Source: https://habr.com/ru/post/zh-CN409743/


All Articles