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應該沒關係阿!!!!!!

沒有留言:

張貼留言