本方案是一个基于 FPGA 的二进制时钟,使用 GPS 作为时间参考。
历史上准确测量时间提出了许多挑战。只有约翰哈里森设计了一个可靠的时钟,它可以在格林威治子午线保持参考时间,从而能够在 1700 年代进行准确的导航以及绘制尚未开发的海洋和陆地的图表。
今天,我们生活在日益互联的世界中,准确的时间参考同样重要。如果没有一个共同的时间参考,当我们从一个信号塔传递到另一个信号塔时,信号塔就无法轻松同步代码和切换呼叫。同样,没有共同时间参考的时间戳业务和银行交易也可能具有挑战性,并成为事件顺序的仲裁噩梦。
当然,可用的最准确的时钟是原子钟,但遗憾的是,它们也是最昂贵的,这限制了机构使用它们的能力。
然而,有一个时间参考精确到 +/-10 ns,可以从空中免费提取,这就是全球导航卫星系统提供的时间参考。当然,其中最著名的是全球定位系统 (GPS),尽管有几个,例如 GLONASS 和 Galileo。
所有这些卫星都包含原子钟,这使我们能够实现跨系统的高度准确的时间参考。
在这个项目中,我们将使用 GPS 接收器 Pmod 接收 GPS 信号并对其进行处理,以便我们可以在二进制时钟上显示时间。
为此,我们将使用 Vivado 和 SDK,这将是我们使用 SDK 的最后一个项目,因为 Vitis 可用。
<strong>Vivado设计</strong>
要开始设计,我们需要做的第一件事是安装 Digilent 库,使我们能够配置 PmodGPS/
该库支持在 Vivado 和 SDK 的硬件和软件开发中使用 Pmod。
为此,请在我们的 Vivado 项目中选择、项目选项并选择 IP 并导航到新的 IP 存储库。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241392-1.p…; alt=""></center>
我们还需要一些东西来驱动 NeoPixel 显示器,同样对于之前的项目,我在这里将一个 neopixel IP 模块推送到我的 github
然后我们就可以创建一个 Vivado 项目,该项目将利用这些 IP 模块与 PmodGPS 通信。
在新的 Vivado 项目中,我们需要以下 IP
<li>Zynq PS - 为最小化配置</li>
<li>PmodGPS - 将在软件控制下与 PmodGPS 通信</li>
<li>AXI BRAM 控制器 - 使 Zynq PS 能够在 PL 中读取和写入 BRAM</li>
<li>BRAM - 双端口 BRAM 包含 Neo 像素值</li>
<li>NeoPixel IP - 驱动 Neo Pixel 驱动信号</li>
<li>处理器重置块 - 为系统提供重置</li>
<li>AXI 互连 - 使多个 AXI 从设备能够连接到单个 PS 主设备</li>
需要配置 PS 才能提供
<li>50 MHz 时的结构时钟</li>
<li>20 MHz 的结构时钟 - 用于为 Neo Pixel IP 提供时钟</li>
<li>GP Master AXI 接口</li>
<li>已启用结构中断</li>
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241393-2.p…; alt=""></center>
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241394-3.p…; alt=""></center>
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241395-4.p…; alt=""></center>
这应该会产生如下所示的框图
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241396-5.p…; alt=""></center>
在生成和导出位流之前,我们还需要设置引脚的 IO 位置。
我将在 PmodGPS 的 Minized 上使用 Pmod2,在 Neo Pixel 驱动器上使用 Pmod1 我们在 XDC 文件中执行此操作,如下所示。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241397-6.p…; alt=""></center>
这样我们就可以实现设计并将硬件设计导出到 SDK 以生成所需的软件。
<strong>软件设计</strong>
在 SDK 中,我们需要根据刚刚从 Vivado 导出的硬件设计创建一个新的应用程序和 BSP。
一旦在 BSP 中创建了它,我们应该会在 BSP MSS 文件中看到 Pmod 驱动程序。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241398-7.p…; alt=""></center>
对于更改,我们的软件应用程序将是中断驱动的。
我们的软件解决方案将遵循的架构是
<li>配置和初始化 PmodGPS</li>
<li>配置和初始化 BRAM 控制器</li>
<li>配置中断控制器并启用来自 PmodGPS UART 的中断。</li>
<li>等待 PmodGPS 锁定信号</li>
<li>从 PmodGPS 读取位置和时间数据</li>
<li>将时间转换为二进制元素进行显示</li>
<li>更新 Neo Pixel 显示</li>
为了使用 PmodGPS 和 AXI BRAM 控制器,我们可以使用 PmodGPS.h 和 xbram.h 中提供的 API
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241399-8.p…; alt=""></center>
虽然可以使用 xscugic.h 提供的 API 配置中断控制器
int SetupInterruptSystem(PmodGPS *InstancePtr, u32 interruptDeviceID, u32 interruptID) {
int Result;
u16 Options;
INTC *IntcInstancePtr = &intc;
XScuGic_Config *IntcConfig;
IntcConfig = XScuGic_LookupConfig(interruptDeviceID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Result != XST_SUCCESS) {
return XST_FAILURE;
}
XScuGic_SetPriorityTriggerType(IntcInstancePtr, interruptID, 0xA0, 0x3);
Result = XScuGic_Connect(IntcInstancePtr, interruptID,
(Xil_ExceptionHandler) XUartNs550_InterruptHandler,
&InstancePtr->GPSUart);
if (Result != XST_SUCCESS) {
return Result;
}
XScuGic_Enable(IntcInstancePtr, interruptID);
XUartNs550_SetHandler(&InstancePtr->GPSUart, (void*) GPS_intHandler,
InstancePtr);
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler) INTC_HANDLER, IntcInstancePtr);
Xil_ExceptionEnable() ;
Options = XUN_OPTION_DATA_INTR | XUN_OPTION_FIFOS_ENABLE;
XUartNs550_SetOptions(&InstancePtr->GPSUart, Options);
return XST_SUCCESS;
}
我想做的第一件事是确保 PmodGPS 能够锁定信号并为我提供准确的位置。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241400-9.p…; alt=""></center>
当此代码在 Pmod2 连接到 PmodGPS 的 Minized 上执行时,我们会在终端上看到以下输出,为我提供了一个位置。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241401-10…; alt=""></center>
为了检查这是正确的位置,将它输入到谷歌地图中可以以合理的精度提供我办公室的位置。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241402-11…; alt=""></center>
由于能够锁定 GPS 信号,因此更新了代码以提供时间。这个时间被称为协调世界时或简称 UTC,UTC 参考格林威治标准时间,目前也恰好与英国的时间相同。
时间作为浮点数从 PmodGPS 输出,如下面的终端输出所示。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241403-12…; alt=""></center>
为了能够创建一个二进制时钟,我们需要将其分解为以下内容
<li>小时几十</li>
<li>小时单位</li>
<li>分 十</li>
<li>分钟单位</li>
<li>秒 十</li>
<li>秒单位</li>
这将使我们能够使用 Neo Pixel Array 绘制时间。
二进制时钟显示时间如下
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241404-13…; alt=""></center>
在 Neo Pixel 上,我将在阵列中间使用 6 x 4 LED 阵列。
但首先我们需要将 UTC 时间转换为所需的格式,我们可以使用以下方法将时间(例如 153400)拆分为正确的小时、分钟和秒分组。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241405-14…; alt=""></center>
然后我们可以根据二进制时间显示的需要将每个元素分成十位和单位。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241406-15…; alt=""></center>
一旦我们分离了数字,我们就需要将值转换为二进制值,为此我创建了一个简单的子例程
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241407-16…; alt=""></center>
这个函数返回一个代表二进制数的四位向量,对于这个例子,我们不需要超过 4 位。
由于 Neo Pixel 阵列被视为一个长 64 Neo Pixel 元素,因此对于每个计数位置,我们只需要更改 LED 偏移位置。
根据该位是否已设置,LED 的颜色是否会发生变化,设置的位为绿色,否则为蓝色。
我使用下面的代码来确定设置 LED 的值,因为二进制转换函数返回一个指针。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241408-17…; alt=""></center>
当我把所有这些放在一起时,一旦 PmodGPS 锁定信号,二进制时钟就会按预期运行。
<strong>确认</strong>
对于许多人来说,读取二进制时钟可能与传统时钟不同。因此,通过终端查看 Neo Pixel 显示和 UTC 时间输出,我们可以验证显示是否正确。
<center><img src="http://xilinx.eetrend.com/files/2022-01/wen_zhang_/100557403-241409-18…; alt=""></center>
解码后的时间看起来是正确的。
<strong>结论</strong>
该项目演示了我们如何轻松快速地将 GPS 用于导航以外的系统,并创建一个有趣的示例,该示例可用作显示器等。
<p><a href="https://github.com/ATaylorCEngFIET/Hackster">您可以在此处找到与此项目相关的文件</a></p>
<p>点击查看:<a href="https://www.hackster.io/adam-taylor/fpga-based-binary-clock-4403de">原文链…;
本文转载自:<span id="profileBt"><a href="https://www.cirmall.com/articles/36390/">电路城</a></span>