[系统相关] 【Altera SoC体验之旅】高速数据采集之数据传输(2)

chenzhufly   2015-4-23 00:18 楼主
【Altera SoC体验之旅】高速数据采集之数据传输(2)
作者:chenzhufly QQ:36886052
1、 硬件环境
硬件平台: Embest SoC --LarkBoard
软件平台:开发板-linux-3.10.31
Quartus 14.0
2、系统概述
在上一篇文章已经成功进行了这样的测试,每中断一次,ARM从FPGA的ROM中取一次数据,这边文章主要是测试一下,ADC的数据经过双口RAM传递给ARM的过程,设计框图如下所示:
框图.png
3、Qsys设计
下图是qsys的设计和连接关系如下图所示:
qsys-ram.png
1) 如图所示adc_origin_data挂载在HPS-to-FPGA bridge上,偏移地址为20040000(这个地址是可以任意改动的,注意和驱动对应就行了)
2) 增加了adc_spi_pio的控制接口,实现对ADC的配置和初始化,这个前面的测试中是没有注意的
quartus工程文件见附件:
test-irq.zip (6.93 MB)
(下载次数: 236, 2015-4-23 00:20 上传)
4、ADC驱动设计
这里测试驱动主要使用了Embest自带的驱动,位于drivers\char\adc9628.c,具体代码可见附件:
adc9628.zip (2.27 KB)
(下载次数: 119, 2015-4-22 23:52 上传)
这是一个很好的参考用例,实际使用的时候还需要进一步的修改。上面qsys中偏移地址的设置就是为了和驱动相对应的。
主要完成以下功能:
1)通过模拟SPI接口完成ADC9628的初始化
  1. /*
  2. *init the registers of ADC9628,
  3. *write to Altera's PIO IP core to operate the gpio as spi pins
  4. */
  5. static void bsp_adc_init(struct adc_priv_data *adc_data)
  6. {
  7. int iadc_val ;
  8. writew( 0x7,adc_data->regbase + (0x1*4)); /* pio_dir = 0x7 */
  9. writew( 0x6,adc_data->regbase + (0x4*4)); /* cs = 1 */
  10. writew( 0x2,adc_data->regbase + (0x4*4)); /* sclk=0 */
  11. mdelay(2);
  12. iadc_val = ad9628_read(0x1 ); /* chip ID, 0x89 */
  13. printk(KERN_INFO"current id = %x \n", iadc_val);
  14. iadc_val = ad9628_read(0x2 ); /* chip grade */
  15. iadc_val = ad9628_read(0x0b ); /* clock divide */
  16. iadc_val = 0x0;
  17. ad9628_write(0x0b, iadc_val);
  18. iadc_val = ad9628_read(0x0b );
  19. iadc_val = ad9628_read(0x09 ); /* DUTY stabilty */
  20. iadc_val = ad9628_read(0x0b ); /* clock ratio */
  21. ad9628_write(0x05, 0x03); /* Channel a b */
  22. iadc_val = ad9628_read(0x5 );
  23. ad9628_write(0x0d, 0x0); /* normal mode */
  24. iadc_val = ad9628_read(0xd );
  25. iadc_val = ad9628_read(0x101 );
  26. iadc_val |= (0x1<<7);
  27. ad9628_write(0x101, iadc_val);
  28. iadc_val = ad9628_read(0x101 );
  29. bsp_adc_cmos();
  30. iadc_val = ad9628_read(0x14 );
  31. }
2)完成读双口RAM的操作
  1. static const struct file_operations adc_fops = {
  2. .read = adc_read,
  3. .open = adc_open,
  4. .release = adc_release,
  5. .owner = THIS_MODULE,
  6. };
3)把ADC注册成一个char型设备
  1. static int __init adc9628_init(void)
  2. {
  3. dev_t dev = MKDEV(LARK_ADC_MAJOR, 0);
  4. int ret;
  5. ret = register_chrdev_region(dev, max_adc_minors, "adc");
  6. if (ret)
  7. goto error;
  8. cdev_init(&adc_cdev, &adc_fops);
  9. ret = cdev_add(&adc_cdev, dev, max_adc_minors);
  10. if (ret) {
  11. goto error_region;
  12. }
  13. adc_class = class_create(THIS_MODULE, "adc");
  14. if (IS_ERR(adc_class)) {
  15. printk(KERN_ERR "Error creating adc class.\n");
  16. cdev_del(&adc_cdev);
  17. ret = PTR_ERR(adc_class);
  18. goto error_region;
  19. }
  20. adc_class->devnode = adc_devnode;
  21. device_create(adc_class, NULL, MKDEV(LARK_ADC_MAJOR, 0), NULL, "adc");
  22. if (!request_mem_region(BSP_ADC_ADDR,sizeof(u32),"adc9628")) {
  23. printk( "Memory region busy\n");
  24. return -EBUSY;
  25. }
  26. gRegbase = ioremap_nocache(BSP_ADC_ADDR, sizeof(u32));
  27. if(!gRegbase) {
  28. printk( KERN_INFO" ioremap failed\n");
  29. return -EIO;
  30. }
  31. if (!request_mem_region(BSP_FIFO_BASE,sizeof(u32)*1024,"adc9628_fifo")) {
  32. printk( KERN_INFO"Memory region busy\n");
  33. return -EBUSY;
  34. }
  35. gFifobase = ioremap_nocache(BSP_FIFO_BASE, sizeof(u32)*1024);
  36. if(!gFifobase) {
  37. printk( KERN_INFO" ioremap failed\n");
  38. return -EIO;
  39. }
  40. return 0;
  41. error_region:
  42. unregister_chrdev_region(dev, max_adc_minors);
  43. error:
  44. return ret;
  45. }
至此ADC驱动介绍完毕,记得在编译系统的时候把驱动编译进去就行了
5、应用程序设计
这里使用的也是Embest提供的测试程序,详细程序可见附件:
adc_test.zip (1.62 KB)
(下载次数: 92, 2015-4-23 00:01 上传)
测试程序主要完成了FFT计算,我也没有深入的研究,因为并不是我想要的东西,只是用它做个测试吧,有兴趣的自行研究吧,这里就不分析代码了;
6、测试结果
1) 环境搭建
把信号发生器的两个输出口,分别接ADC9628 的两个输入端,如下图所示:
1.png
2)设置信号发生器
2.jpg 3.jpg
3)运行测试程序
  1. root@arm:~/adc# ./adc_test
  2. current id = 89
  3. dong fft
  4. caculate real valule
  5. 146:chanel0 frequency = 14.970703, amplitude=2185
  6. 293:chanel1 frequency = 30.043945, amplitude=1806
从测试结果看chanel0的频率测量是14.970703Mhz,chanel1的频率测量是30.043945Mhz,和实际设置值相似,且可以按照设定频率进行准确的跟踪,说明数据传输应该没有问题
7、小结
1) 本次主要测试ADC的采集数据通过双口RAM传递给ARM的过程,测试结果一切正常,为下一步的工作打下了基础;
2)HPS-to-FPGA bridge接口传输的性能还有待进一步的测试,目前优先完成系统设计;
3)下一步准备把前面设计的中断,加入到驱动中去,这样驱动就更加实用了;
4)同时准备移植web服务器,把采集的数据能够在web上进行展示,这方面不擅长,有大侠可帮忙吗?非常感谢!
本帖最后由 chenzhufly 于 2015-4-23 00:20 编辑
生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙 =================================== 做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰

回复评论 (17)

这么高端,很是羡慕。
虾扯蛋,蛋扯虾,虾扯蛋扯虾
点赞  2015-4-23 08:31
有点厉害。。。
分享铸就美好未来。。。
点赞  2015-4-23 11:10
不厉害哦 比较简单的
刚学比较苦逼点
生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙 =================================== 做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰
点赞  2015-4-23 11:33
你好,我看你的代码中 给AD的105M的时钟信号怎么只分配了P端 没有分配N端呢
点赞  2015-11-3 11:23
引用: hunansunjianjun 发表于 2015-11-3 11:23
你好,我看你的代码中 给AD的105M的时钟信号怎么只分配了P端 没有分配N端呢

哦 原来只要分配P就行,N会自动分配。哎 好久没用ALTERA的器件了
点赞  2015-11-3 11:31
一口气看完了楼主的几篇文章,深受启发,感谢!!
点赞  2016-2-25 22:54
有点厉害。。。
点赞  2016-3-18 09:35
楼主辛苦,
先顶
以后要细细看
MicroPython中文社区https://micropython.org.cn/forum/  
点赞  2016-5-6 15:24
很高的采样频率a
点赞  2016-6-17 19:02
确实很有用,找了官网资料,一直没找到h2f控制部分的,api说明也没找到,这次总算有些启示了
点赞  2016-6-21 08:00
想问下 楼主是用什么编译程序的?DS-5吗?
点赞  2016-7-10 18:35
点赞  2017-3-21 14:29
引用: chenzhufly 发表于 2015-4-23 11:33
不厉害哦 比较简单的
刚学比较苦逼点

楼主,你看了你发的adc驱动,有些问题想请教下。bsp_adc_init()函数中
writew( 0x7,adc_data->regbase + (0x1*4));                                                 /* pio_dir = 0x7 */
writew( 0x6,adc_data->regbase + (0x4*4));                                                 /* cs = 1  */
writew( 0x2,adc_data->regbase + (0x4*4));                                                 /* sclk=0 */

对于(0x1*4), (0x4*4),(0x4*4)写了对应值,是什么意思呢? (0x1*4),(0x4*4), (0x4*4)是怎么来的呢?
点赞  2017-4-21 17:35
哦 原来只要分配P就行,N会自动分配。哎 好久没用ALTERA的器件了
哦 原来只要分配P就行,N会自动分配。哎 好久没用ALTERA的器件了
点赞  2017-10-16 14:55
谢谢楼主
点赞  2017-10-24 15:32
这么高端,很是羡慕。
点赞  2018-2-11 20:51

下来看看

点赞  2021-7-8 14:00
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复