请选择 进入手机版 | 继续访问电脑版
[X]关闭

[米联客-XILINX-H3_CZ08_7100] LINUX驱动篇连载-02 XADC

文档创建者:LINUX课程
浏览次数:279
最后更新:2024-09-09
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 2_LINUX应用开发
本帖最后由 LINUX课程 于 2024-9-11 11:04 编辑

软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用XILINX Z7/ZU系列FPGA
登录“米联客”FPGA社区-www.uisrc.com视频课程、答疑解惑!

1 概述
对于芯片内部温度,电压的监控,以及通过配置选通访问外部模拟接口,可以通过PS和PL的10bit片上ADC监控模块来处理。
实验目的:
  • 了解SYSMON的硬件结构。
  • 了解SYSMON的寄存器和工作模式。
  • 了解PS如何访问SYSMON的方法。
  • 掌握Linux端查询芯片各个状态的方法。
2 系统框图
图片9.jpg
3 介绍
3.1 SYSMON概述
ZYNQ MPSOC内置2个10bit 精度的ADC监控模块,分别是PL SYSMON和PS SYSMON.
PS SYSMON具1个1MHZ采样率的10BIT 精度ADC,有多个监控内部电压的节点和2个片上温度传感器,测量的电压范围为0~3V或者0~6V范围。PS PS SYSMON的温度传感器一个靠近RPU,另外一个在FPD(全功率域)靠近APU。PS SYSMON只能使用内部基准。
PL SYSMON具1个200KHZ采样率的10BIT 精度ADC,除了具有多个标准的电压监控节点外,还有4个用户可以定义的监控节点,此外可以监控一些在PS中的节点电压。PL SYSMON的电压测量范围为0~3V或者0~6V。PL SYSMON还具有一个片温度二极管。PL SYSMON内的ADC可以通过选通到外部PL IO用于测量外部电压。这些外部接口支持0~1V的无极性电压测量以及±0.5V的有极性电压测试。PL SYSMON的参考电压也是可以选择内部参考电压或者外部参考电压。
image.jpg
3.1.1: SYSMON的电源
SYSMON的参考电压可以使用外部基准或者使用内部的1.25V基准。如果要获得高精度的采样可以使用外部基准。
为了减少高频影响,可以选择在VCCAUX和XADC的VCCADC之间串接一个磁珠,以及在GND-XADC数字GND之间串接一个磁珠。
image.jpg image.jpg
3.1.2:温度传感器
ZYNQ MPSOC 是属于ultrascale+系列,内部的是SYSMONE4。
当使用外部基准,温度传感器使用以下公式计算温度(仅PL的SYSMONE支持)
image.jpg
当使用内部基准,温度传感器使用以下公式计算温度
image.jpg
3.1.3:电源传感器
对于SYSMON 监控 VCCINT、VCCAUX、VCCBRAM、VCC_PSINTLP、VCC_PSINTFP 和 VCC_PSAUX的电压满量程是3FFH,因此对于VCCINT = 1V,输出值为:
1/3 x 1024 = 341 = 155h
        SYSMON也可以通过 VUSER[3:0]设置,检测VCCO , VCCO _ TOP , VCCO _ BOT , VCCINT , 或者VCCAUX电压。
image.jpg
        当SYSMON通过VUSER[3:0]设置检测VCCO,该VCCO是HR BANK或者HD BANK,那么满量程3FFH对应于6V,比如VCCO=3.3V
1/6x1024 = 563 = 233H
image.jpg
3.1.4:XADC外部采集接口
4-1:共模输入
ADC 的模拟输入使用差分采样方案来降低共模噪声信号的影响。下图显示了差分采样方案的优势,电源的噪声和地上的噪声相互抵消,从而提高采样精度。当采集外部模拟输入信号的时候,只需要把外部模拟信号接入到VP和VN.
image.jpg
4-2:单端输入解法
外部模拟信号如果是单端信号,可以通过电阻网络实现差分采样方式,如下图所示。R1 、R2通过电阻分压,把10V的电压分压到了1V,这样就在SYSMON的采样范围内。R5用于阻抗匹配。之后经过一个滤波器进入到ADC的采样P 和N端。
image.jpg
4-3:XADC无极性输入
当外部采集无极性的输入信号,需要对配置寄存器0设置,来选择工作于无极性模式。VN 上的共模信号可以在 0V 到 +0.5V 之间变化(相对于 GNDADC 测量)。由于差分输入范围为 0V 至 1.0V(VP 至 VN),因此 VP 上的最大信号为 1.5V。
image.jpg
对于10BITADC,无极性的输入范围10’0h~12’h3FF,因此0V对于于10’h0,1V对应于10’h3FF
4-4:XADC有极性输入
当外部采集有极性的输入信号,需要对配置寄存器0设置,来选择工作于有极性模式。有极性模式下,VP 和VN的电压必须相对于GNDADC是正电压(不能输入负电压,差分信号的正负是相对信号的共模点来说的),VP-VN的最大范围是±0.5V。下图中,VN=0.5V 因此最大的VP输入范围是±0.5V(当对于VN)
image.jpg
对于10BITADC,有极性的输入范围10’h200~10’h1FF,因此-0.5V对于于10’h200,+0.5V对应于10’h1FF
4-5:差分输入
无极性输入的应用也包括采集差分信号,差分输入信号是相对于VCM对称。VCM的范围为0.25V~0.75V
image.jpg
4-6:SYSMONE4的Common-N模式
SYSMONE4支持Common-N模式,可以把所有的外部ADC的N接到一起,节省IO
image.jpg
3.2 SYSMONE4的寄存器
image.jpg
可以看到以上寄存器中分状态寄存器和控制寄存器。状态寄存器比较容易理解主要是保存了ADC采集到的数值,以及ADC的当前工作状态,我们就不做分析了。
4 搭建工程
该实验使用默认的vivado工程生成的系统镜像,vivado工程文件在附件中可以找到。可以直接使用附件中的“BOOT”中的系统镜像。详细制作系统过程参考第一章。
4.1 vivado工程搭建
image.jpg
5 程序分析
temp.cpp
  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. using namespace std;

  6. #define Vccint 0
  7. #define Vccaux 1
  8. #define Vccbram 2
  9. #define Vccpint 3
  10. #define Vccpaux 4
  11. #define Vccoddr 5
  12. #define Vrefp 6
  13. #define Vrefn 7
  14. #define Mode "/sys/bus/iio/devices/iio:device0/of_node/compatible"
  15. #define TempPATH "/sys/bus/iio/devices/iio:device0/in_temp0_raw"
  16. #define VccintPATH "/sys/bus/iio/devices/iio:device0/in_voltage0_vccint_raw"
  17. #define VccauxPATH "/sys/bus/iio/devices/iio:device0/in_voltage1_vccaux_raw"
  18. #define VccbramPATH "/sys/bus/iio/devices/iio:device0/in_voltage2_vccbram_raw"
  19. #define VccpintPATH "/sys/bus/iio/devices/iio:device0/in_voltage3_vccpint_raw"
  20. #define VccpauxPATH "/sys/bus/iio/devices/iio:device0/in_voltage4_vccpaux_raw"
  21. #define VccoddrPATH "/sys/bus/iio/devices/iio:device0/in_voltage5_vccoddr_raw"
  22. #define VrefpPATH "/sys/bus/iio/devices/iio:device0/in_voltage6_vrefp_raw"
  23. #define VrefnPATH "/sys/bus/iio/devices/iio:device0/in_voltage7_vrefn_raw"
  24. static const int TempDivisor = 1 << 12; //4096
  25. static const int VccDivisor = 1 << 16;  //65536

  26. float getTemp()
  27. {
  28.     FILE *stream;
  29.     float val;
  30.     float temp_value;
  31.     char buf[20];
  32.     if ((stream = fopen(TempPATH, "r")) == NULL)
  33.     {
  34.         cout << "Cannot open output file." << endl;
  35.         return 1;
  36.     }
  37.     fseek(stream, SEEK_SET, 0);
  38.     fread(buf, sizeof(char), sizeof(buf), stream);
  39.     val = atof(buf);
  40.     temp_value = ((val * 509.3140064) / TempDivisor) - 280.2308787;
  41.     //cout << "The cpu temp is " << temp_value << "°C" << endl;
  42.     fclose(stream);
  43.     stream = NULL;
  44.     return temp_value;
  45. }

  46. float getVcc(int x)
  47. {
  48.     FILE *stream;
  49.     int val;
  50.     float vcc_value;
  51.     char buf[20];
  52.     switch (x)
  53.     {
  54.     case Vccint:
  55.         stream = fopen(VccintPATH, "r");
  56.         break;
  57.     case Vccaux:
  58.         stream = fopen(VccauxPATH, "r");
  59.         break;
  60.     case Vccbram:
  61.         stream = fopen(VccbramPATH, "r");
  62.         break;
  63.     case Vccpint:
  64.         stream = fopen(VccpintPATH, "r");
  65.         break;
  66.     case Vccpaux:
  67.         stream = fopen(VccpauxPATH, "r");
  68.         break;
  69.     case Vccoddr:
  70.         stream = fopen(VccoddrPATH, "r");
  71.         break;
  72.     case Vrefp:
  73.         stream = fopen(VrefpPATH, "r");
  74.         break;
  75.     case Vrefn:
  76.         stream = fopen(VrefnPATH, "r");
  77.         break;
  78.     default:
  79.         break;
  80.     }
  81.     if (stream == NULL)
  82.     {
  83.         cout << "Cannot open output file." << endl;
  84.         return 1;
  85.     }
  86.     fseek(stream, SEEK_SET, 0);
  87.     fread(buf, sizeof(char), sizeof(buf), stream);
  88.     val = atoi(buf);
  89.     vcc_value = ((float)(val << 4) / VccDivisor) * 3;
  90.     fclose(stream);
  91.     stream = NULL;
  92.     return vcc_value;
  93. }

  94. int RoundingADD(float i)
  95. {
  96.     return (i > 0.0) ? (i + 0.5) : (i - 0.5);
  97. }

  98. float Rounding(float i)
  99. {
  100.     return (float)RoundingADD(i * 100) / 100;
  101. }

  102. int main()
  103. {
  104.     while (1)
  105.     {
  106.         system("clear");
  107.         cout << "---------------------------------" << endl;
  108.         cout << "The cpu temp is " << Rounding(getTemp()) << "°C" << endl;
  109.         cout << "The vccint is " << Rounding(getVcc(Vccint)) << "V" << endl;
  110.         cout << "The vccaux is " << Rounding(getVcc(Vccaux)) << "V" << endl;
  111.         cout << "The vccbram is " << Rounding(getVcc(Vccbram)) << "V" << endl;
  112.         cout << "The vccpint is " << Rounding(getVcc(Vccpint)) << "V" << endl;
  113.         cout << "The vccpaux is " << Rounding(getVcc(Vccpaux)) << "V" << endl;
  114.         cout << "The vccoddr is " << Rounding(getVcc(Vccoddr)) << "V" << endl;
  115.         cout << "The vrefp is " << Rounding(getVcc(Vrefp)) << "V" << endl;
  116.         cout << "The vrefn is " << Rounding(getVcc(Vrefn)) << "V" << endl;
  117.         cout << "---------------------------------" << endl;
  118.         sleep(1);
  119.     }
  120.     return 0;
  121. }
复制代码
第7行至66行,定义基本的路径和常量。
第70行至218行,定义了四个基本的函数,前两个分别为获取温度,获取电压的功能函数。
第220行至261行,向终端输出获取到的温度,电压等数据。
6 程序编译
因为并不需要编译驱动,可以直接在开发板上进行本地编译。
将文件上传至开发板。
image.jpg
由于是c++文件,在终端输入“c++ tempmp.cpp -o tempmp.out”
image.jpg
生成了可执行文件,准备工作完成。
7 演示
7.1 硬件准备
SD2.0 启动 01 而模式开关为 ON OFF(7100 需要先将系统烧录进qspi,然后才能从qspi启动sd卡,“[米联客-XILINX-H3_CZ08_7100] LINUX基础篇连载-04 从vitis移植Ubuntu实现二次开发”)
2f5038eb9880afd532753935815b079.jpg
将 PS 端串口线连接电脑,如果要使用 ssh 登录,将网口线同样连接至电脑,最后给开发板通电。每次重新上电,需要重新插拔 PS 串口,否则会登录失败。
image.jpg
7.2 程序准备
在终端输入“ls”命令。确认当前所需文件,已经存在当前的文件夹内。
image.jpg
7.3 实验结果
运行程序。
image.jpg
终端成功输出数据。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则