ZYNQ 7000 XADC


Zynq-Linux移植學習筆記之16-Zynq下linux XADC驅動

XADC模塊的使用方法,一是直接用FPGA JTAG專用接口訪問,這時XADC模塊工作在缺省模式;二是在設計中例化XADC模塊,這是可以通過FPGA邏輯或ZYNQ器件的PS到ADC模塊的專用接口訪問。例化XADC模塊有兩種基本形式:一是ISE和PlanAhead環境下LogiCOREIP核的形式調用,二是EDK環境下對LogiCOREIP核的調用。這兩種調用方法相信對使用過XILINX產品的朋友來說操作界面與步驟都很熟悉,這里就不贅述了,主要是想說明下XADC模塊原語,以期對這模塊有個基本的了解。

1、  簡介

XADC是zynq芯片內部進行溫度和電壓檢測的模塊,通過(http://www.wiki.xilinx.com/xadc)這篇wiki可以知道,XADC控制器有兩種表現形式,一種是位於PS內部,即文檔中提到的the PS-XADC interface for the PS software to control the XADC,另一種是位於PL內部,通過IP核的方式實現。目前常用的是第一種。

通過ug480_7Series_XADC這篇文檔得知,The ADCs can access up to 17 external analog input channels,也就是除了內部原有的監測項外,XADC最多支持17路擴展通道,可以參看下圖。


對硬件有了基本的了解后,就可以進行devicetree的設置了。

 

2、  devicetree配置

由於是在PS部分,XADC控制器設置就像其他控制器一樣即可,system.hdf中給出了地址:


Devicetree設置如下:

[html] view plain copy
  1. xadc@f8007100 {  
  2.         compatible= "xlnx,zynq-xadc-1.00.a";  
  3.         reg =<0xf8007100 0x20>;  
  4.         interrupts= <0 7 4>;  
  5.        interrupt-parent = <&gic>;  
  6.         clocks =<&pcap_clk>;  
  7.    
  8.        xlnx,channels {  
  9.            #address-cells = <1>;  
  10.            #size-cells = <0>;  
  11.            channel@0 {  
  12.                 reg= <0>;  
  13.             };  
  14.            channel@1 {  
  15.                 reg= <1>;  
  16.             };  
  17.            channel@8 {  
  18.                 reg= <8>;  
  19.             };  
  20.         };  
  21.     };  


這里只啟用了三個channel,如果啟用更多channel可以在devicetree中進行添加。

 

3、  kernel配置

內核中已經包含了xadc的驅動程序,位置是drivers\iio\adc,最后三個xilinx打頭的文件。將驅動加入內核配置過程如下:







如果為了省事,也可以直接在defconfig文件中加入配置信息,這樣默認是選中的。


 

4、  測試

加載devicetree,uimage,uramdisk后能在sys目錄下找到檢測信息:


打開in_temp0_raw能看到數字,注意,該數字是原始數字,需要轉換才能得到正確的攝氏度。


該數字不斷變化,表明溫度在變化。其他電壓信息類似。

為了更直觀的展現監測信息,可以做一個用戶app來打印,代碼如下:

 

  1. #define MAX_PATH_SIZE   200  
  2. #define MAX_NAME_SIZE   50  
  3. #define MAX_VALUE_SIZE  100  
  4.   
  5. #define MAX_CMD_NAME_SIZE 100  
  6. #define MAX_UNIT_NAME_SIZE 50  
  7.   
  8. #define SYS_PATH_IIO    "/sys/bus/iio/devices/iio:device0"  
  9.   
  10. #define VCC_INT_CMD     "xadc_get_value_vccint"  
  11. #define VCC_AUX_CMD     "xadc_get_value_vccaux"  
  12. #define VCC_BRAM_CMD        "xadc_get_value_vccbram"  
  13. #define VCC_TEMP_CMD        "xadc_get_value_temp"  
  14. #define VCC_EXT_CH_CMD      "xadc_get_value_ext_ch"  
  15.   
  16.   
  17.   
  18. static const int mV_mul = 1000;  
  19.   
  20. static const int multiplier = 1 << 12;  
  21.   
  22. static char gNodeName[MAX_NAME_SIZE];  
  23.   
  24. enum EConvType  
  25. {  
  26.     EConvType_None,  
  27.     EConvType_Raw_to_Scale,  
  28.     EConvType_Scale_to_Raw,  
  29.     EConvType_Max  
  30. };  
  31.   
  32. enum XADC_Param  
  33. {  
  34.     EParamVccInt,  
  35.     EParamVccAux,  
  36.     EParamVccBRam,  
  37.     EParamTemp,  
  38.     EParamVAux0,  
  39.     EParamMax  
  40. };  
  41.   
  42. struct command  
  43. {  
  44.     const enum XADC_Param parameter_id;  
  45.     const char cmd_name[MAX_CMD_NAME_SIZE];  
  46.     const char unit[MAX_UNIT_NAME_SIZE];  
  47. };  
  48.   
  49. struct command command_list[EParamMax] = {  
  50.                 {EParamVccInt,  VCC_INT_CMD, "mV"},  
  51.                 {EParamVccAux,  VCC_AUX_CMD, "mV"},  
  52.                 {EParamVccBRam, VCC_BRAM_CMD, "mV"},  
  53.                 {EParamTemp,    VCC_TEMP_CMD, "Degree Celsius"},  
  54.                 {EParamVAux0,   VCC_EXT_CH_CMD, "mV"}  
  55. };  
  56.   
  57. struct XadcParameter  
  58. {  
  59.     const char name[MAX_NAME_SIZE];  
  60.     float value;  
  61.     float (* const conv_fn)(float,enum EConvType);  
  62. };  
  63.   
  64. /* 
  65. struct XadcParameter gXadcData[EParamMax] = { 
  66.     [EParamVccInt] = { "in_voltage0_vccint_raw",    0, conv_voltage}, 
  67.     [EParamVccAux] = { "in_voltage4_vccpaux_raw",   0, conv_voltage}, 
  68.     [EParamVccBRam]= { "in_voltage2_vccbram_raw",   0, conv_voltage}, 
  69.     [EParamTemp]   = { "in_temp0_raw",      0, conv_temperature}, 
  70.     [EParamVAux0]  = { "in_voltage8_raw",       0, conv_voltage_ext_ch} 
  71. }; 
  72. */  

 

  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <errno.h>  
  4. #include <unistd.h>  
  5. #include <dirent.h>  
  6. #include <stdlib.h>  
  7. #include <sys/ioctl.h>  
  8. #include <fcntl.h>  
  9. #include <ctype.h>  
  10. #include <pthread.h>  
  11. #include <assert.h>  
  12.   
  13. #include "xadc_core.h"  
  14.   
  15. //utility functions  
  16. float conv_voltage(float input, enum EConvType conv_direction)  
  17. {  
  18.     float result=0;  
  19.   
  20.     switch(conv_direction)  
  21.     {  
  22.     case EConvType_Raw_to_Scale:  
  23.         result = ((input * 3.0 * mV_mul)/multiplier);  
  24.         break;  
  25.     case EConvType_Scale_to_Raw:  
  26.         result = (input/(3.0 * mV_mul))*multiplier;  
  27.         break;  
  28.     default:  
  29.         printf("Convertion type incorrect... Doing no conversion\n");  
  30.         //  intentional no break;  
  31.     case EConvType_None:  
  32.         result = input;  
  33.         break;  
  34.     }  
  35.   
  36.     return result;  
  37. }  
  38.   
  39. float conv_voltage_ext_ch(float input, enum EConvType conv_direction)  
  40. {  
  41.     float result=0;  
  42.   
  43.     switch(conv_direction)  
  44.     {  
  45.     case EConvType_Raw_to_Scale:  
  46.         result = ((input * mV_mul)/multiplier);  
  47.         break;  
  48.     case EConvType_Scale_to_Raw:  
  49.         result = (input/mV_mul)*multiplier;  
  50.         break;  
  51.     default:  
  52.         printf("Convertion type incorrect... Doing no conversion\n");  
  53.         //  intentional no break;  
  54.     case EConvType_None:  
  55.         result = input;  
  56.         break;  
  57.     }  
  58.   
  59.     return result;  
  60. }  
  61.   
  62. float conv_temperature(float input, enum EConvType conv_direction)  
  63. {  
  64.     float result=0;  
  65.   
  66.     switch(conv_direction)  
  67.     {  
  68.     case EConvType_Raw_to_Scale:  
  69.         result = ((input * 503.975)/multiplier) - 273.15;  
  70.         break;  
  71.     case EConvType_Scale_to_Raw:  
  72.         result = (input + 273.15)*multiplier/503.975;  
  73.         break;  
  74.     default:  
  75.         printf("Conversion type incorrect... Doing no conversion\n");  
  76.         //  intentional no break;  
  77.     case EConvType_None:  
  78.         result = input;  
  79.         break;  
  80.     }  
  81.   
  82.     return result;  
  83. }  
  84.   
  85.   
  86. void get_iio_node()  
  87. {  
  88.     struct dirent **namelist;  
  89.     int i,n;  
  90.     char value=0;  
  91.     int fd = -1;  
  92.     char upset[20];  
  93.     float raw_data=0;  
  94.     float true_data=0;  
  95.     int offset=0;  
  96.     int currpos;  
  97.   
  98.     n = scandir(SYS_PATH_IIO, &namelist, 0, alphasort);  
  99.   
  100.     for (i=0; i < n; i++)  
  101.     {  
  102.         sprintf(gNodeName,"%s/%s", SYS_PATH_IIO, namelist[i]->d_name);  
  103.   
  104.         fd = open(gNodeName, O_RDWR );  
  105.   
  106.         if(strstr(gNodeName,"temp"))  
  107.         {  
  108.             if(strstr(gNodeName,"raw"))  
  109.             {  
  110.                 offset=0;  
  111.                 while(offset<5)  
  112.                 {     
  113.                     lseek(fd,offset,SEEK_SET);  
  114.                     read(fd,&value,sizeof(char));     
  115.                     upset[offset]=value;  
  116.                     offset++;  
  117.                 }     
  118.                 upset[offset]='\0';  
  119.                 raw_data=atoi(upset);  
  120.                 true_data=conv_temperature(raw_data, EConvType_Raw_to_Scale);  
  121.                 printf("%s is %f cent\n",namelist[i]->d_name,true_data);  
  122.             }  
  123.         }  
  124.         else if(strstr(gNodeName,"voltage"))  
  125.         {  
  126.             if(strstr(gNodeName,"raw"))  
  127.             {  
  128.                 offset=0;  
  129.                 while(offset<5)  
  130.                 {  
  131.                     lseek(fd,offset,SEEK_SET);  
  132.                     read(fd,&value,sizeof(char));     
  133.                     upset[offset]=value;  
  134.                     offset++;  
  135.                 }     
  136.                 upset[offset]='\0';  
  137.                 raw_data=atoi(upset);  
  138.                 true_data=conv_voltage(raw_data, EConvType_Raw_to_Scale);  
  139.                 printf("%s is %f mv\n",namelist[i]->d_name,true_data);  
  140.             }  
  141.         }  
  142.         close(fd);  
  143.   
  144.     }  
  145. }  
  146.   
  147. int main(int argc, char *argv[])  
  148. {  
  149.     get_iio_node();  
  150.     return 0;  
  151. }  


 

 

在編寫這段代碼時遇到好幾個問題,首先用read函數取值取到的其實是 文件中ASCII碼字符,沒有什么好辦法只好改成一位一位讀取存入字符串然后調用atoi函數轉換為int數字。其次,用lseek函數獲取文件大小時得 到的值都為4096,但是這些文件並不是目錄,不知道為何大小都顯示的是linux最基本的文件塊大小,最后只好投機取巧根據每個文件中的數字位數進行取 值,例如temp和vcc這些文件只有4位,那么就從文件中讀4位。最后輸出結果如下:


上圖中溫度為39度,和實際情況差不多。至此XADC驅動告一段落。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM