前段时间,他参加了关于矩阵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_panel.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)。 但是有一天我会做的。 如果我想。 由于这种发展需要太多时间。