[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_SDK高级篇连载-08DAQ7606 波形显示方案(DMA+VDMA)

文档创建者:FPGA课程
浏览次数:144
最后更新:2024-09-30
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-SOC » 1_SDK应用方案(仅旗舰型号) » 2-SDK高级应用方案
本帖最后由 FPGA课程 于 2024-9-30 11:23 编辑

​ 软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!



1概述
DAQ001是一款8通道16bit 200k采样率的高精度ADC,支持串行和并行采集接口。米联客DAQ001采用串行模式实现200K 8通道同时采样,相比并口方式,串行方式,具有硬件接口简单,节约成本优势。
实验目的:
1:掌握ui_axisbufw配置成非视频模式的情况下的参数设置
2:掌握ADC数据如何通过ui_axisbufw写入到AXI-DMA IP
3:掌握AXI-DMA IP中断的产生方法,以及AXIS时序接口
4:编写波形显示函数,把采集到的波形绘制成波形曲线在显示器上显示
2系统框图
dfd979f45dc04190ad66886ca343c8f2.jpg
3硬件电路分析
硬件接口和子卡模块请阅读“附录1”
配套工程的FPGA PIN脚定义路径为soc_prj/uisrc/04_pin/ fpga_pin.xdc。
4搭建SOC系统工程
4.1PL图形化编程
26a482047ded4467a2aac4e81f4585f4.jpg ​​
以上代码中用户数据位宽为128bit(daq001是8通道16bit 所以是128bit位宽), 用户写入的数据经过ui_axisbufw后进入axi-dma,之后通过AXI_interconnect 进入到ZYNQ DDR中。
SDK代码中,PS(ARM)读取内存中保存的ADC采样数值,并且通过插值方式绘制波形,波形先绘制到内存中,HDMI驱动从这个开辟的波形显存中主动读取数据,显示到显示器上。这样就完成了波形采集显示方案。
下面具体看下关键几个IP的参数设置
1:ui_axisbufw设置
VIVADO_ENABLE:用于设置时序需要支持视频帧同步功能,对于数据流模式设置为0
AXI_DATA_WIDTH:用于设置AXI-Stream数据接口的位宽,这里设置128
W_BUFDEPTH:用于设置FIFO的深度,越大消耗资源越多,这里设置2048
W_XSIZE和W_YSIZE:配合可以一次DMA完成大量数据传输,而不需要太多的FIFO,并且通过W_XSIZE和W_YSIZE合理设置既可以满足速度要求,又可以减少FIFO使用。比如这里设置1024*64也可以设置512*128当设置512*128,那么FIFO就可以设置最大1024足够使用了。
通过这些参数设置,可以看出来,我们一次DMA完成1024*64*128/8=1MB数据传输,也就是8个通道每个通道,完成采集了64K的波形点采集。
afe355efae6b470db1b82ada087dea12.jpg
2:AXI-DMA设置
其中关键参数是设置合适的Width of Buffer Length Register 大小为23bit 代表最大DMA可以支持2^23=8MB数据,足够使用。
另外我们只用到写通道,所以只勾选写通道即可。
6a61ec6c868043d1b949c68e463df884.jpg
3:修改system_wrapper.v
将自动产生的system_wrapper.v复制到本方案工程路径soc_prj/uisrc/01_rtl/system_wrapper.v并对其修改,修改好的代码如下:
  1. `timescale 1ns / 1ps
  2. /*******************************MILIANKE*******************************
  3. *Company : MiLianKe Electronic Technology Co., Ltd.
  4. *WebSite:https://www.milianke.com
  5. *TechWeb:https://www.uisrc.com
  6. *tmall-shop:https://milianke.tmall.com
  7. *jd-shop:https://milianke.jd.com
  8. *taobao-shop1: https://milianke.taobao.com
  9. *Create Date: 2021/10/15
  10. *Module Name:system_wrapper
  11. *File Name:system_wrapper.v
  12. *Description:
  13. *The reference demo provided by Milianke is only used for learning.
  14. *We cannot ensure that the demo itself is free of bugs, so users
  15. *should be responsible for the technical problems and consequences
  16. *caused by the use of their own products.
  17. *Copyright: Copyright (c) MiLianKe
  18. *All rights reserved.
  19. *Revision: 1.0
  20. *Signal description
  21. *1) _i input
  22. *2) _o output
  23. *3) _n activ low
  24. *4) _dg debug signal
  25. *5) _r delay or register
  26. *6) _s state mechine
  27. *********************************************************************/
  28. module system_wrapper(
  29. inout wire [14:0]DDR_addr,
  30. inout wire [2:0]DDR_ba,
  31. inout wire DDR_cas_n,
  32. inout wire DDR_ck_n,
  33. inout wire DDR_ck_p,
  34. inout wire DDR_cke,
  35. inout wire DDR_cs_n,
  36. inout wire [3:0]DDR_dm,
  37. inout wire [31:0]DDR_dq,
  38. inout wire [3:0]DDR_dqs_n,
  39. inout wire [3:0]DDR_dqs_p,
  40. inout wire DDR_odt,
  41. inout wire DDR_ras_n,
  42. inout wire DDR_reset_n,
  43. inout wire DDR_we_n,
  44. inout wire FIXED_IO_ddr_vrn,
  45. inout wire FIXED_IO_ddr_vrp,
  46. inout wire [53:0]FIXED_IO_mio,
  47. inout wire FIXED_IO_ps_clk,
  48. inout wire FIXED_IO_ps_porb,
  49. inout wire FIXED_IO_ps_srstb,
  50. //******************************
  51. output wire hdmi_tx_0_tmds_clk_n,
  52. output wire hdmi_tx_0_tmds_clk_p,
  53. output wire [2:0]hdmi_tx_0_tmds_data_n,
  54. output wire [2:0]hdmi_tx_0_tmds_data_p,
  55. /***********************daq001******************************/               
  56. input  wire ad7606_busy_i,
  57. output wire ad7606_cs_o,        //ad7606 AD cs
  58. output wire ad7606_sclk_o,      //ad7606 AD data read
  59. output wire ad7606_rst_o,       //ad7606 AD reset
  60. output wire ad7606_convsta_o,   //ad7606 AD convert start
  61. output wire ad7606_convstb_o,   //ad7606 AD convert start   
  62. output wire ad7606_range_o,
  63. input  wire ad7606_out_a_i,
  64. input  wire ad7606_out_b_i,
  65. output wire ad7606card_en
  66. );
  67. assign      ad7606card_en=1'b1;
  68. wire        user_rstn;
  69. wire        user_start;
  70. wire        pl_clk0;
  71. reg  [15:0] test_data;
  72. wire ad7606_cap_en;
  73. wire [63:0] ad7606_out_a,ad7606_out_b;
  74. wire [15:0] ad_ch0,ad_ch1,ad_ch2,ad_ch3,ad_ch4,ad_ch5,ad_ch6,ad_ch7;
  75. //sensor input -W_FIFO--------------
  76. wire                 W_wclk_i = pl_clk0;
  77. wire                 W_FS_i   = user_start;
  78. wire                 W_wren_i = ad7606_cap_en && user_start;
  79. wire    [127: 0]     W_data_i = {test_data,ad_ch6,ad_ch5,ad_ch4,ad_ch3,ad_ch2,ad_ch1,ad_ch0};
  80. //----------axis signals write-------         
  81. wire                 axis_clk =pl_clk0;                           
  82. wire    [127: 0]     axis_wdata;
  83. wire                 axis_wvalid;
  84. wire                 axis_wready;
  85. wire                 axis_last;
  86. always @(posedge W_wclk_i)begin
  87.     if(user_rstn == 1'b0)
  88.         test_data <= 0;
  89.     else if(W_wren_i)
  90.         test_data <= test_data + 1'b1;
  91. end
  92. assign ad_ch0 = ad7606_out_a[63:48];
  93. assign ad_ch1 = ad7606_out_a[47:32];
  94. assign ad_ch2 = ad7606_out_a[31:16];
  95. assign ad_ch3 = ad7606_out_a[15: 0];
  96. assign ad_ch4 = ad7606_out_b[63:48];
  97. assign ad_ch5 = ad7606_out_b[47:32];
  98. assign ad_ch6 = ad7606_out_b[31:16];
  99. assign ad_ch7 = ad7606_out_b[15: 0];
  100. /***********************调用daq001 IP这里采用了SPI接口********************/   
  101. uispi7606#(
  102. .SPI_DIV(10'd5),
  103. .T5US_DIV(10'd499)
  104. )
  105. uispi7606_inst
  106. (
  107. .ad_clk_i(pl_clk0),            
  108. .ad_rst_i(user_rstn==1'b0),
  109. .ad_busy_i(ad7606_busy_i),                  
  110. .ad_cs_o(ad7606_cs_o),
  111. .ad_sclk_o(ad7606_sclk_o),      
  112. .ad_rst_o(ad7606_rst_o),         
  113. .ad_convsta_o(ad7606_convsta_o),      
  114. .ad_convstb_o(ad7606_convstb_o),  
  115. .ad_range_o(ad7606_range_o),
  116. .ad_out_a_i(ad7606_out_a_i),
  117. .ad_out_b_i(ad7606_out_b_i),
  118. .ad_out_a(ad7606_out_a),
  119. .ad_out_b(ad7606_out_b),
  120. .ad_cap_en(ad7606_cap_en)
  121. );

  122.    
  123. ila_0 ila_debug (
  124. .clk(pl_clk0), // input wire cl
  125. .probe0({ad7606_cap_en,user_rstn,user_start}), // input wire [15:0]  probe0  
  126. .probe1({test_data,ad_ch6,ad_ch5,ad_ch4,ad_ch3,ad_ch2,ad_ch1,ad_ch0})                  
  127. );  
  128. /***********************
  129. 一次DMA传输128*1024*64 字节大小的数据
  130. **************************/   
  131. ui_axisbufw#(
  132. .VIDEO_ENABLE(0),  
  133. .AXI_DATA_WIDTH(128),
  134. .W_BUFDEPTH(2048),
  135. .W_DATAWIDTH(128),
  136. .W_XSIZE(1024),
  137. .W_YSIZE(64)
  138. )
  139. ui_axisbufw_inst
  140. (
  141. .ui_rstn(user_rstn),
  142. //sensor input -W_FIFO--------------
  143. .W_wclk_i(W_wclk_i),
  144. .W_FS_i(W_FS_i),
  145. .W_wren_i(W_wren_i),
  146. .W_data_i(W_data_i),
  147. //----------axis signals write-------         
  148. .axis_clk(axis_clk),                              
  149. .axis_wdata(axis_wdata),
  150. .axis_wvalid(axis_wvalid),
  151. .axis_wready(axis_wready),
  152. .axis_last(axis_last)
  153. );  
  154. system system_i
  155. (
  156. .DDR_addr(DDR_addr),
  157. .DDR_ba(DDR_ba),
  158. .DDR_cas_n(DDR_cas_n),
  159. .DDR_ck_n(DDR_ck_n),
  160. .DDR_ck_p(DDR_ck_p),
  161. .DDR_cke(DDR_cke),
  162. .DDR_cs_n(DDR_cs_n),
  163. .DDR_dm(DDR_dm),
  164. .DDR_dq(DDR_dq),
  165. .DDR_dqs_n(DDR_dqs_n),
  166. .DDR_dqs_p(DDR_dqs_p),
  167. .DDR_odt(DDR_odt),
  168. .DDR_ras_n(DDR_ras_n),
  169. .DDR_reset_n(DDR_reset_n),
  170. .DDR_we_n(DDR_we_n),
  171. .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
  172. .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
  173. .FIXED_IO_mio(FIXED_IO_mio),
  174. .FIXED_IO_ps_clk(FIXED_IO_ps_clk),
  175. .FIXED_IO_ps_porb(FIXED_IO_ps_porb),
  176. .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
  177. .hdmi_tx_0_tmds_clk_n(hdmi_tx_0_tmds_clk_n),
  178. .hdmi_tx_0_tmds_clk_p(hdmi_tx_0_tmds_clk_p),
  179. .hdmi_tx_0_tmds_data_n(hdmi_tx_0_tmds_data_n),
  180. .hdmi_tx_0_tmds_data_p(hdmi_tx_0_tmds_data_p),
  181. .S_AXIS_S2MM_0_tdata(axis_wdata),
  182. .S_AXIS_S2MM_0_tkeep(16'hffff),
  183. .S_AXIS_S2MM_0_tlast(axis_last),
  184. .S_AXIS_S2MM_0_tready(axis_wready),
  185. .S_AXIS_S2MM_0_tvalid(axis_wvalid),
  186. .pl_clk(pl_clk0),
  187. .user_rstn(user_rstn),
  188. .user_start(user_start)
  189. );
  190.         
  191. endmodule
复制代码

以上代码中,调用了米联客uispi7606 IP CORE采集模拟数据,并且把采集好的数据写入到ui_axisbufw中,为了方便实验中观察数据,把第八个通道的AD数据改成了计数器。实际项目中可以把这个替换成第八个通道的ADC数据。
4.2设置地址分配
需要注意axi-lite接口地址,这个地址我们会在SDK 代码中使用AXI-GPIO控制传输的复位和启动。
94787e215a5b4087b782d524d159d349.jpg
4.3添加PIN约束
1:选中PROJECT  MANAGERà Add SourcesàAdd or create constraints,添加XDC约束文件。
62509d9610214d08a6ff36e2e34a1be6.jpg
2:打开提供例程,复制约束文件中的管脚约束到XDC文件,或者查看原理图,自行添加管脚约束,并保存。
以下是添加配套工程路径下已经提供的pin脚文件。配套工程的pin脚约束文件在uisrc/04_pin路径
4.4编译并导出平台文件
1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。
2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。
3:生成Bit文件。
4:导出到硬件: FileàExport HardwareàInclude bitstream
5:导出完成后,对应工程路径的soc_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
873dc18eb36b4070adc10ad1ea715325.jpg
5搭建Vitis-sdk工程
创建soc_base sdk platform和APP工程的过程不再重复,如果不清楚请参考本章节第一个demo。
5.1创建SDK Platform工程
30416bc6221242a4bdfa49803c7d9c54.jpg
5.2创建daq001_dma_wave工程
6305fed4708b4273a8d8239711d18699.jpg
6程序分析
6.1DMA数据获取原理
f7072d0348cc4c80b361de13418caeb4.jpg
每当AXI-DMA发送的中断后,DMA中断函数被调用。
1:PS_RX_intr_Handler
  1. static void DMA_RxIntrHandler(void *Callback)
  2. {
  3.         u32 IrqStatus;
  4.         u32 Status;
  5.         XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
  6.         /* Read pending interrupts */
  7.         IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);
  8.         /* Acknowledge pending interrupts */
  9.         XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
  10.         /*
  11.          * If no interrupt is asserted, we do not do anything
  12.          */
  13.         if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
  14.                 return;
  15.         }
  16.         /*
  17.          * If error interrupt is asserted, raise error flag, reset the
  18.          * hardware to recover from the error, and return with no further
  19.          * processing.
  20.          */
  21.         if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
  22.                 xil_printf("rx error! \r\n");
  23.                 return;
  24.         }
  25.         /*
  26.          * If completion interrupt is asserted, then set RxDone flag
  27.          */
  28.         if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
  29.         /*
  30.          * 这里设计了一种环形结构的缓存处理方式
  31.          */
  32.                 if(fdma_buf.circle_cnt<2)
  33.                 {
  34.                                 fdma_buf.circle_cnt ++ ;
  35.                                 fdma_buf.next = fdma_buf.circle_cnt -1;
  36.                 }
  37.                 else
  38.                 {
  39.                                 fdma_buf.circle_cnt = 0;
  40.                                 fdma_buf.next = 2;
  41.                 }
  42.                         Status = XAxiDma_SimpleTransfer(&AxiDma, (UINTPTR)RxBufAddr[fdma_buf.circle_cnt],DMA_DATA_SIZE, XAXIDMA_DEVICE_TO_DMA);
  43.                         if (Status != XST_SUCCESS)
  44.                         {
  45.                                 xil_printf("axi dma failed! 0 %d\r\n", Status);
  46.                         }
  47.                         fdma_buf.pkg_done=1; //fdma_buf.pkg_done 代表了当前DMA传输完毕
  48.         }
  49. }
复制代码

2:fdma_buf_st结构体
  1. typedef struct fdma_buf_st
  2. {
  3.         u8  record[16];//用于记录被标记的内存号
  4.         u8  circle_cnt;//环形计数器
  5.         u8  next;//指向下一个需要被读取的内存号
  6.         u8  pkg_done; //代表数据已经被接收
  7.         u16 fram_cnt; //帧计数器,记录当前的帧号,用于统计
  8.         u16 pkg_cnt; //包计数器,为了均衡CPU负载,可以把一包大数据分成多个小数据操作
  9. }fdma_buf_st;
复制代码

3:FdmaAdcWave函数
以下程序中,核心部分除了波形绘制部分,重点是数据的获取方式。当中断到来pkg_done=1,这里把1MB数据分成64份,这样每份代表8个通道的1024个数据采样点,把这个1024个数据点在内存中绘制波形。
  1. int FdmaAdcWave(u32 WaveWidth, u8 *ScreenFrame)
  2. {
  3.         int i,j ;
  4.         RxBufAddr[0] =RX_BUFFER0_BASE; /*设置第一帧起始地址 */
  5.         RxBufAddr[1] =RX_BUFFER1_BASE; /*设置第二帧起始地址*/
  6.         RxBufAddr[2] =RX_BUFFER2_BASE; /*设置第三帧起始地址*/
  7.         InitPen();
  8.         DrawGrids(WaveWidth, WAVE_HEIGHT,GridBuf) ;/* 调用绘制栅格函数,绘制栅格 */
  9.         while(1) {
  10.                         if(fdma_buf.pkg_done == 1) //adc=16bit*8  total_data_size=16bits*8*2048*32 divide in to 64 times as each time 16bits*8*1024
  11.                 {
  12.                         fdma_buf.pkg_done =0;
  13.                         while(fdma_buf.pkg_cnt<64) //分成64份,每次取8*2*1024大小的数据。
  14.                         {
  15.                                 if(fdma_buf.pkg_cnt==0)
  16.                                 {
  17.                                         BufStartPtr = (u16*)(RxBufAddr[fdma_buf.record[fdma_buf.next]]);//get new buffer address
  18.                                         Xil_DCacheInvalidateRange((u32)BufStartPtr, PKG_SIZE);
  19.                                 }
  20.                                 else
  21.                                 {
  22.                                         BufStartPtr = BufStartPtr + PKG_SIZE/2; //指针16位指针BufStartPtr,注意地址的计算方式
  23.                                         Xil_DCacheInvalidateRange((u32)BufStartPtr, PKG_SIZE);
  24.                                 }
  25.                                 for(i = 0; i < 8 ; i++)//重新排列ADC的数据
  26.                                 {
  27.                                         for(j = 0 ; j < WaveWidth ; j++)
  28.                                         {
  29.                                                 DBufTmp[i][j] = BufStartPtr[8*j + i] ;
  30.                                         }
  31.                                 }
  32.                                 memcpy(WaveBuf, GridBuf, WAVE_HSIZE*WAVE_HEIGHT*PIXEL_BYTES) ;/* 复制之前的栅格到内存*/
  33.                                 for(i = 0; i < 8 ; i++)/* Wave Overlay */
  34.                                 {
  35.                                         DrawLine(WaveWidth, WAVE_HEIGHT, (void *)DBufTmp[i], WaveBuf, i); /* 在栅格背景上绘制波形*/
  36.                                 }
  37.                                 /* 内存中的波形复制VDMA显存 */
  38.                                 ImgCopy(WaveWidth, WAVE_HEIGHT, WAVE_STRIDE, WAVE_OFFSET_X, WAVE_OFFSET_Y, ScreenFrame,  WaveBuf) ;
  39.                                 fdma_buf.pkg_cnt++;
  40.                         }
  41.                         fdma_buf.pkg_cnt = 0;
  42.                         fdma_buf.fram_cnt++;
  43.                         //usleep(100) ;/* sleep 100ms */
  44.                 }        }
  45. }
复制代码

6.2波形绘制原理
1:栅格绘制函数
  1. void DrawGrids(u32 ImgWidth, u32 ImgHeight, u8 *ImgBufPtr)
  2. {
  3.         PEN pen;
  4.         u32 pixel_x, pixel_y;
  5.         for(pixel_y = 0; pixel_y < ImgHeight; pixel_y++)
  6.         {
  7.                 for(pixel_x = 0; pixel_x < ImgWidth; pixel_x++)
  8.                 {
  9.                         if (((pixel_y == 0 || (pixel_y+1)%64 == 0) && (pixel_x == 0 || (pixel_x+1)%8 == 0)) || ((pixel_x == 0 || (pixel_x+1)%64 == 0) && (pixel_y+1)%8 == 0))
  10.                         {
  11.                                 /* gray point */
  12.                                 pen.Red = 150;
  13.                                 pen.Green = 150;
  14.                                 pen.Blue = 150;
  15.                         }
  16.                         else
  17.                         {
  18.                                 /* Black point*/
  19.                                 pen.Red = 0;
  20.                                 pen.Green = 0;
  21.                                 pen.Blue = 0;
  22.                         }
  23.                         DrawPoint(ImgBufPtr, pixel_x, pixel_y, ImgWidth,pen);
  24.                 }
  25.         }
  26. }
复制代码

((pixel_y == 0 || (pixel_y+1)%64 == 0) && (pixel_x == 0 || (pixel_x+1)%8 == 0)),Y方向每间隔64个像素点,绘制水平线,水平虚线间距8个像素点。
(pixel_x+1)%8 == 0)) || ((pixel_x == 0 || (pixel_x+1)%64 == 0) && (pixel_y+1)%8 == 0),X方向每间隔64个像素点,绘制垂直虚线,垂直虚线间距8个像素点。
2:描点函数

  1. void DrawPoint(u8 *ImgBufPtr, u32 pixel_x, u32 pixel_y, u32 ImgWidth, PEN pen)
  2. {
  3.         ImgBufPtr[(pixel_x + pixel_y*ImgWidth)*PIXEL_BYTES + 0] = pen.Red;
  4.         ImgBufPtr[(pixel_x + pixel_y*ImgWidth)*PIXEL_BYTES + 1] = pen.Green;
  5.         ImgBufPtr[(pixel_x + pixel_y*ImgWidth)*PIXEL_BYTES + 2] = pen.Blue;
  6.         ImgBufPtr[(pixel_x + pixel_y*ImgWidth)*PIXEL_BYTES + 3] = 0xff;
  7. }
复制代码

3:绘制波形函数
  1. void DrawLine(u32 ImgWidth, u32 ImgHeight,  void *BufPtr, u8 *ImgBufPtr,u8 color)
  2. {
  3.         u8 last_y ,curr_y ;
  4.         u32 i,j ;
  5.         short *PointBufPtr ;//adc one point need 16bit
  6.         //For 16bit signed AD, the range is -32,768~+32,767
  7.         float tmp = 1.00/256 ;//tmp value use to Divide ad by 256
  8.         PointBufPtr = (short *)BufPtr ;
  9.         /*
  10.          * For signed AD, in order to display the waveform normally,
  11.          * just re-adjust the center position to make all the data become positive.
  12.          * For example, if it is an 8-bits signed number, then mid_offset=64 for a 16-bits signed number mid_offset=128
  13.          * */
  14.         u8 ymid_offset = 128;//ad7606 is 16-bits signed value
  15.         for(i = 0; i < ImgWidth ; i++)
  16.         {
  17.                 if (i == 0)
  18.                 {
  19.                         last_y = (u8)((u16)(PointBufPtr[i])*tmp + ymid_offset) ;
  20.                         curr_y = (u8)((u16)(PointBufPtr[i])*tmp + ymid_offset) ;
  21.                 }
  22.                 else
  23.                 {
  24.                         last_y = (u8)((u16)(PointBufPtr[i-1])*tmp + ymid_offset) ;
  25.                         curr_y = (u8)((u16)(PointBufPtr[i]  )*tmp + ymid_offset) ;
  26.                 }
  27.                 if (curr_y >= last_y)
  28.                 {
  29.                         for (j = 0 ; j < (curr_y - last_y + 1) ; j++)
  30.                                 DrawPoint(ImgBufPtr, i, (ImgHeight - 1 - curr_y) + j, ImgWidth, pen[color]) ;
  31.                 }
  32.                 else
  33.                 {
  34.                         for (j = 0 ; j < (last_y - curr_y + 1) ; j++)
  35.                                 DrawPoint(ImgBufPtr, i, (ImgHeight - 1 - last_y) + j, ImgWidth, pen[color]) ;
  36.                 }
  37.         }
  38. }
复制代码

4:复制波形到显存
  1. void ImgCopy(u32 ImgWidth, u32 ImgHeight, u32 ImgStride, int OffSetX, int OffSetY, u8 *ImgFrame, u8 *ImgBufPtr)
  2. {
  3.         int i ;
  4.         u32 ImgSrcOffset;
  5.         u32 FramDestOffset ;
  6.         u32 CopyLineLen = ImgWidth*PIXEL_BYTES ;
  7.         for(i = 0 ; i < ImgHeight;  i++)
  8.         {
  9.                 ImgSrcOffset = i*ImgWidth*PIXEL_BYTES ;
  10.                 FramDestOffset = (OffSetY+i)*ImgStride + OffSetX*PIXEL_BYTES ;
  11.                 memcpy(ImgFrame+FramDestOffset, ImgBufPtr+ImgSrcOffset, CopyLineLen) ;
  12.         }
  13.         Xil_DCacheFlushRange((INTPTR) ImgFrame+OffSetY*ImgStride, ImgHeight*ImgStride) ;
  14. }
复制代码


以上函数负责把绘制好再内存中的波形数据复制到VDMA的视频缓存中,其中OffSetX 和OffSetY参数用于控制绘制波形在屏幕中的位置。
2c64e702d382466db043c82827fa6c48.jpg
7方案演示

7.1硬件准备
dec9546379e04d52bec4299008d5e974.jpg
7.2实验结果

22fd5252e2db418aa83869fe2e5c9962.jpg






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

本版积分规则