我正在做一个(看似)简单的项目作为学习练习:通过 iCEstick(Lattice iCE40HX-1k FPGA)将基于 SSD1331 的 96x64 PMOD 显示器连接到 PC,这样我就可以通过 USB 发送一些 RGB565 编码的图像以显示在说显示。
问题是,SSD1331 显示器需要一个初始化程序才能进入“清除黑屏”状态。大约有 20 条命令要转移到显示控制器中;长度在 1 到 5 个字节之间变化,总共 44 个字节。
到目前为止,我pwr_on
用 FSM 编写了 Verilog 模块,用于以正确的顺序将命令转换为 PMOD;命令的值定义为localparam
。一切正常,但总有一个但是。我认为所有这些命令常量都存储在 LUT 中(我没有推断任何 RAM 块,所以它们还会去哪里,对吧?),并且 iCE40HX1k 中只有 1,280 个 LUT 可用,其中大约有 100 个 LUT 用于 init 过程大约 150 毫秒,并且在下一次重置之前永远不需要,这似乎是一种浪费。
现在,我可以看到以下方法来处理这个问题:
- 根本不要在 FPGA 中实现初始化序列;相反,通过 USB 发送这些命令。
简单但没那么有趣;毕竟,我正在尝试学习 FPGA 编程,而不是 Linux 驱动程序。 - 充分利用
SB_WARMBOOT
和多配置。
iCE40HX 最多可在 EEPROM 中存储 4 种配置;SB_WARMBOOT
原语基本上可以让您随意在它们之间跳转。我可以在配置 0 中编写 init 过程,一旦完成,就跳转到配置 1 并支持 USB,从而获得一个干净的状态。但是,在配置之间的转换过程中,我需要保持至少 3 个显示 PMOD 引脚(pmod_enable、vcc_enable 和 pmod_rstn)为高电平。我找不到任何方法来做到这一点;如果有人知道,请向我发送正确的方向。 - 将命令数据存储在 BRAM 中。
HX1K 有 16 个 RAM4K 块(每个存储 4096 位),因此即使其中一个也应该为 44 字节的命令数据提供足够的空间,而无需花费宝贵的 LUT。
选项 3 看起来很简单。但是,由于我对我的资源的贪婪,一旦完成初始化,我希望该 RAM4K 块可用于其他任务。现在,在我看来,Verilog 合成器(我正在使用 yosys)完全没有意识到当pwr_on
模块将done
导线拉高时,它所连接的 BRAM 单元可以在推断其他逻辑时被重用。
想到的一种解决方案是将该 BRAM 块分配到一个单独的模块中,用初始化所需的数据填充它并将其连接到pwr_on
模块,然后根据需要将其重新连接到其他模块。然而,由于几个原因,这种方法看起来很难看,因此问题是:我错过了一个技巧吗?我怎么能在一个模块的SB_RAM512x8
配置中使用一个 BRAM 块,然后将它重SB_RAM256x16
用于另一个模块?