cuter

Vivado HLS何去何从?——近日的一些尝试

1
阅读(27828)

Vivado HLS何去何从?

——近日的一些尝试

如何更好的利用vivado hls是我近期一直在思考的问题。是不是一般的c程序都能很好的转换为IP核?应用的限制在哪里?hls更适合用来做什么?


带着这些疑问,做了以下一些尝试:

1、尝试使用hls实现zedboard oled的驱动

看过我之前博客的朋友会知道,我在zedboard oled上花过一些功夫。值得高兴的是,我之前的方案已经被不少网友用到自己的设计当中。虽然如此,我一直觉得用纯软件的方式来驱动oled效率太低。有网友提出以PL为核心的驱动方式,由于这种方案需要将显示内容预存储在PL的ROM中,所以很不灵活。比较好的方案还是要ps+pl配合实现的,用双口ram或者ddr做oled的显存,ps负责显示内容控制,pl负责oled的刷新、显示。虽然一直心存改进的念头,但是由于种种原因,一直没有动手。

这次借着hls的东风,想尝试把之前的驱动程序稍作修改,修改成hls能够直接综合的代码,然后做成IP,从而使读写时序均由pl完成。目前为止,还没有令人振奋的成果。

这里把所做的设计放出来,希望感兴趣的网友能够一起研究讨论,能获得官方高手的指点就更好了。

首先是代码对比:

arm c代码为:


//更新显存到LCD void OLED_Refresh_Gram(void) { u8 i,n; for(i=0;i<8;i++) { write_cmd (0xb0+i); //设置页地址(0~7) write_cmd (0x02); //设置显示位置—列低地址,偏移了2列 write_cmd (0x10); //设置显示位置—列高地址 for(n=0;n<128;n++)write_data(OLED_GRAM[n][i]); } } //向SSD1306写入一个字节的命令。 void write_cmd(u8 data) { u8 i; Clr_OLED_DC; for(i=0;i<8;i++) { Clr_OLED_SCLK; if(data&0x80) Set_OLED_SDIN; else Clr_OLED_SDIN; Set_OLED_SCLK; data<<=1; } } //向SSD1306写入一个字节的数据。 void write_data(u8 data) { u8 i; Set_OLED_DC; for(i=0;i<8;i++) { Clr_OLED_SCLK; if(data&0x80) Set_OLED_SDIN; else Clr_OLED_SDIN; Set_OLED_SCLK; data<<=1; } }


hls c代码为:


void oled_refresh_gram(char *dc, char *sclk, char *sdin) { char i,n; for(i=0;i<8;i++) { write_cmd (0xb0+i,dc, sclk, sdin); write_cmd (0x0,dc, sclk, sdin); write_cmd (0x10,dc, sclk, sdin); for(n=0;n<128;n++)write_data(oled_gram[n+128*i],dc, sclk, sdin); } } // cmd write function void write_cmd(unsigned char data, char *dc, char *sclk, char *sdin) { char i; *dc = 0; for(i=0;i<8;i++) { *sclk = 0; if(data&0x80) { *sdin = 1; //Set_OLED_SDIN; } else { *sdin = 0; //Clr_OLED_SDIN; } *sclk = 1; //Set_OLED_SCLK; data<<=1; } } void write_data(unsigned char data,char* dc,char* sclk,char* sdin) { char i; *dc = 1; for(i=0;i<8;i++) { *sclk = 0; if(data&0x80) { *sdin = 1; } else { *sdin = 0; } *sclk = 1; data<<=1; } }


然后是仿真结果:

不知道电脑抽什么风,一到仿真就卡住,这里就没图了,总之结果是不对的,之前仿真过一次,结果是sclk、sdin、dc三根线状态都不正常,有高阻态出现……


2、尝试使用hls将axis-stream相关库函数

产生这个念头,是看到某个文档,好像是ug902提到stream库函数的使用。

主要尝试了2方面,另有一个小的想法。

i)axis2vesa转换
尝试将axis-stream数据流按照标准vesa时序送显示器。没有成功,主要原因在于在库函数提供的数据结构中,有些控制信号是不可见的,例如valid和tready信号,无法利用这些信号控制什么时候开始读写数据。从hls生成的IP接口来看,valid、tready都是有的,所以猜测,这些信号是由hls自动管理的。

虽然说遇到一些困难,但从过程来看,利用hls实现协议转换虽然有一点难度,但是是可以实现的。OpenCV库函数mat2axivideo、axivideo2mat也是一种转换,和这里的尝试本质上上一样的。

ii)仅处理数据,如画面叠加的实现。
在尝试axis2vesa设计的时候,发现想要“控制”是很难的,如果只处理数据,难度倒不是很大,所以考虑只处理数据。例如,两幅画面的数据流叠加后输出,这点是很容易实现的。我之前的博客里提到的“边标识填充算法”也可以利用HLS实现,可以降低程序设计的难度。这里也算是对axis数据流的处理。

另外还有一个想法,是否能够将linebuffer作oled的显示帧存?这个还没有尝试。


3、利用HLS实现信号发生

这个是相当easy的,传统FPGA在设计正弦波、三角波、方波等常规波形信号发生器时,往往采用ROM预存储波形+周期读取的方法实现,HLS的帮助下,波形发生器的实现起来就非常简单。只需要用C语言生成波形即可,剩下的工作交于HLS完成。从正弦波的例子可以看出,一些数学函数波形的生成都是类似的。

举例而言:

正弦波HLS 关键c代码:

void init_sin_table(din1_t sin_table[256]) { int i; for (i = 0; i < 256; i++) { dint_t real_val = sin( 2 * M_PI * (dint_t)i / 256.0); sin_table[i] = (din1_t)(512.0 + 512.0 * real_val); } }


地址线宽度:8bits,数据线宽度:10bits,M_PI=3.14159265358

仿真结果:

三角波仿真结果(代码就不给了,比正弦波还简单):


有这些想法,总的来说是想利用hls进行偷懒,倒不是说这些想法有多大的实用价值,主要目的是想搞明白到底该如何去用hls这个东西。很多时候,我们拿着官方提供的design example,在自己电脑上做一遍,觉得很简单,然而这还远远不够。重要的是,如何把hls结合到自己的实际需求中去,我手里有一个需求,用hdl做起来麻烦,hls能不能帮助我降低设计难度?我该怎么着手设计我自己的程序?

从官方给的opencv相关应用,以及文中所做的尝试来看,hls的强大应该是在数据的处理上面,比如本文提到的图像叠加、波形发生器的实现,之前文章里提到的rgb2yuv的实现,在本质上都是对数据进行处理然后送出。如果想用hls做控制,可能就需要下一番功夫了。比如上文提到的oled驱动开发,如果使用hdl进行设计或许比用hls更快一些。


版权声明:

本文由博主“cuter”发布。欢迎转载,但不得擅自更改博文内容,也不得用于任何盈利目的。转载时不得删除作者简介和版权声明。如有盗用而不说明出处引起的版权纠纷,由盗用者自负。

博客官方地址:

ChinaAET:http://blog.chinaaet.com/cuter521

EDN China:http://bbs.ednchina.com/BLOG_cuter521_356737.HTM

Baidu
map