八、赛普拉斯EZ-USB FX3 SPI

SPI是一种高速、同步、串行、全双工的通信技术,常用于嵌入式系统。协议包括主从模式,通过MOSI、MISO、SCLK和CS四条线进行通信。SPI有四种模式,取决于CPOL和CPHA的组合,影响数据采样的时机。文章还提供了初始化、配置和操作SPI的函数示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、简介

        SPI(Serial Perripheral Interface)串行外设接口,是由摩托罗拉(Motorola)推出的一种高速、同步、串行、全双工的通信技术,在嵌入式设备中广泛使用的接口协议。SPI支

        SPI分为两种模式:主模式,从模式,当作为主模式时可以挂载多个从设备,每个设备都有单独的片选线。

图1.0 SPI一主多从 

        SPI接口共有四根通信线,分别为MOSI、MISO、CS(SSN)、SCLK,当采用4根通信线则为全双工通信,当采用3根通信线则为单工通信:

                ·MOSI(Master Output Slave Input):主设备数据输出,从设备数据输入

                ·MISO(Master Input Slave Output):主设备的数据输入,从设备数据输出

                ·SCLK(Serial Clock):时钟信号,由主设备产生

                ·CS(Chip Select):片选信号,拉低选择对应的从设备

        SPI根据时钟相位(CPHA)与时钟极性(CPOL)的不同组合共有四种模式,它能决定数据是在什么时刻采样。

 图1.1 SPI采样模式

        SPI模式0,CPOL = 0,CPHA = 0,时钟空闲时为低电平,数据在时钟的偶数边沿采样(橙色线)

 图1.2 SPI模式0

         SPI模式1,CPOL = 0,CPHA = 1,时钟空闲时为低电平,数据在时钟的奇数边沿采样(橙色线)

 图1.3 SPI模式1

         SPI模式2,CPOL = 1,CPHA = 0,时钟空闲时为高电平,数据在时钟的奇数边沿采样(橙色线)

图1.4 SPI模式2

         SPI模式3,CPOL = 1,CPHA = 1,时钟空闲时为高电平,数据在时钟的偶数边沿采样(橙色线)

图1.5 SPI模式3 

二、程序

        初始化SPI设备函数

extern CyU3PReturnStatus_t
CyU3PSpiInit (
        void);

        配置SPI函数

extern CyU3PReturnStatus_t
CyU3PSpiSetConfig (
        CyU3PSpiConfig_t *config,       /**< Pointer to the SPI config structure. */
        CyU3PSpiIntrCb_t cb             /**< Callback for receiving SPI events. */
        );

        设置片选信号函数

extern CyU3PReturnStatus_t
CyU3PSpiSetSsnLine (
        CyBool_t isHigh                 /**< CyFalse: Pull down the SSN line, CyTrue: Pull up the SSN line. */
        ); 

         SPI发送函数(单位:字)

extern CyU3PReturnStatus_t
CyU3PSpiTransmitWords (
        uint8_t *data,                  /**< Source data pointer. This needs to be padded to nearest
                                byte if the word length is not byte aligned. */
        uint32_t byteCount              /**< This needs to be a multiple of the word length aligned to the next
                                             byte. */
        );

         SPI接收函数(单位:字)

extern CyU3PReturnStatus_t
CyU3PSpiReceiveWords (
        uint8_t *data,                  /**< Buffer to read the data into. */
        uint32_t byteCount              /**< Amount of data to be read. This should be an integral multiple
                                             of the SPI word length aligned to the next byte. */
        );

         SPI发送/接收函数(单位:字)

extern CyU3PReturnStatus_t
CyU3PSpiTransferWords (
        uint8_t  *txBuf,        /**< Source buffer containing data to transmit. Can be NULL if txByteCount is 0. */
        uint32_t  txByteCount,  /**< Number of data bytes to transmit. Needs to be a multiple of the word length
                                     aligned to the next byte. */
        uint8_t  *rxBuf,        /**< Destination buffer to receive data into. Can be NULL if rxByteCount is 0. */
        uint32_t  rxByteCount   /**< Number of data bytes to receive. Needs to be a multiple of the word length
                                     aligned to the next byte. */
        );

         SPI配置源文件

#include "cyfx3_spi.h"
#include "cyu3error.h"
#include "cyu3utils.h"


static CyU3PReturnStatus_t CyFx3GpioConfig(void)
{
	CyU3PReturnStatus_t CyFx3Status;

	//GPIO时钟配置(整个工程中只需要初始化一次)
	CyU3PGpioClock_t GpioClkConifg = {
		.fastClkDiv = 2,
		.slowClkDiv = 0,
		.halfDiv = 0,
		.simpleDiv = CY_U3P_GPIO_SIMPLE_DIV_BY_2,
		.clkSrc = CY_U3P_SYS_CLK,
	};
	CyFx3Status = CyU3PGpioInit(&GpioClkConifg,NULL);

	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

#if !SPI_HARDWARE

	CyU3PGpioSimpleConfig_t SpiMosiGpioConfig = {
		.outValue = CyTrue,
		.driveLowEn = CyTrue,
		.driveHighEn = CyTrue,
		.inputEn = CyFalse,
		.intrMode = CY_U3P_GPIO_NO_INTR,
	};
	CyFx3Status = CyU3PGpioSetSimpleConfig(SPI_MOSI_GPIO_PIN,&SpiMosiGpioConfig);

	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	CyU3PGpioSimpleConfig_t SpiMisoGpioConfig = {
		.outValue = CyTrue,
		.driveLowEn = CyFalse,
		.driveHighEn = CyFalse,
		.inputEn = CyTrue,
		.intrMode = CY_U3P_GPIO_NO_INTR,
	};
	CyFx3Status = CyU3PGpioSetSimpleConfig(SPI_MISO_GPIO_PIN,&SpiMisoGpioConfig);

	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	CyU3PGpioSimpleConfig_t SpiClkGpioConfig = {
		.outValue = CyTrue,
		.driveLowEn = CyTrue,
		.driveHighEn = CyTrue,
		.inputEn = CyFalse,
		.intrMode = CY_U3P_GPIO_NO_INTR,
	};
	CyFx3Status = CyU3PGpioSetSimpleConfig(SPI_CLK_GPIO_PIN,&SpiClkGpioConfig);

	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	CyU3PGpioSimpleConfig_t SpiSsnGpioConfig = {
		.outValue = CyTrue,
		.driveLowEn = CyTrue,
		.driveHighEn = CyTrue,
		.inputEn = CyFalse,
		.intrMode = CY_U3P_GPIO_NO_INTR,
	};
	return CyU3PGpioSetSimpleConfig(SPI_SSN_GPIO_PIN,&SpiSsnGpioConfig);

#endif
}


CyU3PReturnStatus_t CyFx3SpiInit(void)
{

#if !SPI_HARDWARE

	return CyFx3GpioConfig();

#else

	CyU3PReturnStatus_t CyFx3Status;

	CyFx3Status = CyU3PSpiInit();
	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	CyU3PSpiConfig_t SpiConfig = {
		.isLsbFirst = CyFalse,
		.cpol = CyFalse,
		.cpha = CyFalse,
		.ssnPol = CyFalse,
		.ssnCtrl = CyFalse,
		.leadTime = CY_U3P_SPI_SSN_LAG_LEAD_HALF_CLK,
		.lagTime = CY_U3P_SPI_SSN_LAG_LEAD_HALF_CLK,
		.clock = SPI_FREQUENCY,
		.wordLen = 8,
	};

	CyFx3Status = CyU3PSpiSetConfig(&SpiConfig,NULL);

	if(CyFx3Status != CY_U3P_SUCCESS)
	{
		return CyFx3Status;
	}

	return CyU3PSpiSetSsnLine(CyFalse);
#endif
}

#if !SPI_HARDWARE

static CyU3PReturnStatus_t SpiSetMosiValue(CyBool_t isHigh)
{
	return CyU3PGpioSetValue(SPI_MOSI_GPIO_PIN,isHigh);
}

static CyBool_t SpiGetMisoValue(void)
{
	return CyFx3GpioReadBit(SPI_MISO_GPIO_PIN);
}

static CyU3PReturnStatus_t SpiSetClkValue(CyBool_t isHigh)
{
	return CyU3PGpioSetValue(SPI_CLK_GPIO_PIN,isHigh);
}

CyU3PReturnStatus_t SpiSetSsnValue(CyBool_t isHigh)
{
	return CyU3PGpioSetValue(SPI_SSN_GPIO_PIN,isHigh);
}

//CPOL = 0, CPHA = 0, MSB first
uint64_t SpiReadWriteMode0(uint32_t write_dat1,uint32_t write_dat2,uint32_t len)
{
    uint32_t i;
    uint32_t read_dat;
    uint32_t testreadspi;

	if(len == 32)
    {
        for(i = 0;i < 32;i++)
        {
            if(write_dat1 & 0x80000000)
            {
            	SpiSetMosiValue(CyTrue);
            }
            else
            {
            	SpiSetMosiValue(CyFalse);
            }
            SpiSetClkValue(CyTrue);
            read_dat <<= 1;
            write_dat1 <<= 1;
            CyU3PBusyWait(1);
            if(SpiGetMisoValue() == CyTrue)
            {
               read_dat++;
            }

            SpiSetClkValue(CyFalse);
        }
		testreadspi = read_dat;
    }
    else if(len == 64)
    {
        for(i = 0;i < 32;i++)
        {
            if(write_dat1 & 0x80000000)
            {
            	SpiSetMosiValue(CyTrue);
            }
            else
            {
            	SpiSetMosiValue(CyFalse);
            }

            SpiSetClkValue(CyTrue);

            write_dat1 <<= 1;
            //CyU3PBusyWait(1);
            read_dat <<= 1;
            CyU3PBusyWait(1);
            if(SpiGetMisoValue() == CyTrue)
            {
                read_dat++;
            }

            SpiSetClkValue(CyFalse);
        }
		testreadspi = read_dat << 16;
        for(i = 0;i < 32;i++)
        {

            if(write_dat2 & 0x80000000)
            {
            	SpiSetMosiValue(CyTrue);
            }

            else
            {
            	SpiSetMosiValue(CyFalse);
            }

            SpiSetClkValue(CyTrue);

            write_dat2 <<= 1;
            read_dat <<= 1;
            CyU3PBusyWait(1);

            if(SpiGetMisoValue() == CyTrue)
            {
                read_dat++;
            }
            //CyU3PBusyWait(1);
            SpiSetClkValue(CyFalse);
        }
		testreadspi += read_dat >> 16;
    }
    return testreadspi;
}

uint8_t SpiReadWriteByte(uint8_t Byte)
{
	uint8_t i;

	for(i = 0;i < 8;i++)
	{
		if(Byte & 0x80)
		{
			SpiSetMosiValue(CyTrue);
		}
		else
		{
			SpiSetMosiValue(CyFalse);
		}
		Byte <<= 1;
		CyU3PBusyWait(1);
		SpiSetClkValue(CyFalse);
		if(SpiGetMisoValue() == CyTrue)
		{
			Byte |= 0x01;
		}
		CyU3PBusyWait(1);
		SpiSetClkValue(CyTrue);
	}

	/*
	for(i = 0;i < 8;i++)
	{
		SpiSetClkValue(CyTrue);
		if(Byte & 0x80)
		{
			SpiSetMosiValue(CyTrue);
		}
		else
		{
			SpiSetMosiValue(CyFalse);
		}
		Byte <<= 1;
		CyU3PBusyWait(1);
		SpiSetClkValue(CyFalse);

		if(SpiGetMisoValue() == CyTrue)
		{
			Byte |= 0x01;
		}
		CyU3PBusyWait(1);
	}
	*/
	return Byte;
}

void CyFx3SpiReceiveTransmitBytes(uint8_t *WriteData,uint8_t *ReadData,uint16_t DataLen)
{
	for(uint16_t i = 0;i < DataLen;i++)
	{
		ReadData[i] = SpiReadWriteByte(WriteData[i]);
	}
}

#endif

        SPI配置头文件

#ifndef CYFX3_SPI_H_
#define CYFX3_SPI_H_

#include "cyu3spi.h"
#include "cyu3gpio.h"
#include "gpio_regs.h"

#define SPI_HARDWARE					0
#define SPI_GPIO_REGS					0

#define SPI_FREQUENCY				    8000000U   //8MHz

#if !SPI_HARDWARE

#define CyFx3GpioReadBit(GpioPin)	    ((GPIO->lpp_gpio_simple[GpioPin]& CY_U3P_LPP_GPIO_IN_VALUE) >> 1)
#define CyFx3GpioSetBit(GpioPin)		((*(uvint32_t *)&GPIO->lpp_gpio_simple[GpioPin]) |= CY_U3P_LPP_GPIO_OUT_VALUE)
#define CyFx3GpioResetBit(GpioPin)		((*(uvint32_t *)&GPIO->lpp_gpio_simple[GpioPin]) &= ~CY_U3P_LPP_GPIO_OUT_VALUE)

#define SPI_MOSI_GPIO_PIN            	 51
#define SPI_MISO_GPIO_PIN            	 57
#define SPI_CLK_GPIO_PIN             	 50
#define SPI_SSN_GPIO_PIN              	 52

CyU3PReturnStatus_t SpiSetSsnValue(CyBool_t isHigh);
uint8_t SpiReadWriteByte(uint8_t WriteData);
void CyFx3SpiReceiveTransmitBytes(uint8_t *WriteData,uint8_t *ReadData,uint16_t DataLen);
#endif

CyU3PReturnStatus_t CyFx3SpiInit(void);
#endif /* CYFX3_SPI_H_ */
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值