2014年8月29日 星期五

simulate microblaze with chipscope

Reference http://www.zpss.aei.polsl.pl/content/dydaktyka/SD/Xilinx/lab6.pdf

為了想要看到上篇spi出來的訊號是不是跟我在scope看到的一樣
所以研究了一下怎麼simulate microblaze
本來是想要用外加chipscope來看波形,但是總出現PR Error
後來搜尋了一下用simulate microblaze, 我覺得因為ISE版本改很大
所以我在網路上找到的例子都不適用在ISE 14.4,別人可以checkbutton我的都是disable
直到找到這篇reference,我的心靈才得到了救贖阿!!!!

原來chipscope本來就可以內嵌進去microblaze,不用另外寫程式! 這麼方便的事情我竟然到今天才發現(崩╰(〒皿〒)╯ )

xps上選擇Debug->Debug Configuration
然後按左下角的Add ChipScope Peripheral,就會出現一個讓你選要加IBA,ILA or VIO
因為我要看得只是spimaster output 訊號,所以用ILA就可以了



然後會出現選項讓你選你要觀察哪個訊號,我把SPI中要觀察的訊號分別接到不同的triger當中,這樣比較好控制,下面的butter長度可以拉長一點,clk記得要選對,我一開始選200mosc,後來PR Error, FSL也不行,可能其他選項的CLK可以,還沒試過



建立完以後,會在Interface看到vioila



Hardware->Generate Netlist
然後在ISE重新generate bit file

xpsProject->Export Hardware Design to SDK
確定elfcompile成功以後programm FPGA
bit,bmm,elf檔燒入之後
Run->Run Configuration,Xilinx C/C++ ELF下面新增,會自動加入spi_test Debug



然後run就會Debug進入main的第一行等待,如果之後要從新debug,要按Run->Debug history->spi_test Debug



然後打開chipscope設定trigger的條件,不用重燒一次bit file
先觀察右邊是不是有看到ila
然後trigger的數量跟我設定的一樣,改不改名都可以
我把trigger條件設定在sck拉高的時候,因為它是active high

如果要加入其它的條件可以在下面設定與M2 and 或是or



然後按run等待sdk發出指令來trigger訊號,sdk上可以resume也可以stepover,看實際需求,然後就可以在chipscope上面看到spi的訊號了


看到圖形後果然ssactive low,但是匪夷所思的是為甚麼是在tri-state!!!!
然後正常的ss卻沒有啦low,但是我在Scope上看到的是active high!

果然bug沒有解完的一天! But anyway! Its nice to learn something new !


2014年8月27日 星期三

xilinx xps spi ipcore test

Xilinx xps spi ipcore study

Reference.
LogiCORE IP XPS Serial Peripheral Interface (SPI) (v2.02a)

因為可能需要把硬體的資訊寫在sd card裡面,所以這幾天都研究怎麼使用這個ipcore
看了ipcore的文件還有網路上的資訊還是不太了解要怎麼開始使用這個ipcore
後來才發現原來xilinx有這麼多SDK的範例,看範例就好啦! 真是蠢阿我!!!

用一個最簡單的microblaze來測試function
xps是用PLB bus,wizard 裡面別選錯了

把不需要的東西拿掉,留下UART方便DEBUG

建立完microblaze以後在手動加入spi ipcore,記得把fifofalse

console下方出現address overlap的訊息,所以自己指定隨便一個位置,如果不適當,會有error




spibus拉到mb_plb


再到portsspi的腳位拉出來

最後檢查spi是不是已經再address map

然後generate netlist

ISE上針對microblaze generate top HDL Source ,省下寫top module的時間XD


xps上也可以看到referenceucf file,當然前提是用特定的版子

但是注意它跟系統自動產生的pin name並不完全一樣,spi也不在reference ucf裡面,我把它接到J55,56,57,58來用Scope觀察

產生bit file

在資料夾中建立workspace資料夾,xps中將hardware importworkspace

建立一個test peripheralapplication project,這個template project會根據你的microblaze裡面有哪些peripheral來產生相對應的source file,所以我的資料夾中就只有uartspi




run testperiph.c會在scope上面寫入四次資料, 後來tracetestloopback function我才大概知道為什麼之前一直寫Write register function都沒三小路用

我猜測 write register的步驟應該如下

1. SPICR讀出來,系統預設值為0x180,將它與XSP_CR_MASTER_MODE_MASK(0x04)or來設為
mastermode(0x184)

2. SPISR讀出來,本來系統預設值為0x25,但不知為何我總讀到0x15表示error condition detect,但是對此步驟沒有影響,其判斷SPISRXSP_SR_TX_FULL_MASK and 0,表示SPISR中的tx_full為零,則把資料塞進SPIDTR準備送出,直到tx_full1
,此時資料準備好了但是還未送出

3. 再將SPICR讀出與XSP_CR_TRANS_INHIBIT_MASK的反向做AND.XSP_CR_TRANS_INHIBIT_MASK代表SPICRbit 23, master transaction,表示SPICR的其它bit保留,不管bit 23是零或一皆設為零,表示master transaction enable再將其與XSP_CR_ENABLE_MASKor表示master transaction enablespi system enable,這時候資料才真正開始傳送,do while來看如果SPISR表示的29 bit tx_empty0,則表示還有資料,繼續傳送直到tx_empty1,則跳出do while
,讀回來的兩次資料為0x09,0x06,09表示tx full rx empty,06表示tx empty rx full

4. 傳完以後將SPICRXSP_CR_TRANS_INHIBIT_MASKOR來做master transaction disable,然後再將SPICRXSP_CR_ENABLE_MASK的反向做AND,表示SPI system disable





testperith.c (master mode,write only)
#include <stdio.h>
#include "xparameters.h"
#include "xil_cache.h"
#include "uartlite_header.h"
#include "xspi.h"
#include "spi_header.h"

#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID



void spi_write_byte(XSpi *InstancePtr,u8 Data);


void spi_write_byte(XSpi *InstancePtr,u8 Data)
{
u32 StatusReg;
u32 ControlReg;

// Setup the control register to enable master mode
ControlReg = XSpi_GetControlReg(InstancePtr); // 0x180
XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_MASTER_MODE_MASK); // 0x00000004 Enable master mode // 0x184

// Fill the transmit register.
StatusReg = XSpi_GetStatusReg(InstancePtr); //0x15
while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) // 0x00000008 Transmit Reg/FIFO is full
{
XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET,Data);
StatusReg = XSpi_GetStatusReg(InstancePtr); // 0x09
}

// Start the transfer by not inhibiting the transmitter and enabling the device.
ControlReg = XSpi_GetControlReg(InstancePtr) &(~XSP_CR_TRANS_INHIBIT_MASK); // 0x00000100 Master transaction inhibit // 0x84
XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK); // 0x00000002 System enable
do {
StatusReg = XSpi_GetStatusReg(InstancePtr); //0x09->0x06
} while ((StatusReg & XSP_SR_TX_EMPTY_MASK) == 0); // 0x00000004 Transmit Reg/FIFO is empty

// Wait for the transfer to be done by polling the transmit empty status bit.
ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; // 0x00000100 Master transaction inhibit // 0x184
XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); // 0x00000002 System enable //0x184


}

int main()
{

int Status;
XSpi_Config *ConfigPtr; /* Pointer to Configuration data */
XSpi Spi;

print("-------spi test-------\n\r");

ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID);
if (ConfigPtr == NULL) {
return XST_DEVICE_NOT_FOUND;
}

Status = XSpi_CfgInitialize(&Spi, ConfigPtr,
ConfigPtr->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}

spi_write_byte(&Spi,0x01);
spi_write_byte(&Spi,0x02);
spi_write_byte(&Spi,0x03);

print("---Exiting spi test ---\n\r");
return 0;

}




後來發現在C:\Xilinx\14.4\ISE_DS\EDK\sw\XilinxProcessorIPLib\drivers\spi_v3_01_a\examples
資料夾下的範例比xilinx forum裡面的強大多拉! 以後寫sdkcode記得來這邊看就好了


後記補上read function
int spi_read_byte(XSpi *InstancePtr)
{
u32 StatusReg;
u32 RxData;

while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) {
RxData = XSpi_ReadReg(InstancePtr->BaseAddr,XSP_DRR_OFFSET);
StatusReg = XSpi_GetStatusReg(InstancePtr);
}
return RxData;
}



再把其他東西分一分寫成function,misomosi連在一起測試,teraterm看到收到的資料跟送出的一樣

peripheral.c(master mode,read write )
#include <stdio.h>
#include "xparameters.h"
#include "xil_cache.h"
#include "uartlite_header.h"
#include "xspi.h"
#include "spi_header.h"

#define SPI_DEVICE_ID XPAR_SPI_0_DEVICE_ID

int init_spi(XSpi *InstancePtr);
void enable_master(XSpi *InstancePtr);
void spi_write_byte(XSpi *InstancePtr,u8 Data);
int spi_read_byte(XSpi *InstancePtr);



void spi_write_byte(XSpi *InstancePtr,u8 Data)
{
u32 StatusReg;
u32 ControlReg;

// Fill the transmit register.
StatusReg = XSpi_GetStatusReg(InstancePtr); //0x15
while ((StatusReg & XSP_SR_TX_FULL_MASK) == 0) // 0x00000008 Transmit Reg/FIFO is full
{
XSpi_WriteReg(InstancePtr->BaseAddr, XSP_DTR_OFFSET,Data);
StatusReg = XSpi_GetStatusReg(InstancePtr); // 0x09
}

// Start the transfer by not inhibiting the transmitter and enabling the device.
ControlReg = XSpi_GetControlReg(InstancePtr) &(~XSP_CR_TRANS_INHIBIT_MASK); // 0x00000100 Master transaction inhibit // 0x84
XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_ENABLE_MASK); // 0x00000002 System enable
do {
StatusReg = XSpi_GetStatusReg(InstancePtr); //0x09->0x06
} while ((StatusReg & XSP_SR_TX_EMPTY_MASK) == 0); // 0x00000004 Transmit Reg/FIFO is empty

// Wait for the transfer to be done by polling the transmit empty status bit.
ControlReg |= XSP_CR_TRANS_INHIBIT_MASK; // 0x00000100 Master transaction inhibit // 0x184
XSpi_SetControlReg(InstancePtr , ControlReg & ~ XSP_CR_ENABLE_MASK); // 0x00000002 System enable //0x184
}


int spi_read_byte(XSpi *InstancePtr)
{
u32 StatusReg;
u32 RxData;

while ((StatusReg & XSP_SR_RX_EMPTY_MASK) == 0) {
RxData = XSpi_ReadReg(InstancePtr->BaseAddr,XSP_DRR_OFFSET);
StatusReg = XSpi_GetStatusReg(InstancePtr);
}
return RxData;
}

void enable_master(XSpi *InstancePtr)
{
u32 ControlReg;
// Setup the control register to enable master mode
ControlReg = XSpi_GetControlReg(InstancePtr); // 0x180
XSpi_SetControlReg(InstancePtr, ControlReg | XSP_CR_MASTER_MODE_MASK); // 0x00000004 Enable master mode // 0x184
}

int init_spi(XSpi *InstancePtr)
{
int Status;
XSpi_Config *ConfigPtr; /* Pointer to Configuration data */
ConfigPtr = XSpi_LookupConfig(SPI_DEVICE_ID);
if (ConfigPtr == NULL) {
return XST_DEVICE_NOT_FOUND;
}

Status = XSpi_CfgInitialize(InstancePtr, ConfigPtr,ConfigPtr->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}

int main()
{

XSpi Spi;

int Rdata1,Rdata2,Rdata3;

print("-------spi test-------\n\r");

init_spi(&Spi);
enable_master(&Spi);

spi_write_byte(&Spi,0x11);
Rdata1 = spi_read_byte(&Spi);
//xil_printf("read back data : (0x%08x)\n\r",Rdata1);
spi_write_byte(&Spi,0x22);
Rdata2 = spi_read_byte(&Spi);
//xil_printf("read back data : (0x%08x)\n\r",Rdata2);
spi_write_byte(&Spi,0x33);
Rdata3 = spi_read_byte(&Spi);
//xil_printf("read back data : (0x%08x)\n\r",Rdata3);

// Reset the SPI device to leave it in a known good state.
XSpi_Reset(&Spi);

print("---Exiting spi test ---\n\r");

return 0;

}

但是案情並不是這麼單純,有兩點我實在想不通阿

  1. datasheet上明明寫slave selectactive low 但是我怎麼改在scope上都是active high!
  2. main function,如果印出讀回資訊就無法讀寫超過一次,明明uartspi應該沒關係阿!!!!!!