查看: 94026|回复: 105

[原创] [使用实例] 树莓派驱动AD7606数据采集模块—SPI接口使用手记

  [复制链接]

该用户从未签到

发表于 2016-3-7 15:04:38 | 显示全部楼层 |阅读模式
分享到:
本帖最后由 ky123 于 2018-3-2 09:25 编辑

        最近做项目,尝试着使用Raspberry Pi2来进行开发。Raspberry Pi2还是挺强大的,只是感觉可用的IO口很少。。项目中需要用到ADC模块,就去淘宝上淘一个安富莱德AD7606,感觉做工挺不错的还。不过价格也是贵哈,120大洋买的。
HDFX80D@5}J4RGGDR~}@_XW.png

        AD7606是8路、16位的AD,真双极性-5~+5或者-10~+10,采样率为200ksps(不可设定),可以选择使用并行模式、字节模式以及SPI模式。考虑到树莓派可怜的IO口数量,妥妥的选择用SPI模式。
TB2G6_aaXXXXXbcXpXXXXXXXXXX_!!299314119.png


        板子默认是上图左边的并行模式,因此拿到手之后需要改动用一下电阻到右边的样子。再详细的资料大家可以去淘宝搜一下,上面讲的很详细。废话不多说,下面上接线图。
LDBEH`8MC2[6HC8Z1W3%L$Y.png

       AD7606是带了数字滤波器的,可以通过OS1~OS3来配置,这里我接到了固定电平(000,不滤波)上。有需要的话也可以接到gpio上,我发的驱动程序里面已经预留好了接口。然后rage口是配置量程的,我也接的的固定电平(选择了-5~+5),同样的也可以接在gpio上。AD7606的时序还是很简单的,是标准的SPI接口。由于其所有配置都通过管教的电平来完成,所用的SPI只有SCLK和MISO。
      下图即为AD7606串行模式下的时序图。转换时序选择了在转换后读取,比较方便配置(比较好写^_^),然后是下面的SPI
YH(VSG_@%{N7(G5U7PX@_(3.png

转换时序图

R$~K]8XZT@@Y435Z1S($ROL.png

通信时序图

的时序图。SPI的通信有4种模式,如下图所示,对比可以知道是第二种,即CPOL = 1, CPHA = 0。根据linux/spi/spidev.h中的定
1364867758_7264.jpg


义可知为
  1. /*----- SET SPI MODE -----
  2.     SPI_MODE_0 (0,0)         CPOL = 0, CPHA = 0, Clock idle low, data is clocked in on rising edge, output data (change) on falling edge
  3.     SPI_MODE_1 (0,1)         CPOL = 0, CPHA = 1, Clock idle low, data is clocked in on falling edge, output data (change) on rising edge
  4.     SPI_MODE_2 (1,0)         CPOL = 1, CPHA = 0, Clock idle high, data is clocked in on falling edge, output data (change) on rising edge
  5.     SPI_MODE_3 (1,1)         CPOL = 1, CPHA = 1, Clock idle high, data is clocked in on rising, edge output data (change) on falling edge
  6.     spi_mode = SPI_MODE_0;
复制代码
应该为SPI_MODE_2。然而,当我在wiringPi的官网查看reference时却发现只提到有以下两个函数:
  1. int wiringPiSPISetup (int channel, int speed) ;
  2. int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ;
复制代码
并不能设置模式啊!!!这和说好不一样啊,坑爹的wiringPi为毛没有把mode接口留出来呢。不甘心之下就去github上查阅了wiringPiSPI.h的源文件,发现了猫腻:
  1. #ifdef __cplusplus
  2. extern "C" {
  3. #endif

  4. int wiringPiSPIGetFd     (int channel) ;
  5. int wiringPiSPIDataRW    (int channel, unsigned char *data, int len) ;
  6. int wiringPiSPISetupMode (int channel, int speed, int mode) ;
  7. int wiringPiSPISetup     (int channel, int speed) ;

  8. #ifdef __cplusplus
  9. }
  10. #endif
复制代码
原来如此,mode还是可选的,只是作者没有提而已。。再查阅一下wiringPiSPISetup函数原型可知,其默认选择了mode0,所以我们在使用时应该使用wiringPiSPISetupMode函数。
       接下来直接上驱动的核心代码:(参考安富莱提供的8051程序进行移植)
  1. uint8_t ADC_val[CH_NUM * 2];

  2. void AD7606_Init(){
  3.         AD7606_IOSet();
  4.         AD7606_SetDF(0);                 //default:OS2 OS1 OS0 = 000
  5.         AD7606_SetInputRange(0);         //default:range = -5 ~ +5
  6.         AD7606_Reset();
  7. }

  8. //hook function,used to set input range.
  9. void AD7606_SetInputRange(int _ucRange){
  10.         
  11. }
  12. //hook function,used to set digital filter.
  13. void AD7606_SetDF(uint8_t _ucMode){
  14.         
  15. }
  16. //reset function
  17. void AD7606_Reset(){
  18.         digitalWrite(CS , HIGH);
  19.         digitalWrite(CVAB , HIGH);
  20.          /* AD7606 is high level reset,at least 50ns */
  21.         digitalWrite(RST, LOW);
  22.         //delayMicroseconds(1);
  23.         digitalWrite(RST, HIGH);
  24.         //delayMicroseconds(1);
  25.         digitalWrite(RST, LOW);
  26. }

  27. void AD7606_IOSet(){
  28.         pinMode(RST , OUTPUT);
  29.         pinMode(CVAB, OUTPUT);
  30.         pinMode(CS  , OUTPUT);
  31.         pinMode(BUSY, INPUT);
  32.         pullUpDnControl(BUSY, PUD_UP);
  33.         digitalWrite(RST, LOW);
  34.         digitalWrite(CS , HIGH);
  35.         digitalWrite(CVAB , HIGH);
  36. }

  37. void AD7606_StartConv(){
  38.         /* Conv in rising edge,at least 25ns  */
  39.         digitalWrite(CVAB, LOW);
  40.         //delayMicroseconds(1);
  41.         digitalWrite(CVAB, HIGH);
  42. }
  43. //Software Poll
  44. bool AD7606_StartADC(){        
  45.         if (digitalRead(BUSY) == 0){
  46.                 digitalWrite(CS, LOW);
  47.                 if (wiringPiSPIDataRW (SPI_CHANNEL_0, ADC_val, CH_NUM * 2) == -1){
  48.                 printf("SPI failure: %s\n", strerror(errno));
  49.                 }
  50.                 digitalWrite(CS, HIGH);  
  51.                 AD7606_StartConv();                        
  52.                 while(digitalRead(BUSY) == 0);
  53.                 return true;
  54.         }
  55.         else{
  56.                 printf("Value is not ready: %s\n", strerror(errno));
  57.                 return false;
  58.         }
  59. }
复制代码
这里为需要软件控制数字滤波器以及采样范围的留下了两个hook function,可以自己扩展。然后上电的reset函数,根据手册reset的时间不应少于50ns,而Raspberry Pi2的gpio口电平转换最快是4MHz左右,因此无需额外的延时。在AD7606_StartConv函数中进行了采样结果转换开始的操作。根据手册,我将CVA和CVB口并联起来,给一次信号接足够。按照安富莱提供的资料的说法,CVAB最好接到有pwm输出能力的口上,所以我选择了gpio1,不过后来发现没什么特别之处,换成别的口应该也没什么问题。最后就是AD7606_StartADC函数,由于本次的项目需要用到软件查询的方式采样,所以这里我仅仅写了软件查询,没有写中断的方式。根据函数可以知道,采样的第一组数据是无效的。最终的采样结果是8个16位的数,我保存在了一个extern变量
  1. extern uint8_t ADC_val[CH_NUM * 2];
复制代码
中,每个结果占数组的两个位置。因此,在调用AD7606_StartADC()后,从ADC_val数组中即可方便的获得采样结果。
       接下来就是上电实测。使用稳压电源输出3.0000V,稳压电源本身测得输出为3.0037V,万用表测得为3.007V。使用
IMG_1547.JPG

IMG_1545.JPG

AD7606的通道1进行采样,通道2~7接地,通道8悬空,得到如下的测量结果:
IMG_1553.JPG

第一组数据根据驱动文件的驱动方式可知是无效的。观察第二组之后的数据可知采集得到的数据是有效的。至此,驱动完毕。
游客,如果您要查看本帖隐藏内容请回复


回复

使用道具 举报

该用户从未签到

 楼主| 发表于 2016-3-8 22:54:46 | 显示全部楼层
沙发自己坐
回复 支持 反对

使用道具 举报

  • TA的每日心情
    慵懒
    2018-3-29 13:14
  • 签到天数: 20 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2016-3-16 22:05:55 | 显示全部楼层
    看着不错,顺便问一下,最高采样率实际可到多少?
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2016-3-20 10:30:00 | 显示全部楼层
    mark            
    回复 支持 反对

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2016-3-20 19:28:29 | 显示全部楼层
    yu0405jie 发表于 2016-3-16 22:05
    看着不错,顺便问一下,最高采样率实际可到多少?

    应该是可以到200Ksps
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-4-22 16:57
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    发表于 2016-3-31 23:15:19 | 显示全部楼层
    請問,可以附上實際 rpi 連結 ad7606 module 的圖嗎?
    對硬體很不熟悉,希望可以對照著做。
    謝謝~~
    回复 支持 反对

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2016-4-2 12:50:36 | 显示全部楼层
    qqq1234567 发表于 2016-3-31 23:15
    請問,可以附上實際 rpi 連結 ad7606 module 的圖嗎?
    對硬體很不熟悉,希望可以對照著做。
    謝謝~~  ...

    文章中已经给了连接图。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    郁闷
    2016-5-12 17:57
  • 签到天数: 6 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2016-4-11 18:27:35 | 显示全部楼层
    厲害!
    正好需要此類經驗,謝謝!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    郁闷
    2016-5-12 17:57
  • 签到天数: 6 天

    连续签到: 1 天

    [LV.2]偶尔看看I

    发表于 2016-4-15 15:32:52 | 显示全部楼层
    樓主有個問題!

    Raspberry Pi2的GPIO 28,29在哪里?
    你確定有麽?

    GPIO28,29衹有在PI 的Reversion 2.0才有啊!!

    回复 支持 反对

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2016-4-18 11:58:29 | 显示全部楼层
    bajonetty 发表于 2016-4-15 15:32
    樓主有個問題!

    Raspberry Pi2的GPIO 28,29在哪里?

    我用的就是2B+
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

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



    手机版|小黑屋|与非网

    GMT+8, 2024-4-20 07:52 , Processed in 0.204529 second(s), 33 queries , MemCache On.

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

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.