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,記得把fifo選false
console下方出現address
overlap的訊息,所以自己指定隨便一個位置,如果不適當,會有error
把spi的bus拉到mb_plb
再到ports把spi的腳位拉出來
最後檢查spi是不是已經再address
map中
然後generate
netlist
在ISE上針對microblaze
generate top HDL Source ,省下寫top
module的時間XD
在xps上也可以看到reference的ucf
file,當然前提是用特定的版子
但是注意它跟系統自動產生的pin
name並不完全一樣,spi也不在reference
ucf裡面,我把它接到J55,56,57,58來用Scope觀察
產生bit
file
在資料夾中建立workspace資料夾,在xps中將hardware
import到workspace
建立一個test
peripheral的application
project,這個template
project會根據你的microblaze裡面有哪些peripheral來產生相對應的source
file,所以我的資料夾中就只有uart與spi
先run
testperiph.c會在scope上面寫入四次資料,
後來trace到testloopback
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,但是對此步驟沒有影響,其判斷SPISR與XSP_SR_TX_FULL_MASK
and 為0,表示SPISR中的tx_full為零,則把資料塞進SPIDTR準備送出,直到tx_full為1
,此時資料準備好了但是還未送出
3.
再將SPICR讀出與XSP_CR_TRANS_INHIBIT_MASK的反向做AND.XSP_CR_TRANS_INHIBIT_MASK代表SPICR的bit
23, master transaction,表示SPICR的其它bit保留,不管bit
23是零或一皆設為零,表示master
transaction enable再將其與XSP_CR_ENABLE_MASK做or表示master
transaction enable且spi
system enable,這時候資料才真正開始傳送,用do
while來看如果SPISR表示的29
bit tx_empty為0,則表示還有資料,繼續傳送直到tx_empty為1,則跳出do
while
,讀回來的兩次資料為0x09,0x06,09表示tx
full 與rx
empty,06表示tx
empty rx full
4.
傳完以後將SPICR與XSP_CR_TRANS_INHIBIT_MASK做OR來做master
transaction disable,然後再將SPICR與XSP_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裡面的強大多拉!
以後寫sdk的code記得來這邊看就好了
後記補上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,把miso與mosi連在一起測試,用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;
}
|
但是案情並不是這麼單純,有兩點我實在想不通阿
- datasheet上明明寫slave select是active low 但是我怎麼改在scope上都是active high阿!
- 在main function中,如果印出讀回資訊就無法讀寫超過一次,明明uart跟spi應該沒關係阿!!!!!!
沒有留言:
張貼留言