查看: 396|回复: 0

[原创] 领航者ZYNQ开发板试用2:XADC模块测试温度和电压

[复制链接]

主题

好友

929

积分

举人

  • TA的每日心情
    奋斗
    2020-3-16 07:17
  • 签到天数: 53 天

    连续签到: 1 天

    [LV.5]常住居民I

    发表于 2020-1-23 10:17:20 |显示全部楼层

    ZYNQ-7000系列的XADC模块是一个双12位分辨率的而且每秒一兆(MSPS, 1 Mega sample per second)采样速率的高精度模数转换器,双通道的ADC支持单极和差分输入工作模式,其最多可支持17路外部模拟输入通道,并且内部包括芯片内的温度和供电电压传感器,供电电压包括PL的VCCINT、VCCAUX、VCCBRAM和PS的VCCPINT、VCCPAUX和VCCO_DDR。
      领航者ZYNQ开发板底板上有1个XADC接口,把ZYNQ-7000一对差分专用模拟输入脚引到接口上了,可以从外部输入模拟信号到XADC模块, 注意模拟差分信号或单端信号的峰峰值最大为1伏特电压。

      正点原子提供的《领航者ZYNQ之嵌入式开发指南_V1.1.pdf》文档的第10章PS XADC接口实验是介绍XADC模块的实验步骤的,里面的介绍内容和代码这里没有必要重复贴出来,建议大家要先学习一遍,对应的源码工程在【正点原子】领航者 ZYNQ开发板光盘资料\领航者ZYNQ开发板资料盘(A盘)\4_SourceCode\ZYNQ_7010\2_Embedded_System.rar压缩包内,我们首先是按照该文档进行读片内温度和电压的实验,然后进一步读外部XADC接口输入的模拟电压。学习XADC模块的首要参考文档是XILINX官方出的ug480: 7 Series FPGAs and Zynq-7000 SoC XADCDual 12-Bit 1 MSPS Analog-to-Digital Converter User Guide,也是非常建议大家要通读一遍的。
        片内温度测量时ADC数值与温度的转换关系参考下图的公式:
    201.jpg


    一个LSB大概为0.123度。

    片内电压测量时ADC数值就是按3V为最大12比特的线性表示,一个LSB大概为0.732mV,如VCCINT= 1V, 读出的ADC数值应该是 1/3 x 4096 =1365 = 555 h。
    总结下XADC模块的访问方式,如下图示XADC模块的系统框图:
    202.jpg


    主要有PL-JTAG接口,PS-XADC接口,DRP(dynamic reconfiguration port)并行接口, PL-JTAG接口和PS-XADC接口都是串行接口,并且由上图也可以看到二者通过选择器二选一连到XADC模块,不能同时使用,这两种接口都不需要编程PL部分,只需要对PL部分供电。DRP并行接口主要由PL访问,PS也可以通过AXI总线访问PL逻辑来间接地访问XADC模块,设计时需要在PL逻辑中例化XADCIP核。
        XADC模块提供了多达128个16比特的寄存器供用户读写控制,寄存器接口如下图示:
    203.jpg

    详细寄存器比特含义的描述请参考ug480的第3章,这里特别摘出XADC模块有6种工作模式,按下图由第1个控制寄存器的SEQ0~SEQ3决定:
    204.jpg


    这里Single pass sequence模式是指按顺序采样一次后就停止的模式,如果连续按预定序列采样不停止的话就是Continuous sequence mode模式。上电后或者没有例化XADC IP核时一般是工作在Default Mode缺省模式来执行片内温度和电压的监控功能。
        以上对ZYNQ-7000系列的XADC模块有个基本的了解后我们开始实验,首先解压2_Embedded_System.rar压缩包内的10_ps_xadc文件压到一个工作目录,注意路径不要有中文名字,然后用vavido2018.3打开ps_xadc.xpr工程,在工程主界面运行File—Launch SDK后按OK打开SDK的工作区,如下图示:
    205.jpg


    这里我们将修改工程软件实现片内温度和电压监控功能基础上采集开发板外部XADC接口输入的模拟电压,需要把工作模式从Default Mode修改为Continuous sequence mode模式,并对应配置使能位,修改后的代码如下:

    //****************************************************************************************//

    #include "xparameters.h"

    #include "xadcps.h"

    #include "stdio.h"

    #include "xil_printf.h"

    #include "sleep.h"


    #define XADC_DEVICE_ID    XPAR_XADCPS_0_DEVICE_ID      //PS XADC 器件ID


    static  XAdcPs                   xadc_inst;                //XADC驱动实例


    int main(void)

    {

           int    Op_status;

           XAdcPs_Config*ConfigPtr;  //XADC 配置指针


           u32 temp_rawdata;                    //温度           原始数据

           u32vcc_pint_rawdata;         //PS 内核电压      原始数据

           u32 vcc_paux_rawdata;       //PS 辅助电压      原始数据

           u32vcc_pddr_rawData;       //PS DDR电压      原始数据

           u32 vcc_int_rawdata;           //PL 内核电压      原始数据

           u32 vcc_aux_rawdata;         //PL 辅助电压      原始数据

           u32vcc_bram_rawData;             //PL BRAM电压    原始数据

           u32vcc_vpvn_rawData;       //VP_VN电压 原始数据


           float temp;                                 //温度

           float vcc_pint;                     //PS内核电压

           float vcc_paux;                           //PS 辅助电压

           float vcc_pddr;                           //PS DDR电压

           float vcc_int;                       //PL 内核电压

           float vcc_aux;                      //PL 辅助电压

           float vcc_bram;                          //PL BRAM电压

           float vcc_vpvn;                           //VP_VN电压


           //初始化XADC驱动

           ConfigPtr =XAdcPs_LookupConfig(XADC_DEVICE_ID);

           XAdcPs_CfgInitialize(&xadc_inst,ConfigPtr, ConfigPtr->BaseAddress);


           //设置XADC操作模式为“默认安全模式”

           XAdcPs_SetSequencerMode(&xadc_inst,XADCPS_SEQ_MODE_SAFE);


        //修改模式为连续采样并使能通道

           Op_status =XAdcPs_SetSeqChEnables     (&xadc_inst,XADCPS_SEQ_CH_TEMP |XADCPS_SEQ_CH_VCCPINT

             | XADCPS_SEQ_CH_VCCPAUX |XADCPS_SEQ_CH_VCCPDRO | XADCPS_SEQ_CH_VCCINT

             | XADCPS_SEQ_CH_VCCAUX | XADCPS_SEQ_CH_VBRAM| XADCPS_SEQ_CH_VPVN);

           if(Op_status !=XST_SUCCESS)

           {

                  printf("XAdcPs_SetSeqChEnableserror!\n\r");

           }


           XAdcPs_SetSequencerMode(&xadc_inst,XADCPS_SEQ_MODE_CONTINPASS);


           while(1){

                  //获取原始温度传感器数据

                  temp_rawdata= XAdcPs_GetAdcData(&xadc_inst, XADCPS_CH_TEMP);

                  //转换成温度信息

                  temp =XAdcPs_RawToTemperature(temp_rawdata);


                  //获取VCCPINT传感器数据,并转换成电压信息

                  vcc_pint_rawdata= XAdcPs_GetAdcData(&xadc_inst, XADCPS_CH_VCCPINT);

                  vcc_pint =XAdcPs_RawToVoltage(vcc_pint_rawdata);


                  //获取VCCPAUX传感器数据,并转换成电压信息

                  vcc_paux_rawdata= XAdcPs_GetAdcData(&xadc_inst, XADCPS_CH_VCCPAUX);

                  vcc_paux =XAdcPs_RawToVoltage(vcc_paux_rawdata);


                  //获取VCCPDRO传感器数据,并转换成电压信息

                  vcc_pddr_rawData= XAdcPs_GetAdcData(&xadc_inst, XADCPS_CH_VCCPDRO);

                  vcc_pddr =XAdcPs_RawToVoltage(vcc_pddr_rawData);


                  //获取VCCINT传感器数据,并转换成电压信息

                  vcc_int_rawdata= XAdcPs_GetAdcData(&xadc_inst, XADCPS_CH_VCCINT);

                  vcc_int =XAdcPs_RawToVoltage(vcc_int_rawdata);


                  //获取VCCAUX传感器数据,并转换成电压信息

                  vcc_aux_rawdata= XAdcPs_GetAdcData(&xadc_inst, XADCPS_CH_VCCAUX);

                  vcc_aux =XAdcPs_RawToVoltage(vcc_aux_rawdata);


                  //获取VBRAM传感器数据,并转换成电压信息

                  vcc_bram_rawData= XAdcPs_GetAdcData(&xadc_inst, XADCPS_CH_VBRAM);

                  vcc_bram =XAdcPs_RawToVoltage(vcc_bram_rawData);


                  //获取VPVN传感器数据,并转换成电压信息

                  vcc_vpvn_rawData= XAdcPs_GetAdcData(&xadc_inst, XADCPS_CH_VPVN);

                  vcc_vpvn =XAdcPs_RawToVoltage(vcc_vpvn_rawData)/3;


                  //打印温度、电压信息

                  printf("RawTemp    %lu, Real Temp    %fC \n", temp_rawdata,     temp);

                  printf("RawVccPInt %lu, Real VccPInt %fV \n", vcc_pint_rawdata, vcc_pint);

                  printf("RawVccPAux %lu, Real VccPAux %fV \n", vcc_paux_rawdata, vcc_paux);

                  printf("RawVccPDDR %lu, Real VccPDDR %fV \n", vcc_pddr_rawData, vcc_pddr);

                  printf("RawVccInt  %lu, Real VccInt  %fV \n", vcc_int_rawdata,  vcc_int);

                  printf("RawVccAux  %lu, Real VccAux  %fV \n", vcc_aux_rawdata,  vcc_aux);

                  printf("RawVccBram %lu, Real VccBram %fV \n", vcc_bram_rawData, vcc_bram);

                  printf("RawVccVPVN %lu, Real VccVPVN %fV \n", vcc_vpvn_rawData, vcc_vpvn);

                  printf("\n\r");

                  //延时5s

                  sleep(5);

           }

           return 0;

    }
    注意这里并没有设置控制寄存器0的输入极性比特,所以VP_VN输入极性是默认的单极性输入,我们可以在它们之间用一个直流电源输入0~1V的电源来进行测试,VN接电源地,VP接电源正极,测试过程和结果可以参看下面视频:

    最后祝大家新年快乐!


    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    关闭

    站长推荐上一条 /5 下一条

    手机版|电路城

    GMT+8, 2020-3-29 22:40 , Processed in 0.071706 second(s), 14 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz!

    返回顶部