[X]关闭

Mis603开发板MB SOC开发教程:第九章 协同设计超级定时器

文档创建者:Milinker_XU
浏览次数:5394
最后更新:2016-01-20
本帖最后由 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…。


◎弹出创建IP向导,点击Next。



◎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至工程中,所有参数选择默认就行。


◎添加完成后,可以看到该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提供指导。




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

发表评论已发布 2

贾文洋

发表于 2016-1-19 10:36:40 | 显示全部楼层

回复

使用道具 举报

宋桓公

发表于 2016-1-20 18:50:59 | 显示全部楼层

老许你好猛~~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则