正点原子 发表于 2023-4-11 09:13:32

《ATK-DFPGL22G之FPGA开发指南_V1.0》第十章PS SYSMON测量温度电压实验

本帖最后由 正点原子 于 2023-4-11 16:00 编辑

1)实验平台:正点原子 DFZU2EG_4EV MPSoC开发板
2)购买链接:https://item.taobao.com/item.htm?&id=692368045899
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-340252-1-1.html
4)正点原子官方B站:https://space.bilibili.com/394620890
5)正点原子FPGA交流群:994244016





第十章PS SYSMON测量温度电压实验
系统监视器(System Monitors)是MPSOC中用来测量电压和温度的模块,能够将电压和温度信息提供给系统的其它部分,包括平台管理单元(PMU),实时处理单元(RPU)和应用处理单元(APU)。MPSOC中有两个SYSMON模块:PL端SYSMON模块和PS端SYSMON模块。
本章我们将使用PS端SYSMON模块,读取芯片的温度电压等信息。本章包括以下几个部分:
10.1简介
10.2实验任务
10.3硬件设计
10.4软件设计
10.5下载验证

10.1简介
PS SYSMON模块位于PS端低功耗域内,由VCC_PSAUX和VCC_PSADC供电。PS SYSMON能同时测量两个温度和几个固定的电压节点。AXI互联主机通过PS SYSMON和AMS寄存器组控制PS端SYSMON模块。
MPSOC中PS SYSMON和PL SYSMON模块都属于SYSMONE4结构,结构上存在很多相似处。也有许多不同点,例如采样率,参考电压,编程接口,电源域,温度传感器等。PS SYSMON模块框图如下图所示:
图10.1.1 PS SYSMON模块框图
PS SYSMON监测的内部电压节点位于低功耗域和全功耗域,包含内部和IO缓冲区节点。PS中所有电压测量都是单极的,内部电压节点测量范围是0~3V或0~6V。PS内部有两个温度传感器,一个物理位置在RPU附近,另外一个在APU附近。在图10.1.1中,软件通过APB SLAVE接口配置PS SYSMON的寄存器。
PS和PL的SYSMON模块各自独立运行。运行模式包括单通道读模式,默认的序列模式和自动序列器模式,SYSMON通常以默认的序列模式运行。在默认模式下,可以通过CONFIG_REG寄存器将SYSMON配置成自定义序列。
单通道读模式一次只能测量一个通道的传感器信号。在使用单通道模式时,先向CONFIG_REG0寄存器比特位写入通道序号,再将CONFIG_REG1寄存器比特位设置成单通道模式,然后等待EOC(end of conversion)中断,当中断触发时,读取相关测量寄存器。
自动序列器模式下,SYSMON模块可以一次或连续的对打开的通道列表进行顺序访问。模拟输入按照固定顺序进行时间多路复用,并且每次只有一路信号送给ADC输入。读取每个通道的测量值时,最大值和最小值都会被存储。测量值也可以在连续测量结果的平均值。
10.2实验任务
本章的实验任务是通过APB Slave接口,读取PS SYSMON测量的芯片温度、供电电压等信息,并通过串口打印出来。
10.3硬件设计
根据实验任务我们可以画出本次实验的系统框图,如下图所示:
图 10.3.1 系统框图
在图 10.3.1中,CPU作为AXI主机连接到SYSMON模块APB Slave接口,读取SYSMON模块采集的温度和电压数据,然后通过串口打印出来。
本次实验在《Hello World》实验中的最小系统上就可以完成,也就是说不需要额外配置PS端或者添加PL端的外设。
打开《hello_world》工程,另存为本次实验工程《ps_sysmon》,导出硬件设计(Hardware),具体步骤可以参照前面的实验,最后打开Vitis软件。
10.4软件设计
在VITIS软件中新建一个空的应用工程,应用工程名为“ps_sysmon”。然后为应用工程新建一个源文件“main.c”,我们在新建的main.c文件中输入本次实验的代码:
1   #include "xsysmonpsu.h"
2   #include "xparameters.h"
3   #include "xstatus.h"
4   #include "stdio.h"
5   #include "sleep.h"
6   
7   #define SYSMON_DEVICE_ID    XPAR_XSYSMONPSU_0_DEVICE_ID
8   #define printf xil_printf
9   
10int    PS_SYSMON_Test(u16 SysMonDeviceId);
11static int SysMonPsuFractionToInt(float FloatNum);
12static XSysMonPsu SysMonInst;                        //PS SYSMON实例
13
14int main(void)
15{
16      xil_printf("Run Sysmon Polled Test\r\n");
17
18      PS_SYSMON_Test(SYSMON_DEVICE_ID);
19
20      return XST_SUCCESS;
21}
22
23int PS_SYSMON_Test(u16 SysMonDeviceId)
24{
25      XSysMonPsu_Config *ConfigPtr;
26      u32 TempRawData;                              //温度         原始数据
27      u32 VccAuxRawData;                            //PS 辅助电压原始数据
28      u32 VccIntRawData;                            //PS 内核电压原始数据
29      u32 VCCO_PSIO0RawData;                        //Bank500电压原始数据
30      u32 VCCO_PSIO1RawData;                        //Bank501电压原始数据
31      float TempData;                               //温度
32      float VccAuxData;                           //PS 辅助电压
33      float VccIntData;                           //PS 内核电压
34      float VCCO_PSIO0Data;                         //Bank500电压
35      float VCCO_PSIO1Data;                         //Bank501电压
36      u64 IntrStatus;
37      XSysMonPsu *SysMonInstPtr = &SysMonInst;
38
39      printf("\r\nEntering the SysMon Test. \r\n");
40
41      ConfigPtr = XSysMonPsu_LookupConfig(SysMonDeviceId);
42      if (ConfigPtr == NULL) {
43          return XST_FAILURE;
44      }
45      XSysMonPsu_CfgInitialize(SysMonInstPtr, ConfigPtr,
46                  ConfigPtr->BaseAddress);
47
48      XSysMonPsu_SetSequencerMode(SysMonInstPtr,
49            XSM_SEQ_MODE_SAFE, XSYSMON_PS);            //设置Sequence Mode为安全模式
50
51      XSysMonPsu_SetAlarmEnables(SysMonInstPtr,          //关闭寄存器1中指定信号的警报
52            0x0, XSYSMON_PS);
53
54      XSysMonPsu_SetAvg(SysMonInstPtr,
55            XSM_AVG_16_SAMPLES, XSYSMON_PS);         //设置采样16次后计算平均值
56
57      XSysMonPsu_SetSeqAvgEnables(SysMonInstPtr,
58            XSYSMONPSU_SEQ_CH0_TEMP_MASK |             //使能Temp_LPD通道平均值测量
59            XSYSMONPSU_SEQ_CH0_SUP1_MASK |             //使能VCC_PSINTLP通道平均值测量
60            XSYSMONPSU_SEQ_CH0_SUP3_MASK |             //使能VCC_PSAUX通道平均值测量
61            XSYSMONPSU_SEQ_CH0_SUP6_MASK |             //使能VCCO_PSIO0通道平均值测量
62            XSYSMONPSU_SEQ_CH2_SUP7_MASK ,             //使能VCCO_PSIO1通道平均值测量
63            XSYSMON_PS);
64
65      XSysMonPsu_SetSeqChEnables(SysMonInstPtr,
66            XSYSMONPSU_SEQ_CH0_TEMP_MASK |             //打开Temp_LPD通道
67            XSYSMONPSU_SEQ_CH0_SUP1_MASK |             //打开VCC_PSINTLP通道
68            XSYSMONPSU_SEQ_CH0_SUP3_MASK |             //打开VCC_PSAUX通道
69            XSYSMONPSU_SEQ_CH0_SUP6_MASK |             //打开VCCO_PSIO0通道
70            XSYSMONPSU_SEQ_CH2_SUP7_MASK ,             //打开VCCO_PSIO1通道
71            XSYSMON_PS);
72
73      IntrStatus = XSysMonPsu_IntrGetStatus(SysMonInstPtr); //读中断状态寄存器
74      XSysMonPsu_IntrClear(SysMonInstPtr, IntrStatus);//清除中断状态寄存器
75
76      XSysMonPsu_SetSequencerMode(SysMonInstPtr,
77            XSM_SEQ_MODE_CONTINPASS, XSYSMON_PS);   //设定Sequence Mode为通道循环模式
78
79      while ((XSysMonPsu_IntrGetStatus(SysMonInstPtr) & ((u64)XSYSMONPSU_ISR_1_EOS_MASK<<
80          32))!= ((u64)XSYSMONPSU_ISR_1_EOS_MASK<< 32));//等待EOS(end of sequence)发生
81
82      while(1)
83      {
84      //从ADC数据寄存器读实时温度值
85      TempRawData = XSysMonPsu_GetAdcData(SysMonInstPtr,
86                              XSM_CH_TEMP, XSYSMON_PS);      //读Temp_LPD通道数据
87      TempData = XSysMonPsu_RawToTemperature_OnChip(TempRawData);
88      printf("The Current Temperature is %0d.%03d Centigrades.\r\n",
89                  (int)(TempData), SysMonPsuFractionToInt(TempData));
90
91      //从ADC数据寄存器读VccInt电压值
92      VccIntRawData = XSysMonPsu_GetAdcData(SysMonInstPtr,
93                              XSM_CH_SUPPLY1, XSYSMON_PS);   //读VCC_PSINTLP通道数据
94      VccIntData = XSysMonPsu_RawToVoltage(VccIntRawData);
95      printf("The Current VCCINT is %0d.%03d Volts. \r\n",
96            (int)(VccIntData), SysMonPsuFractionToInt(VccIntData));
97
98      //从ADC数据寄存器读VccAux电压值
99      VccAuxRawData = XSysMonPsu_GetAdcData(SysMonInstPtr,
100                           XSM_CH_SUPPLY3, XSYSMON_PS);   //读VCC_PSAUX通道数据
101   VccAuxData = XSysMonPsu_RawToVoltage(VccAuxRawData);
102   printf("The Current VCCAUX is %0d.%03d Volts. \r\n",
103             (int)(VccAuxData), SysMonPsuFractionToInt(VccAuxData));
104
105   VCCO_PSIO0RawData = XSysMonPsu_GetAdcData(SysMonInstPtr,
106                           XSM_CH_SUPPLY6, XSYSMON_PS);   //读Bank500电压
107   VCCO_PSIO0Data = XSysMonPsu_VccopsioRawToVoltage(VCCO_PSIO0RawData);
108   printf("The Current VCCO_PSIO0 is %0d.%03d Volts. \r\n",
109               (int)(VCCO_PSIO0Data), SysMonPsuFractionToInt(VCCO_PSIO0Data));
110
111   VCCO_PSIO1RawData = XSysMonPsu_GetAdcData(SysMonInstPtr,
112                           XSM_CH_SUPPLY7, XSYSMON_PS);   //读Bank501电压
113   VCCO_PSIO1Data = XSysMonPsu_VccopsioRawToVoltage(VCCO_PSIO1RawData);
114   printf("The Current VCCO_PSIO1 is %0d.%03d Volts. \r\n\r\n\r\n",
115               (int)(VCCO_PSIO1Data), SysMonPsuFractionToInt(VCCO_PSIO1Data));
116
117   //延时5s
118   sleep(5);
119   }
120
121   return XST_SUCCESS;
122 }
123
124 //将小数转换成整数
125 int SysMonPsuFractionToInt(float FloatNum)
126 {
127   float Temp;
128
129   Temp = FloatNum;
130   if (FloatNum < 0) {
131         Temp = -(FloatNum);
132   }
133
134   return( ((int)((Temp -(float)((int)Temp)) * (1000.0f))));
135 }
代码第14行至第21行,是程序的主函数,主函数比较简单,先输出打印信息“Run Sysmon Polled Test”,然后调用PS_SYSMON_Test()函数,该函数是在官方函数基础上修改而来。
在PS_SYSMON_Test()函数中,首先对SYSMON进行初始化,如程序第41行至第46行所示。通过调用XSysMonPsu_SetSequencerMode()函数,将SYSMON操作模式设置为默认模式(安全模式)。程序第54行至第55行,设置平均值的采样次数为16次。接下来是使能通道的平均值测量,即测量结果是采样16次后计算的平均值,如第57行至第63行所示,如果不打开通道的平均值测量,则测量结果是最后一次采样值。
程序第92行至第93行中,通过调用XSysMonPsu_GetAdcData()函数,读取Vcc_Int内核电压的原始数据。该函数中,第二个参数XSM_CH_SUPPLY1代表supply1通道,通过查看ug1085手册,supply1通道实际就是VCC_PSINTLP通道,如下图所示:
图10.4.1 PS SYSMON传感器通道
通过查看ug1087手册可知,该通道物理地址为0x00FFA50804,而XSysMonPsu_GetAdcData()函数通过对第二和第三个参数计算,最终获取的就是物理地址为0x00FFA50804的VCC_PSINTLP通道的原始数据。程序第94行中,XSysMonPsu_RawToVoltage()函数对原始数据先乘以3再除以65536,公式详细讲解可参考ug580手册,如图10.4.2所示。其它通道的电压温度测量类似,这里不详细讲解。注意MIO通道电压计算公式和其它通道是不同的。
图10.4.2 电压计算公式
程序第96行调用SysMonPsuFractionToInt()函数,该函数将浮点型数据的小数部分转换成整数,函数定义如第125行至第135行所示。
10.5下载验证
首先我们将下载器与开发板上的JTAG接口连接,下载器另外一端与电脑连接。然后使用USB连接线将USB_UART(开发板PS PORT)接口与电脑连接,用于串口通信。最后连接开发板的电源,给开发板上电。
打开Vitis Terminal终端,设置并连接串口。然后下载本次实验的程序,下载完成后,在下方的VITIS Terminal中可以看到应用程序每隔5秒打印一次芯片温度和电压等信息,如下图所示:
图 10.5.1 串口终端中打印的信息
从图 10.5.1中可以看到,串口终端能够正确打印温度和电压信息,说明本次实验在MPSOC开发板上面下载验证成功。
页: [1]
查看完整版本: 《ATK-DFPGL22G之FPGA开发指南_V1.0》第十章PS SYSMON测量温度电压实验