| 本帖最后由 Milinker_XU 于 2016-1-19 09:19 编辑 
 
 前面章节中我们利用xilinx的IP做了大量的实验,相比大家对MB这个SOC系统已经有所了解。但有时候想,如果自己实现的功能模块如何添加到MB系统中去呢。这就得对MB的AXI4协议有更深的了解才行了。本章节我们使用MB系统中的通用寄存器,设计个定时器。暂定为使用通用寄存器0吧。 ◎首先,确定好32位通用寄存器0各位的含义,这里我们列出了张表,如下所示。 
 ◎开始设计我们所需要的IP,打开xilinx的EDK开发环境,选择菜单Hardware下的Create or Import Peripheral…。 
 
 
 
 
 ◎PeripheralFlow中保持默认,创建新的。
 
 
◎一直到Name andVersion对话框,将IP命名为soc_timer。IP版本号,保持默认即可。 
 
 ◎在BusInterface中,将IP挂在AXI4-Lite总线下。
 
 ◎在IPIFservices中,选择所有功能。 
 
 ◎User S/W Register下选择软件可访问的寄存器个数。由于定时器我们就用到了一个通用寄存器,故保持默认值为1即可。 
 
 ◎在IP Interconnet中,保持默认。这些信号是IP挂在总线内部的信号,其实不需要我们处理的,xilinx开发工具已经帮我们处理好。 
 
 ◎PeripheralSimulation Support中保持默认,不产生BFM仿真。 ◎下面的窗口中,将其全部选中。 
 
 ◎继续NEXT,直到出现Finish。 ◎进行向导完成后,打开生成的ip。文件目录:…\mis603_soc\pcores\soc_timer_v1_00_a\devl\projnav。 
 
 ◎打开soc_timer.xise工程。可以看到刚刚生成的IP源代码。其中user_logic.v中,是用户文件,需要进行相应的修改。 
 
 ◎让我们打开user_logic.v文件。分析该文件,可以看到,其端口包含刚刚生成的内部信号。如用户外接端口,也可以在里面进行定义,由于我们使用的是定时器,不需要外接接口,因此保持端口名不变。 
 
 ◎程序继续往下看,知道遇见USERlogic implementation added here。将功能代码,添加进去。我们产生三种定时器US,MS,S,因此所需添加的代码如下。注意主频100Mhz,也就是一个周期10ns。 | parameter T1US = 6'd99;     parameter T1MS = 16'd99999;    parameter T1S  = 26'd99999999; reg [5 :0]us_cnt;    reg [15:0]ms_cnt;    reg [25:0]s_cnt;     /*****1us, 1ms ,1s 时钟发生器*******/     always @(posedge Bus2IP_Clk)     begin                    if(us_cnt <= T1US) us_cnt <=  us_cnt + 1'b1;             else us_cnt <= 0;             if(ms_cnt <= T1MS) ms_cnt <=  ms_cnt + 1'b1;             else ms_cnt <= 0;              if(s_cnt <= T1S) s_cnt <=  s_cnt + 1'b1;             else s_cnt <= 0;     end /* Tus_set --1us 定时器定时时间 最大65535 us Tms_set --1ms 定时器定时时间 最大65535 ms Ts_set  --1s   定时器定时时间 最大65535 s Tus_up -- 1us 触发信号 Tms_up -- 1ms 触发信号 Ts_up  -- 1s   触发信号 Tus_busy --1 us 定时器忙 Tms_busy --1 ms 定时器忙 Ts_busy  --1 s   定时器忙 T_Ctr_Reg -- 定时器控制寄存器 */     reg [15:0]Tus_set;     reg [15:0]Tms_set;      reg [15:0]Ts_set;      wire Tus_busy ,Tms_busy,Ts_busy;      wire  Tus_up,Tms_up,Ts_up;      assign  Tus_up = (us_cnt==0);      assign Tms_up = (ms_cnt==0);      assign  Ts_up  = (s_cnt ==0);      assign Tus_busy = (Tus_set>0);      assign Tms_busy = (Tms_set>0);      assign Ts_busy  = (Ts_set >0);      wire [31:0] T_Ctr_Reg;      assign T_Ctr_Reg= slv_reg0;       always @(posedge Bus2IP_Clk)       begin          if ( Bus2IP_Resetn == 1'b0 )             begin                 Tus_set <= 0;                  Tms_set <= 0;                  Ts_set <= 0;             end          else               begin                  if(Tus_up && Tus_set)  Tus_set <= Tus_set - 1'b1;                 if(Tms_up && Tms_set)  Tms_set <= Tms_set - 1'b1;                 if(Ts_up  && Ts_set ) Ts_set  <= Ts_set  - 1'b1;                 if(T_Ctr_Reg&32'h01000000)  Tus_set <= T_Ctr_Reg&32'h00ffffff;   // 设置1us 定时器时间 单位 us                 if(T_Ctr_Reg&32'h02000000)  Tms_set <= T_Ctr_Reg&32'h00ffffff;   // 设置1ms 定时器时间 单位 ms                 if(T_Ctr_Reg&32'h04000000)  Ts_set  <=  T_Ctr_Reg&32'h00ffffff;  // 设置1s  定时器时间 单位 s             end     end | 
 ◎从上述代码可以看到,只需设置us,ms,s的定时值,启动对应的定时器,即可完成定时。 ◎继续查看下面的程序,修改下面的代码。通知MB系统,此时定时器忙碌。 |   // implement  slave model register read mux   always @(  slv_reg_read_sel or slv_reg0 )     begin          case (  slv_reg_read_sel ) 1'b1 : slv_ip2bus_data <= {Tus_busy ,Tms_busy,Ts_busy};         default : slv_ip2bus_data <= 0;       endcase       end // SLAVE_REG_READ_PROC | 
 ◎上述操作完成后,编译代码,没有错误后,关闭soc_timer工程。从EDK中,可以看到USER中的SOC_TIMER IP。
 
 
 
 ◎添加完成后,可以看到该IP,已经挂在AXI4Lite_0下面了。跟xilinx提供的ip一模一样嘛。
 
 ◎运行Hardware下的Generate NetList产生网表。 ◎返回至ISE工程下,运行工程产生bit文件。 ◎返回XPS平台,进入SDK开发平台。在system.xml中查看ip版本号是否都有,否则,重启SDK。
 
 ◎新建一个工程,工程命名为Stimer,以helloworld作为模板。 ◎将Stimer工程中的helloworld.c文件修改成Stimer.c文件。再新建两个文件,一个Stimer.h的头文件,一个timer_set.c文件。
 
 ◎在timer_set.c文件中,完成定时器初值的设定以及定时器启动,对应的函数介绍如下所示。 delay_us() - 微秒精度定时器,最大24b 长度 需要等待时间到才返回 delay_ms() - 毫秒精度定时器,最大24b 长度 需要等待时间到才返回 delay_s() -   秒精度定时器,最大24b 长度 需要等待时间到才返回 delay_us_loop() - 微秒精度定时器,最大24b 长度 立刻返回 1代表定时时到 0代表定时未到 delay_ms_loop() - 毫秒精度定时器,最大24b 长度 立刻返回 1代表定时时到 0代表定时未到 delay_s_loop()  -   秒精度定时器,最大24b 长度 立刻返回 1代表定时时到 0代表定时未到     其代码如下所示:
 |  /*  * timer_set.c  *  *  Created on: 2016-1-18  *      Author: Administrator  */ #include "Stimer.h" void delay_us( u16 val) {  En_Timer(0x01000000|val);  while(STIMER_STATU&0x01); }   void delay_ms( u16 val) {  En_Timer(0x02000000|val);  while(STIMER_STATU&0x02); }   void delay_s( u16 val) {  En_Timer(0x04000000|val);  while(STIMER_STATU&0x04); }   u8 us_s=0; u8 delay_us_loop( u16 val ) // loop 调用后直接返回 {  switch(us_s)  {  case 0:      En_Timer(0x01000000|val);//启动定时器      us_s=1;  break;  case 1:      if(STIMER_STATU&0x01);else  us_s=0;  break;  }    if(us_s) return  0;  else return 1; }   u8 ms_s=0; u8 delay_ms_loop( u16 val ) // loop 调用后直接返回 {  switch(ms_s)  {  case 0:      En_Timer(0x02000000|val);//启动定时器      ms_s=1;  break;  case 1:      if(STIMER_STATU&0x02);else  ms_s=0;  break;  }    if(ms_s) return  0;  else return 1; }   u8 s_s=0;   u8 delay_s_loop( u16 val ) // loop 调用后直接返回 {  switch(s_s)  {  case 0:      En_Timer(0x04000000|val);//启动定时器      s_s=1;  break;  case 1:      if(STIMER_STATU&0x04);else  s_s=0;  break;  }  if(s_s) return 0;  else return 1; } | 
 ◎Stimer.h文件中,同样只包含必要的头文件和函数声明。 | /*  * Stimer.h  *  *  Created on: 2016-1-18  *      Author: Administrator  */   #ifndef STIMER_H_ #define STIMER_H_   #include <stdio.h> #include "platform.h" #include "xparameters.h" #include "xbasic_types.h" #include "xil_io.h" #include "xgpio.h"   //寄存器操作 #define En_Timer(x)  {Xil_Out32(XPAR_SOC_TIMER_0_BASEADDR,x);Xil_Out32(XPAR_SOC_TIMER_0_BASEADDR,0);}   #define STIMER_STATU   Xil_In32 (XPAR_SOC_TIMER_0_BASEADDR)   void delay_us (u16 val); void delay_ms (u16 val); void delay_s   (u16 val);   u8 delay_us_loop (u16 val); u8 delay_ms_loop (u16 val); u8 delay_s_loop   (u16 val);   #endif /* STIMER_H_  */ | 
 ◎主函数中将LED用来做定时器的测试。 | #include "Stimer.h"   int main() {     u8 i=0;     u32 led;     led=0x00000000;     XGpio_Out32(XPAR_LED_BASEADDR,led);     delay_ms(1000);     led=0xffffffff;     XGpio_Out32(XPAR_LED_BASEADDR,led);     delay_ms(1000);     led=0x55555555;     XGpio_Out32(XPAR_LED_BASEADDR,led);     delay_ms(1000);     while(1)     {         i=0;         led=0x000000FE;         while(i<8)         {             XGpio_Out32(XPAR_LED_BASEADDR,led);             led<<=1;             i++;             delay_ms(1000);         }     }     return 0; } | 
 ◎实际上,受制于MB系统自身的工作效率,上面的定时不是很准确的。大家若是实际工作中遇到需要精确定时的,还是使用xilinx自带的IP,这里只是给大家如何自己添加个IP提供指导。
 |