2014年5月16日 星期五

Ml605 microblaze with your own IP

Ml605 microblaze with your own IP

無可避免的還是用microblaze比較威,先來建立一個自己的IP放在AXI,方便接來下用UART進來的資料可以一起經由bus進入IP內部的邏輯

前兩年做過的東西早就忘光了,今天又依照tutorial 做了一次,趕快來紀錄一下,這樣下次複習比較快XDDDD

Tutorial 原版 EDK Concepts, Tools, and Techniques
A Hands-On Guide to EffectiveEmbedded System Design
UG683 (v13.4) January 18, 2012

建立一個專案,新增processer
選擇讓processor先預選基本的配備,然後在刪掉不需要的
local memory size 調大一點
timer新增進來,並加上interrupt

LED之後要做測試用所以不加進來


完成了以後可以看到大致的結構


接下來新增一個自己的IP


依照tutorial 新增一個blink ip,然後一直按到finish


打開\system\pcores\blink_v1_00_a\hdl\vhdl
裡面的兩個vhdl檔來新增port與寫入功能

blink.vhdl


user_logic.vhdl,利用輸入addressdata來決定讓led閃爍或是停止


在打開\system\pcores\blink_v1_00_a\data 裡面的 blink_v2_1_0.mpd
LEDs加入port


改完了以後按


就會在左側的ip列表裡面看到剛剛的blink,按兩下加入bus


base_address 先不用改,稍後系統會自動分配


portleds拉到外面的pin


addresses可以看到我們新增的ipaddress0x7c600000


接下來按hardware- generate netlist

成功了以後來寫top levelucf,注意blink_0_LEDs_pin 是否出現在output pin

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity ml605_microblaze_top is
    Port (
    osc_200m_p : in  STD_LOGIC;
    osc_200m_n : in  STD_LOGIC;
    reset : in  STD_LOGIC;
    uart_tx : out  STD_LOGIC;
    uart_rx : in  STD_LOGIC;
    gpio_led : out  STD_LOGIC_VECTOR (3 downto 0);
    gpio_dip : in  STD_LOGIC_VECTOR (7 downto 0));
end ml605_microblaze_top;

architecture Behavioral of ml605_microblaze_top is

  component system is
    port (
      RS232_Uart_1_sout : out std_logic;
      RS232_Uart_1_sin : in std_logic;
      RESET : in std_logic;
      blink_0_LEDs_pin : out std_logic_vector(3 downto 0);
      DIP_Switches_8Bits_TRI_I : in std_logic_vector(7 downto 0);
      CLK_P : in std_logic;
      CLK_N : in std_logic
    );
  end component;

begin

  microblaze_i : system
    port map (
      RS232_Uart_1_sout => uart_tx,
      RS232_Uart_1_sin => uart_rx,
      RESET => reset,
      blink_0_LEDs_pin => gpio_led,
      DIP_Switches_8Bits_TRI_I => gpio_dip,
      CLK_P => osc_200m_p,
      CLK_N => osc_200m_n
    );
end Behavioral;

NET osc_200m_n LOC = "H9" | DIFF_TERM = "TRUE" | IOSTANDARD = "LVDS_25";
NET osc_200m_p LOC = "J9" | DIFF_TERM = "TRUE" | IOSTANDARD = "LVDS_25";
NET gpio_dip[0] LOC = "D22" | IOSTANDARD = "LVCMOS15";
NET gpio_dip[1] LOC = "C22" | IOSTANDARD = "LVCMOS15";
NET gpio_dip[2] LOC = "L21" | IOSTANDARD = "LVCMOS15";
NET gpio_dip[3] LOC = "L20" | IOSTANDARD = "LVCMOS15";
NET gpio_dip[4] LOC = "C18" | IOSTANDARD = "LVCMOS15";
NET gpio_dip[5] LOC = "B18" | IOSTANDARD = "LVCMOS15";
NET gpio_dip[6] LOC = "K22" | IOSTANDARD = "LVCMOS15";
NET gpio_dip[7] LOC = "K21" | IOSTANDARD = "LVCMOS15";
NET gpio_led[0] LOC = "AC22" | IOSTANDARD = "LVCMOS25";
NET gpio_led[1] LOC = "AC24" | IOSTANDARD = "LVCMOS25";
NET gpio_led[2] LOC = "AE22" | IOSTANDARD = "LVCMOS25";
NET gpio_led[3] LOC = "AE23" | IOSTANDARD = "LVCMOS25";

NET reset LOC = "H10" | IOSTANDARD = "SSTL15" | TIG;
NET uart_rx LOC = "J24" | IOSTANDARD = "LVCMOS25";
NET uart_tx LOC = "J25" | IOSTANDARD = "LVCMOS25";

接下來在ISE geberate programming file

新增一個workspace資料夾

之後在XPS上直接連到SDK,指向剛剛新增的workspace



可以看到SDK上已經有Processor的資料


file-new-application project
新增一個hello world project

然後programm FPGA  


接下來可以用兩種方法來玩一下UART
  1. hello world 不用改,XMD Console
XMD%
Accepted a new TCLSock connection from 127.0.0.1 on port 53775
Programming Bitstream -- D:/ml605_microblaze/workspace/system_hw_platform/download.bit
Fpga Programming Progress ......10....20....30....40....50....60....70....80....90.....Done
mb

JTAG chain configuration
--------------------------------------------------
Device ID Code IR Length Part Name
1 0a001093 8 System_ACE_CF
2 64250093 10 XC6VLX240T

MicroBlaze Processor Configuration :
-------------------------------------
Version............................8.40.b
Optimization.......................Performance
Interconnect.......................AXI-LE
MMU Type...........................No_MMU
No of PC Breakpoints...............1
No of Read Addr/Data Watchpoints...0
No of Write Addr/Data Watchpoints..0
Instruction Cache Support..........off
Data Cache Support.................off
Exceptions Support................off
FPU Support.......................off
Hard Divider Support...............off
Hard Multiplier Support............on - (Mul32)
Barrel Shifter Support.............on
MSR clr/set Instruction Support....on
Compare Instruction Support........on
Data Cache Write-back Support......off
Fault Tolerance Support............off
Stack Protection Support...........off

Connected to MicroBlaze "mdm" target. id = 0
Starting GDB server for "mdm" target (id = 0) at TCP port no 1234

Note:: "mbconnect" command is Deprecated. Use "connect mb" command
XMD% stop
Processor stopped

XMD% mwr 0x7c600000 0x1
XMD% mrd 0x7c600000
7C600000: 00000001

XMD% mwr 0x7c600000 0x0
XMD%

第二種方法新增peripheral_tests_0 application project , 讓我們用c來控制uart



可以看到在左欄已經產了一些與周邊相關的程式,但這不是全部我需要的XD
我需要可以一個可以從UART搜集資料進來變成hex,好讓我可以把資料送入microblazeaxi bus,進而控制自創IPLED



裡面的reference code中的xlib_string.hxil_string.c,人家寫好的函式總是比較好用阿XD \xapp493_DisplayPort_SPM\XAPP493\v6\ML605\sdk_workspace\dp_source_policy_maker_0\src
xlib_string.h
//#define SIMULATION
#define DEBUG_LEVEL 1


#include "xil_types.h"

#define PRINT_TS 0
#define PRINT_EDID 1
#define LLC_TEST_MODE 0

#if (DEBUG_LEVEL >= 4)
#define dbg4_printf xil_printf
#else
#define dbg4_printf do_nothing
#endif

#if (DEBUG_LEVEL >= 3)
#define dbg3_printf xil_printf
#else
#define dbg3_printf do_nothing
#endif

#if (DEBUG_LEVEL >= 2)
#define dbg2_printf xil_printf
#else
#define dbg2_printf do_nothing
#endif

#if (DEBUG_LEVEL >= 1)
#define dbg_printf xil_printf
#define dbg1_printf xil_printf
#else
#define dbg_printf do_nothing
#define dbg1_printf do_nothing
#endif

#if (DEBUG_LEVEL == 0)
#define dbg_printf do_nothing
#endif

#define dbg_llc_printf do_nothing //xil_printf
#define dbg1_llc_printf do_nothing //xil_printf
#define dbg2_llc_printf do_nothing

void do_nothing();

char xil_getc(u32 timeout_ms);

u32 xil_gethex(u8 num_chars);


xil_string.c
#include "xlib_string.h"
#include "stdio.h"
#include "xlib_string.h"
#include "xuartlite_l.h"
#include "xparameters.h"
#include "xtmrctr.h"

char xil_getc(u32 timeout_ms){
 char c;
 u32 timeout = 0;

   extern XTmrCtr TimerCounter;

   //dbg_printf ("timeout_ms = %x\n\r",timeout_ms);
     // Reset and start timer
   if ( timeout_ms > 0 && timeout_ms != 0xff ){
    XTmrCtr_Start(&TimerCounter, 0);
    //dbg_printf ("timeout_ms = %x\n\r",timeout_ms);
   }



  while(XUartLite_IsReceiveEmpty(STDIN_BASEADDRESS) && (timeout == 0)){
      if ( timeout_ms == 0 ){ // no timeout - wait for ever
      timeout = 0;
      } else if ( timeout_ms == 0xff ) { // no wait - special case
      timeout = 1;
      } else if(timeout_ms > 0){
    if(XTmrCtr_GetValue(&TimerCounter, 0) > ( timeout_ms * (XPAR_MICROBLAZE_CORE_CLOCK_FREQ_HZ / 1000) )){
     timeout = 1;
    }
      }
  }
  if(timeout == 1){
   c = 0;
  } else {
   c = XUartLite_RecvByte(STDIN_BASEADDRESS);
  }

  return c;
}


u32 xil_gethex(u8 num_chars){
u32 data;
u32 i;
u8 term_key;
data = 0;

for(i=0;i= 'a') {
  term_key = term_key - 'a' + 10;
 } else if(term_key >= 'A') {
   term_key = term_key - 'A' + 10;
 } else {
  term_key = term_key - '0';
 }
 data = (data << 4) + term_key;
}


return data;
}

void do_nothing(){

}



將這兩個檔案加入我們建立的peripheral project,因為要init platform, 所以也把hello_world_0 裡面的platform.c, platform.h, platform_config.h 加入 peripheral project

將原本的testperiph.c main()拿掉,加入剛剛的h file
#include 
#include "xparameters.h"
#include "xil_cache.h"
#include "xintc.h"
#include "intc_header.h"
#include "uartlite_header.h"
#include "xbasic_types.h"
#include "xgpio.h"
#include "gpio_header.h"
#include "xtmrctr.h"
#include "tmrctr_header.h"
#include "tmrctr_intr_header.h"

//------------------ ADD CODE ---------------------
#include "xlib_string.h"
#include "platform.h"

void reg_write(u32 reg_address, u32 data);
u32  reg_read(u32 reg_address);
XTmrCtr TimerCounter;

int main()
{
    init_platform();
    while(1){
     dbg_printf(" TEST ");
     u32 addr = xil_gethex(8);
     u32 data = xil_gethex(8);
     reg_write(addr,data);
    }//end while
    cleanup_platform();
    return 0;
}

void reg_write(u32 reg_address, u32 data)
{
 dbg_printf("reg_write (0x%08x) 0x%08x\n\r", reg_address, data);
    *(volatile u32*)reg_address = data;
}

u32 reg_read(u32 reg_address)
{
 dbg_printf("reg_read (0x%08x) ", reg_address);
 u32 data = *(volatile u32*)reg_address;
 dbg_printf(" 0x%08x\n\r", data);
    return data;
}


在將產生的elf檔燒入版子,打開tera term,連續寫入addressdata就可以看到板子上的LED已經開始閃耀搂!




要注意一下microblazebaudrateteraterm的是否一致

如果之後不會再改sdk或是下次懶得再開sdk的話也可以直接把download.bit 燒進去板子裡面, programm FPGA後的console下方寫著
data2mem -bm D:/ml605_microblaze/edkBmmFile_bd.bmm -bt \
D:/ml605_microblaze/ml605_microblaze_top.bit -bd \
D:/ml605_microblaze/workspace/peripheral_tests_0/Debug/peripheral_tests_0.elf tag \
microblaze_0 -o b D:/ml605_microblaze/workspace/system_hw_platform/download.bit

系統已經自動幫你下commandworkspace/system_hw_platform/download.bit

結論有錢的真的是大爺,系統都幫你做好了,如果用免錢的microblaze就是童養媳的命運阿阿阿阿!!!!

這篇寫得太囉嗦了,後記下一篇用wxpythonserial來寫一個簡單的小介面來跟板子溝通,並產生exe檔方便其他沒有灌python的人使用

沒有留言:

張貼留言