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;
}