tag 标签: 并行

相关帖子
相关博文
  • 热度 19
    2017-5-10 13:56
    1568 次阅读|
    0 个评论
    我们都知道源同步方式的典型代表是DDRx信号,下面就来介绍源同步方式是怎样改善系统同步的先天不足的。 源同步要解决的第一个问题是减少在芯片之间传输数据所需的I/O引脚数量。这通过将芯片#1的输出处的n位数据复用到k位互连(k n),然后将芯片#2的输入上的互连的k位解复用到n位内部数据路径上来实现,如下图所示。所得到的系统只需要每个芯片上的k个I/O引脚,而不需要先前的n个引脚。 当然,虽然引脚数量要求已经通过k:n的比率降低,但是参考时钟的所需频率已经增加了这个比率的倒数。由于噪声,电磁干扰(EMI)和功耗问题,系统设计人员通常不喜欢在系统内分配高速参考时钟。通常,分配较低频率的时钟,并且使用芯片中的PLL将该参考时钟乘以可用频率,但所产生的时钟相位的变化以及数据传输的频率越高,往往会加剧并行数据总线的时序问题。 源同步的第二个法宝就是在两个芯片之间的数据通路中增加了一个高速时钟,如下图所示。假设该时钟源提供的时钟频率略低于在芯片互连上对数据进行触发的时钟频率,每个芯片都使用PLL来产生这个频率倍数的时钟,所得到的时钟用于启动和捕获相应芯片中的数据。芯片#1中用于从该芯片启动数据的PLL的输出时钟也是该芯片的输出,芯片#2使用该时钟来捕获数据,这种方法称为时钟转发。 时钟转发的优点是用于在芯片#1上启动数据的高速时钟可用于芯片#2作为捕获数据的参考。这样之前通过时钟分配网络驱动两个芯片的延迟的变化在时序分析中就不需要考虑了,只有时钟路径和数据位之间的延迟变化是相关的。 虽然制程,电压和温度导致的这些路径之间的变化在一定程度上相互影响,但接口的时序分析需要的余量较少,因此建立和保持时间更容易满足。 我们还是来看看典型的例子吧,图中所示的时钟可以是单数据速率(SDR)或双倍数据速率(DDR)的时钟,如下图所示。SDR就是接收芯片在SDR时钟的每个上升沿(或每个下降沿)捕获数据; 而DDR则是接收芯片捕获DDR时钟的每个边沿(上升沿和下降沿)的数据。 无论时钟是SDR还是DDR时钟,接收芯片都使用该时钟直接捕获数据。 该芯片还使用参考时钟以相同的频率生成内部系统时钟,这些时钟是中间同步的。 虽然频率相同(鉴于它们共享共同的频率参考),但是时钟之间的相位关系是未知的,并且可能由于PVT变化而变化。 因此,接收芯片通常将接收到的数据从接口时钟域重新定时到内部芯片时钟的时钟域。 FIFO用于执行此重定时功能, 期望最小化由接口时钟计时的触发器的数量,以便最小化时钟分配网络中的延迟,否则时钟问题将会加剧。
  • 热度 25
    2012-10-31 23:45
    2878 次阅读|
    0 个评论
    好了,杂乱的代码,还是放在一起好看:   // used variables int back_posi_pin = 7; int back_nega_pin = 6; int vcc_pin = 13; int not_serial_pin = A1; int light_control_pin = A0; // the data pins int data_pin_2 = 2; int data_pin_3 = 8; int data_pin_1 = 3; int data_pin_0 = 12; int data_pin_4 = 11; int data_pin_5 = 10; int data_pin_6 = 9; int data_pin_7 = 5; int reset_pin = 4;   int lightness = 200; // these are the control pins int rw_pin = A2; int e_pin = A3; int rs_pin = A4; // this array set the data situation   int data_array =  {0,0,1,1,0,0,0,0};   // the initial arrays int funcset = {0,0,0,0,1,1,0,0}; int display_clear = {1,1,1,0,0,0,0,0};  // not sure // the usual used commands     int extend_func_on = {0,0,0,0,1,1,0,0}; int paint_on = {0,0,1,0,1,1,0,0};   int open_show = {0,1,1,0,0,0,0,0};   int temp = {bitRead(b,0),bitRead(b,1),bitRead(b,2),bitRead(b,3),    bitRead(b,4),bitRead(b,5),bitRead(b,6),bitRead(b,7)};    write_data(adapt); }   void write_cmd_adapt(unsigned char b){    int adapt ) {   //delay(2);   delayMicroseconds(500);    set_e();   set_rs();   clear_rw();   set_data(b);   set_e();   clear_e(); }     unsigned char read_data() {     unsigned char Rdata;     pinMode(data_pin_0,INPUT);       pinMode(data_pin_1,INPUT);     pinMode(data_pin_2,INPUT);     pinMode(data_pin_3,INPUT);     pinMode(data_pin_4,INPUT);     pinMode(data_pin_5,INPUT);     pinMode(data_pin_6,INPUT);     pinMode(data_pin_7,INPUT);        set_rs();     set_rw();     clear_e();     set_e();     delayMicroseconds(500);      Rdata = digitalRead(data_pin_0)+digitalRead(data_pin_0)*2+digitalRead(data_pin_0)*4     +digitalRead(data_pin_0)*8+digitalRead(data_pin_0)*16+digitalRead(data_pin_0)*32     +digitalRead(data_pin_0)*64+digitalRead(data_pin_0)*128;     clear_e();     return Rdata; }   void write_cmd(int a = a;   temp = b;   temp = c;   temp = d;    temp = e;   temp = f;   temp = g;   temp = h;   }   void set_data(int data_array ==1){    digitalWrite(data_pin_0,HIGH);    }    else{    digitalWrite(data_pin_0,LOW);      }       if(data_array ==1){    digitalWrite(data_pin_1,HIGH);    }    else{    digitalWrite(data_pin_1,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_2,HIGH);    }    else{    digitalWrite(data_pin_2,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_3,HIGH);    }    else{    digitalWrite(data_pin_3,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_4,HIGH);    }    else{    digitalWrite(data_pin_4,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_5,HIGH);    }    else{    digitalWrite(data_pin_5,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_6,HIGH);    }    else{    digitalWrite(data_pin_6,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_7,HIGH);    }    else{    digitalWrite(data_pin_7,LOW);      }   }   // functions to control the control signals void set_rw() {    analogWrite(rw_pin,255); }   void clear_rw() {    analogWrite(rw_pin,0); }   void set_rs() {    analogWrite(rs_pin,255); }   void clear_rs() {    analogWrite(rs_pin,0); }   void set_e() {    analogWrite(e_pin,255); }   void clear_e() {    analogWrite(e_pin,0); }     好了,并行的方式就写到这里了,还是有很多的话的,耽误大家这么多时间,真是愧疚不已的。     下面就是串口的方式的介绍了,这回需要说的应该没那么多了。
  • 热度 18
    2012-10-31 23:44
    1226 次阅读|
    0 个评论
    好了,有了这一些的函数的铺垫,接下来的事情好办多了。 首先是画点前的模式设置和清屏: write_cmd_adapt(0x34); clean_screen();   clean_screen 如下: void clean_screen() { settemp(0,0,1,0,1,1,0,0); write_cmd(temp); for(int i=0;i32;i++){ write_cmd_adapt(0x80+i); write_cmd_adapt(0x80);   for(int j=0;j16;j++){ write_data_adapt(0x00); }   }     for(int i=0;i32;i++){ write_cmd_adapt(0x80+i); write_cmd_adapt(0x88);   for(int j=0;j16;j++){ write_data_adapt(0x00); }   } }     这个清屏的函数需要解释一下,这样后面的画点的函数就好办了,清屏其实就是画点,不过貌似12864 没有直接的一条指令可以清屏,当然,这样我觉得速度必然受到了很大的影响,不过这里只是普通用途,不是很计较,不过后面还是有一件有意思的事情发生,后面说。 写点的时候,先写指令,告诉12864 点的位置,分为x 和y ,具体的映射关系你需要查看一下手册或是datasheet ,上面其实能看出来,从0x80 开始,前面的空间是系统使用的,你可以想见,12864 中,有自己的符号的预定义的空间,如果有中文字库,还有字库的空间,这样这些空间都是固化的,不能给你使用的,不然就乱套了。 Temp 是一个临时的使用数组,算是之前不方便的“遗留”   void settemp(int a,int b,int c,int d,int e,int f,int g,int h) { temp = a; temp = b; temp = c; temp = d; temp = e; temp = f; temp = g; temp = h;   }   这样你能明白画点是怎么画的了,在说明白一点吧,你现在只需要写一个画点的函数,这个你马上打开Arduino 环境,5 分钟,应该就出来了,可是有一个问题,这里画的不是一个点,其实一次画的是8 个数据------ write_data_adapt(0x00); 这就麻烦了,我只需要你画一个点,当然,这是可以的,不过至少现在不可以,8 的间隔导致我只能8 个8 个的重复的操作,我可以只亮8 个数据中的一个,但是之后是隔了8 个以后绘画,问题就出来了,如果我需要画两个相邻的点怎么办?这个你还不能预先知道,所以只能事后查询得知,这样,我们还需要一个函数------ 读8 个数据管脚的电平的函数。   unsigned char read_data() { unsigned char Rdata; pinMode(data_pin_0,INPUT); pinMode(data_pin_1,INPUT); pinMode(data_pin_2,INPUT); pinMode(data_pin_3,INPUT); pinMode(data_pin_4,INPUT); pinMode(data_pin_5,INPUT); pinMode(data_pin_6,INPUT); pinMode(data_pin_7,INPUT); set_rs(); set_rw(); clear_e(); set_e(); delayMicroseconds(500); Rdata = digitalRead(data_pin_0)+digitalRead(data_pin_0)*2+digitalRead(data_pin_0)*4 +digitalRead(data_pin_0)*8+digitalRead(data_pin_0)*16+digitalRead(data_pin_0)*32 +digitalRead(data_pin_0)*64+digitalRead(data_pin_0)*128; clear_e(); return Rdata; }   这样就完整了,这个也是根据12864 手册说明写出来的,看到这里的管脚方向的变化了吗?所以先前的再次设置管脚方向就是必须的了,你会想,会冲突吗?不会,因为之间有足够的时间的间隔,不会有问题。   查询的思路就是,先给出要查询的点的位置,然后查询。 查询到管脚的信息后,就是一些函数中的处理了,小技巧,就不详细说明了,好了,最后的一个函数:   unsigned char read_data() { unsigned char Rdata; pinMode(data_pin_0,INPUT); pinMode(data_pin_1,INPUT); pinMode(data_pin_2,INPUT); pinMode(data_pin_3,INPUT); pinMode(data_pin_4,INPUT); pinMode(data_pin_5,INPUT); pinMode(data_pin_6,INPUT); pinMode(data_pin_7,INPUT); set_rs(); set_rw(); clear_e(); set_e(); delayMicroseconds(500); Rdata = digitalRead(data_pin_0)+digitalRead(data_pin_0)*2+digitalRead(data_pin_0)*4 +digitalRead(data_pin_0)*8+digitalRead(data_pin_0)*16+digitalRead(data_pin_0)*32 +digitalRead(data_pin_0)*64+digitalRead(data_pin_0)*128; clear_e(); return Rdata; }     名字很霸气,恩,不过还是有一点小问题,暂时还没有解决,你可以看看是啥问题喽。 还有一个有趣的是,我之前的write_data 函数中的间隔取得太大,结果在频繁调用的时候就来问题了---- 太慢,所以我开始烧进去没看到反应,还以为错了,正在调试程序呢,过了大概有5 分钟,突然看到屏上有预期的图案了!真是意外啊。所以间隔还是小一点,你可以测试一下极限是多少。      
  • 热度 20
    2012-10-31 23:43
    1261 次阅读|
    0 个评论
    好了,这里需要按照时序图,一点也不能违背,所以小心啦,全靠这个时序图了。 在一开始的时候,我写的写数据函数显得比较笨拙: void write_data(int b = {0,0,0,0,1,1,0,0}; int funcset2 = {1,0,0,0,0,0,0,0}; int entry_mode_set = {0,0,1,0,1,1,0,0}; int extend_func_off = {0,1,1,0,1,1,0,0}; int paint_off = {1,1,1,1,0,0,0,0};   不过这些有助于新手熟悉怎样去使用手册和说明,比如说,在上面的数组中,每一个中都是安放着特定的一个命令的数据组合,extend_func_on 就是开启扩充指令集,这是因为之后一些命令需要在扩充模式下进行使用,下面是我截取的一张图,上面讲述的是扩充模式时管脚的各个电平设定的情况,这就是我们设定需要的“地图”了     对照着你就可以看出各个引脚的电平值了,而我的数组中的值,正是与之一一对应的。 由于这个带来的不便,后来又写了一个调整的函数,美其名为write_data_adapt:   void write_data_adapt(unsigned char b){    int adapt ) {   //delay(2);   delayMicroseconds(500);   set_e();   clear_rs();   clear_rw();   set_data(a);   set_e();   clear_e(); }     当然,调整函数也有:   void write_cmd(int a ) {     pinMode(data_pin_0,OUTPUT);       pinMode(data_pin_1,OUTPUT);     pinMode(data_pin_2,OUTPUT);     pinMode(data_pin_3,OUTPUT);     pinMode(data_pin_4,OUTPUT);     pinMode(data_pin_5,OUTPUT);     pinMode(data_pin_6,OUTPUT);     pinMode(data_pin_7,OUTPUT);         if(data_array ==1){    digitalWrite(data_pin_0,HIGH);    }    else{    digitalWrite(data_pin_0,LOW);      }       if(data_array ==1){    digitalWrite(data_pin_1,HIGH);    }    else{    digitalWrite(data_pin_1,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_2,HIGH);    }    else{    digitalWrite(data_pin_2,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_3,HIGH);    }    else{    digitalWrite(data_pin_3,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_4,HIGH);    }    else{    digitalWrite(data_pin_4,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_5,HIGH);    }    else{    digitalWrite(data_pin_5,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_6,HIGH);    }    else{    digitalWrite(data_pin_6,LOW);      }      if(data_array ==1){    digitalWrite(data_pin_7,HIGH);    }    else{    digitalWrite(data_pin_7,LOW);      }   }   这个函数是设置8 个数据端的电平的,注意到这个函数的开头把管脚的方向做了一个调整,这个是必须的。不过暂时你并不能看出这句话的正确性,因为我之前初始的时候也是输出的方向啊,怎么还要设置一次?这个后面就能明白。        
  • 热度 18
    2012-10-31 23:39
    2177 次阅读|
    0 个评论
    接上次的话茬 并行的接线比较多,主要是数据的发送用的是8根数据线,而在串行中,用的是2根数据线,这样一对比就立马能看见区别了,不过串行的在后面再讲,先讲并行的。 主要的工作就是提供驱动所需的所有的部件—函数,然后按照时序图和说明书上的说明“按图索骥”,在对的时间发送对的数据就行了,那么我们一步一步的完成函数的书写,这里用的Arduino的环境,个人感觉这个真心很好用,用多了有一些依赖。所以慎重啦。 定义管脚的部分不详细讲,主要是常用的的语法,基本和C差不多,这里比较常用的数据类型是unsigned char ,主要原因来说,单片机的空间有限,所以不比电脑中,可以比较随意,当然,需要多少就定义多少,也是一种好的习惯。 定义如下: int back_posi_pin = 7; int back_nega_pin = 6; int vcc_pin = 13; int not_serial_pin = A1; int light_control_pin = A0; // the data pins int data_pin_2 = 2; int data_pin_3 = 8; int data_pin_1 = 3; int data_pin_0 = 12; int data_pin_4 = 11; int data_pin_5 = 10; int data_pin_6 = 9; int data_pin_7 = 5; int reset_pin = 4;   int lightness = 200; // these are the control pins int rw_pin = A2; int e_pin = A3; int rs_pin = A4;   这里有一半的管脚是定义的8个数据端口,这个比较明显,而另外的一些需要说明一下,lightness这个管脚,是用来控制屏幕的亮度的,是通过一个电阻进行调节的,具体的原理和滑变差不多,定义这个变量的值,可以调整屏幕的亮度,太小了你会在之后发现屏幕不能正常的显示你需要它显示的东西,这里定的值(最大是255)是200,稍小一点也是可以的。 重点的是下面的rw,e和rs管脚,这三个管脚对12864进行了控制,没有了他们,即使你发送给12864数据他也不知道怎么去理解这些数据,就比如啥时候发送的是数据,啥时候发送的是指令,e,在英文中是enable的意思,也就是使能,rs决定的是数据和指令,也就是能够告诉12864发的是数据还是指令,而rw,就是read和write的意思,读写的控制,决定是要读数据还是写数据,这里读的时候,单片机就能从8个数据端口获取电平情况,而写的时候,是12864从这8个数据管脚获取电平高低情况,所以很显然,比如你需要写数据,首先把数据放到管脚上,然后告诉12864我数据已经准备好,你可以取了。这三个信号在时序图上都有具体的说明,马上给出,其实时序图的职能就是这个,提供关于控制的时间上的顺序,提供具体的步骤,驱动者的任务就是根据这个进行一步一步的操作,只要他们的单片机和12864没有坏,那么肯定能够成功的,这个也是一大乐趣呀。 在Arduino中,程序被分为初始化部分和持续执行部分,这一点如果你用过processing编过程,应该是熟悉的,也就是说,初始化的部分只会被执行一次,而持续部分就是以一定的frameRate进行反复的执行,除非你在程序中设置了退出,程序是不会停止的。 这里只进行一次性的赋值显示,还没有做到高级的功能,所以暂时不用持续执行部分,只是用初始化的部分,而这里我们又可以将初始化的部分分为前后两个部分,一个是初始化中的初始化,而另一部分就是任务的具体完成代码段。 这前半部分是比较常规的初始化部分,完成一件事,管脚方向定义和器件的初始设置。   // first set the output and inout pin in mode     pinMode(back_posi_pin,OUTPUT);       pinMode(vcc_pin,OUTPUT);           pinMode(back_nega_pin,OUTPUT);     pinMode(light_control_pin,OUTPUT);         pinMode(data_pin_0,OUTPUT);       pinMode(data_pin_1,OUTPUT);     pinMode(data_pin_2,OUTPUT);     pinMode(data_pin_3,OUTPUT);     pinMode(data_pin_4,OUTPUT);     pinMode(data_pin_5,OUTPUT);     pinMode(data_pin_6,OUTPUT);     pinMode(data_pin_7,OUTPUT);           pinMode(not_serial_pin,OUTPUT);         pinMode(rw_pin,OUTPUT);      pinMode(rs_pin,OUTPUT);        pinMode(e_pin,OUTPUT);          pinMode(reset_pin,OUTPUT);                  digitalWrite(vcc_pin,HIGH);     digitalWrite(back_posi_pin,HIGH);     digitalWrite(back_nega_pin,LOW);     analogWrite(not_serial_pin,255); // set the mode to parallel     digitalWrite(data_pin_2,HIGH);     analogWrite(light_control_pin,lightness);       // initial work     delay(1000);     digitalWrite(reset_pin,LOW);     digitalWrite(reset_pin,HIGH);   // reset the system   代码比较好阅读,解释也就少一点了,pinMode就是制定管脚的方向,这个在很多的单片机都是需要的,就比如51单片机和430单片机(以低功耗著称),单片机不是神,他不会自己判断方向,所以你就需要告诉他喽。   有一点需要说明一下,三个控制信号的端口,也就是之前提到的rs,rw,e这三个管脚,我在这里定义的是使用Arduino的模拟端,也就是区别于数字端的,这个其实不难理解,如果你用过AD,DA转换,这个就相当于这种转换,只不过这种转换是内置的,数字的,就是只有1,0两种状态,而模拟的,在Arduino中,有0-255这样一个范围的输入输出,所以更精确的感知外界,Arduino用在传感器的驱动制作方面很多,所以对于传感器的应用中,需要这些,比如你测量一个温度,总不能只有两个温度吧?热敏电阻必然是一个连续区间的测量值,好了,不再扯远了。   那么,这里我想当于把模拟当数字口用,所以只用到这里的0和255这两种状态,就相当于数字的0和1两种状态,不过你可以用电表进行测量,你能发现,其实这两种输出的值是一样的,也就是说,模拟口输出255时,电压值同数字口设为1时的输出值。   所以类比数字口,提供了三对控制电平高低的函数:   void set_e() {    digitalWrite(e_pin,HIGH); }   void clear_e() {    digitalWrite(e_pin,LOW); }   void set_rs() {    digitalWrite(rs_pin,HIGH); }   void clear_rs() {    digitalWrite(rs_pin,LOW); }   void set_rw() {    digitalWrite(rw_pin,HIGH); }   void clear_rw() {    digitalWrite(rw_pin,LOW); }     好了,现在我们在添加一些函数,我们需要的可能很简单,只要一个函数:write,参数先不说。 你可能会问,怎么会只需要一个函数呢?是的,确实只需要一个函数,前面其实有一些提示,主要的问题在于,你可能会疑问我说的数据/命令怎么区别,还有读写的方向怎么确定,其实都不难,主要是确定一点,那就是写数据的模式,数据有两种,一种就是单纯的数字,还有一种就是命令,在三个控制信号的指引下,我们就能很好的告诉12864这些额外的信息,这样,我们确实只需要一个写的函数就可以了,不过我们需要告诉这个函数我们对于读写方向以及数据。命令的选择,这个也就是入口参数的意义。
相关资源