SPI是串行外設接口(Serial Peripheral Interface)的縮寫,是一種高速的,全雙工,同步的通信總線,並且在芯片的管腳上只佔用四根線,節約了芯片的管腳,同時爲PCB的佈局上節省空間,提供方便,正是出於這種簡單易用的特性,越來越多的芯片集成了這種通信協議。
sck:時鐘線
MOSI:數據輸出線
MISO:數據輸入線
ss:片選線;
特點:全雙工,傳輸速率幾Mbps。
1.SPI初始化函數:
#define SPI_DEVICE_ID XPAR_XSPIPS_0_DEVICE_ID
XSpiPs_LookupConfig(SpiDeviceId); //查找設備基地址:0xE0006000,時鐘:166666672
XSpiPs_CfgInitialize((&SpiInstance), SpiConfig, //初始化設置
SpiConfig->BaseAddress);
裏面有個復位函數:XSpiPs_Reset(InstancePtr); //回到初始狀態
XSpiPs_WriteReg(InstancePtr->Config.BaseAddress, XSPIPS_CR_OFFSET,
XSPIPS_CR_RESET_STATE);
XSPIPS_CR_RESET_STATE= 0x00020000U /**< Mode Fail Generation Enable */
2.spi工作模式選擇,主要涉及時鐘極性和相位極性,還有主從模式
XSpiPs_SetOptions((&SpiInstance), XSPIPS_MASTER_OPTION); //XSPIPS_MASTER_OPTION=1
3. XSpiPs_SetClkPrescaler(&SpiInstance, XSPIPS_CLK_PRESCALE_64); //0x05U 64分頻
//這個函數的關鍵就是設置分頻係數,分頻係數一定,其他基本確定。
4.XSpiPs_Enable((&SpiInstance)); //0xE0006014=1 enable the SPI
5.發送函數
void SpiPs_Send(u8 *SendBuffer, int ByteCount)
{
u32 StatusReg;
int TransCount = 0;
/*
* Fill the TXFIFO with as many bytes as it will take (or as
* many as we have to send).
*/
while ((ByteCount > 0) && (TransCount < XSPIPS_FIFO_DEPTH)) //XSPIPS_FIFO_DEPTH=128
{
SpiPs_SendByte(SpiInstance.Config.BaseAddress,*SendBuffer);
//0x1CU /**< Data Transmit Register */
SendBuffer++;
++TransCount;
ByteCount--;
}
/*
* Wait for the transfer to finish by polling Tx fifo status.
*/
do {
StatusReg = XSpiPs_ReadReg(
SpiInstance.Config.BaseAddress,
XSPIPS_SR_OFFSET);
} while ((StatusReg & XSPIPS_IXR_TXOW_MASK) == 0);
}
將數據寫入數據發送寄存器;下半部分等待發送完成,沒有看明白,寄存器位第2位not_full。
等待發送完成。
XSPIPS_IXR_TXOW_MASK=0x4
6.接收函數
void SpiPs_Read(u8 *ReadBuffer,int ByteCount)
{
int Count;
u32 StatusReg;
do{
StatusReg = XSpiPs_ReadReg(SpiInstance.Config.BaseAddress,
XSPIPS_SR_OFFSET);
}while(!(StatusReg & XSPIPS_IXR_RXNEMPTY_MASK));
/*
* Reading the Rx Buffer
*/
for(Count = 0; Count < ByteCount; Count++){
ReadBuffer[Count] = SpiPs_RecvByte(
SpiInstance.Config.BaseAddress);
}
}
XSPIPS_IXR_RXNEMPTY_MASK=0x10
不斷判斷是否有數據,有數據則讀數據。
米聯客參考程序:
頭文件
#ifndef SRC_SPIPS_H_
#define SRC_SPIPS_H_
#include "xparameters.h" /* SDK generated parameters */
#include "xspips.h" /* SPI device driver */
#include "xil_printf.h"
void SpiPs_Read (u8 *ReadBuffer, int ByteCount);
void SpiPs_Send (u8 *SendBuffer, int ByteCount);
int SpiPs_Init (u16 SpiDeviceId);
#define SPI_DEVICE_ID XPAR_XSPIPS_0_DEVICE_ID
#define MAX_DATA 100
#define SpiPs_RecvByte(BaseAddress) (u8)XSpiPs_In32((BaseAddress) + XSPIPS_RXD_OFFSET)
#define SpiPs_SendByte(BaseAddress, Data) XSpiPs_Out32((BaseAddress) + XSPIPS_TXD_OFFSET, (Data))
XSpiPs SpiInstance;
#endif /* SRC_SPIPS_H_ */
主要子程序:
/*
* spips.c
*
* Created on: 2019年5月3日
* Author: Administrator
*/
#include "spips.h"
int SpiPs_Init(u16 SpiDeviceId)
{
int Status;
u8 *BufferPtr;
XSpiPs_Config *SpiConfig; //設備Id,地址和時鐘。
/*
* Initialize the SPI driver so that it's ready to use
*/
SpiConfig = XSpiPs_LookupConfig(SpiDeviceId); //查找設備基地址:0xE0006000,時鐘:166666672
if (NULL == SpiConfig) {
return XST_FAILURE;
}
Status = XSpiPs_CfgInitialize((&SpiInstance), SpiConfig, //初始化設置
SpiConfig->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* The SPI device is a slave by default and the clock phase
* have to be set according to its master. In this example, CPOL is set
* to quiescent high and CPHA is set to 1.
*/
Status = XSpiPs_SetOptions((&SpiInstance), XSPIPS_MASTER_OPTION); //XSPIPS_MASTER_OPTION=1
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = XSpiPs_SetClkPrescaler(&SpiInstance, XSPIPS_CLK_PRESCALE_64); //0x05U 64分頻
//這個函數的關鍵就是設置分頻係數,分頻係數一定,其他基本確定。
/*
* Enable the device.
*/
XSpiPs_Enable((&SpiInstance)); //0xE0006014=1 enable the SPI
return XST_SUCCESS;
}
void SpiPs_Read(u8 *ReadBuffer,int ByteCount)
{
int Count;
u32 StatusReg;
do{
StatusReg = XSpiPs_ReadReg(SpiInstance.Config.BaseAddress,
XSPIPS_SR_OFFSET);
}while(!(StatusReg & XSPIPS_IXR_RXNEMPTY_MASK));
/*
* Reading the Rx Buffer
*/
for(Count = 0; Count < ByteCount; Count++){
ReadBuffer[Count] = SpiPs_RecvByte(
SpiInstance.Config.BaseAddress);
}
}
void SpiPs_Send(u8 *SendBuffer, int ByteCount)
{
u32 StatusReg;
int TransCount = 0;
/*
* Fill the TXFIFO with as many bytes as it will take (or as
* many as we have to send).
*/
while ((ByteCount > 0) && (TransCount < XSPIPS_FIFO_DEPTH)) //XSPIPS_FIFO_DEPTH=128
{
SpiPs_SendByte(SpiInstance.Config.BaseAddress,*SendBuffer);
//0x1CU /**< Data Transmit Register */
SendBuffer++;
++TransCount;
ByteCount--;
}
/*
* Wait for the transfer to finish by polling Tx fifo status.
*/
do {
StatusReg = XSpiPs_ReadReg(
SpiInstance.Config.BaseAddress,
XSPIPS_SR_OFFSET);
} while ((StatusReg & XSPIPS_IXR_TXOW_MASK) == 0);
}
測試程序:
/*
* spi_test.c
*
* Created on: 2019年5月3日
* Author: Administrator
*/
#include "spips.h"
u8 ReadBuf[MAX_DATA]; //100
u8 SendBuf[MAX_DATA];
int main(void)
{
int i =0;
SpiPs_Init(SPI_DEVICE_ID); //宏定義XPAR_PS7_SPI_0_DEVICE_ID=0;
for(i=0;i<10;i++)
SendBuf[i]=i;
SpiPs_Send(SendBuf,10);
SpiPs_Read(ReadBuf,10);
for(i=0;i<10;i++)
{
xil_printf("%d,",ReadBuf[i]);
}
return 0;
}