EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
1、 硬件环境 硬件平台: Embest SoC --LarkBoard 软件平台:开发板-linux-3.10.31 Quartus 14.0
6 Y R( o) V; I; ^& h: p' ^$ u
2、系统概述 在上一篇文章已经成功进行了这样的测试,每中断一次,ARM从FPGA的ROM中取一次数据,这边文章主要是测试一下,ADC的数据经过双口RAM传递给ARM的过程,设计框图如下所示:
+ |( q j: o( g+ d1 H. {3、Qsys设计 下图是qsys的设计和连接关系如下图所示: - b" I) b7 t- r
1) 如图所示adc_origin_data挂载在HPS-to-FPGA bridge上,偏移地址为20040000(这个地址是可以任意改动的,注意和驱动对应就行了) 2) 增加了adc_spi_pio的控制接口,实现对ADC的配置和初始化,这个前面的测试中是没有注意的
; Q. f) G! t& i/ }, O+ `
6 ]; Z" |/ N |1 a/ q% V
4、ADC驱动设计 这里测试驱动主要使用了Embest自带的驱动,位于drivers\char\adc9628.c,具体代码可见附件: 这是一个很好的参考用例,实际使用的时候还需要进一步的修改。上面qsys中偏移地址的设置就是为了和驱动相对应的。
7 _# ]! J" v" ~
主要完成以下功能: 1)通过模拟SPI接口完成ADC9628的初始化 - /*
- *init the registers of ADC9628,
- *write to Altera's PIO IP core to operate the gpio as spi pins
- */
- static void bsp_adc_init(struct adc_priv_data *adc_data)
- {
- int iadc_val ;
- 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 */
- mdelay(2);
- iadc_val = ad9628_read(0x1 ); /* chip ID, 0x89 */
- printk(KERN_INFO"current id = %x \n", iadc_val);
- iadc_val = ad9628_read(0x2 ); /* chip grade */
- iadc_val = ad9628_read(0x0b ); /* clock divide */
- iadc_val = 0x0;
- ad9628_write(0x0b, iadc_val);
- iadc_val = ad9628_read(0x0b );
- iadc_val = ad9628_read(0x09 ); /* DUTY stabilty */
- iadc_val = ad9628_read(0x0b ); /* clock ratio */
- ad9628_write(0x05, 0x03); /* Channel a b */
- iadc_val = ad9628_read(0x5 );
- ad9628_write(0x0d, 0x0); /* normal mode */
- iadc_val = ad9628_read(0xd );
- iadc_val = ad9628_read(0x101 );
- iadc_val |= (0x1<<7);
- ad9628_write(0x101, iadc_val);
- iadc_val = ad9628_read(0x101 );
- bsp_adc_cmos();
- iadc_val = ad9628_read(0x14 );
- }
) c! ~! H' r8 F' F9 U/ V 4 R1 y* Z2 w T$ U2 O+ C
5 |, L5 w' v- O. `) n6 \/ h. @7 L* r
2)完成读双口RAM的操作 - static const struct file_operations adc_fops = {
- .read = adc_read,
- .open = adc_open,
- .release = adc_release,
- .owner = THIS_MODULE,
- };! S' x: q8 R( m
+ O' ^# Y& k* X# e2 D
" y0 j) y' Z/ Q
4 j6 i a# V9 g8 Y) @/ S3)把ADC注册成一个char型设备 - static int __init adc9628_init(void)
- {
- dev_t dev = MKDEV(LARK_ADC_MAJOR, 0);
- int ret;
- ret = register_chrdev_region(dev, max_adc_minors, "adc");
- if (ret)
- goto error;
- cdev_init(&adc_cdev, &adc_fops);
- ret = cdev_add(&adc_cdev, dev, max_adc_minors);
- if (ret) {
- goto error_region;
- }
- adc_class = class_create(THIS_MODULE, "adc");
- if (IS_ERR(adc_class)) {
- printk(KERN_ERR "Error creating adc class.\n");
- cdev_del(&adc_cdev);
- ret = PTR_ERR(adc_class);
- goto error_region;
- }
- adc_class->devnode = adc_devnode;
- device_create(adc_class, NULL, MKDEV(LARK_ADC_MAJOR, 0), NULL, "adc");
- if (!request_mem_region(BSP_ADC_ADDR,sizeof(u32),"adc9628")) {
- printk( "Memory region busy\n");
- return -EBUSY;
- }
- gRegbase = ioremap_nocache(BSP_ADC_ADDR, sizeof(u32));
- if(!gRegbase) {
- printk( KERN_INFO" ioremap failed\n");
- return -EIO;
- }
- if (!request_mem_region(BSP_FIFO_BASE,sizeof(u32)*1024,"adc9628_fifo")) {
- printk( KERN_INFO"Memory region busy\n");
- return -EBUSY;
- }
- gFifobase = ioremap_nocache(BSP_FIFO_BASE, sizeof(u32)*1024);
- if(!gFifobase) {
- printk( KERN_INFO" ioremap failed\n");
- return -EIO;
- }
- return 0;
- error_region:
- unregister_chrdev_region(dev, max_adc_minors);
- error:
- return ret;
- }
0 q+ E5 \( H- `. H8 c7 d) y7 N9 Y/ I + n6 _. Y9 |. s/ y; L
: _. @5 S! J G
至此ADC驱动介绍完毕,记得在编译系统的时候把驱动编译进去就行了 ' N0 p- P$ T8 W: {
5、应用程序设计 这里使用的也是Embest提供的测试程序,详细程序可见附件: adc_test.zip (1.62 KB, 下载次数: 88) 测试程序主要完成了FFT计算,我也没有深入的研究,因为并不是我想要的东西,只是用它做个测试吧,有兴趣的自行研究吧,这里就不分析代码了;
' J! o7 |1 z: K! y8 |. G9 ]
$ W& }# X- X0 K& u9 a1 g' J. a
6、测试结果 . w7 D" ~* t4 ~
1) 环境搭建 把信号发生器的两个输出口,分别接ADC9628 的两个输入端,如下图所示: P! O( M+ k) R2 ~: G
. }* c. A/ x6 e1 T, n2)设置信号发生器 2 d+ U5 @. V! S- F; t3 A( K( ~
/ c. m, q5 D4 v! y. F# r2 U, w) r
3)运行测试程序 - root@arm:~/adc# ./adc_test
- current id = 89
- dong fft
- caculate real valule
- 146:chanel0 frequency = 14.970703, amplitude=2185
- 293:chanel1 frequency = 30.043945, amplitude=1806! T* o1 Z. t3 W" y2 w
, Z& f, B$ t% e2 W8 q
- H4 K) y, H% {2 v6 f" R
( g" g4 [: d, C- x/ f/ ?$ B4 }从测试结果看chanel0的频率测量是14.970703Mhz,chanel1的频率测量是30.043945Mhz,和实际设置值相似,且可以按照设定频率进行准确的跟踪,说明数据传输应该没有问题 ! B% R5 }7 v3 i' R9 j' c
7、小结 1) 本次主要测试ADC的采集数据通过双口RAM传递给ARM的过程,测试结果一切正常,为下一步的工作打下了基础; 2)HPS-to-FPGA bridge接口传输的性能还有待进一步的测试,目前优先完成系统设计; 3)下一步准备把前面设计的中断,加入到驱动中去,这样驱动就更加实用了; 4)同时准备移植web服务器,把采集的数据能够在web上进行展示,这方面不擅长,有大侠可帮忙吗?非常感谢! O, L, i& V F
& C# A" d0 R% d% P1 Y7 p. B2 ^3 a, o3 j0 J% j( D$ n5 S
|