嵌入式系统:SPI

  • Post author:
  • Post category:其他




一、SPI

在这里插入图片描述




(一)SPI协议


1.通信方式

(1)同步串行

(2)全双工



2.电路连接


在这里插入图片描述

(1)NSS:从机选择引脚(低电平有效)

(2)SCK:同步时钟信号引脚

(3)MOSI:主发从收,主机发送数据引脚

(4)MISO:主收从发,主机接收数据引脚



3.数据传输时序

:由于SPI的灵活性,共有四种工作时序

(1)

时钟的极性与相位

  • 时钟极性(CPOL):总线空闲时的电平状态


    • CPOL = 1,总线空闲时为高电平

    • CPOL = 0,总线空闲时为低电平
  • 时钟相位(CPHA):信号采集跳变沿选择


    • CPHA = 1,在第二个跳变沿数据被采样

    • CPHA = 0,在第一个跳变沿数据被采样

(2)

工作模式

(不需实际硬背,根据时钟的相位和极性可推出)

在这里插入图片描述

  • CPOL = 1,CPHA = 0,

    时钟下降沿发送数据

    ,上升沿接收数据
  • CPOL = 0,CPHA = 0,

    时钟上升沿发送数据

    ,下降沿接收数据

在这里插入图片描述

  • CPOL = 1,CPHA = 1,

    时钟上升沿发送数据

    ,下降沿接收数据
  • CPOL = 0,CPHA = 1,

    时钟下降沿发送数据

    ,上升沿接收数据



(二)数据读写流程


1.从机选择


2.读写数据(全双工,写数据的同时读数据,一个时钟周期)




(三)编程


1.编程流程

(1)GPIO复用为SPI模式(硬件SPI)

(2)

SPI功能配置

  • 波特率(时钟频率)
  • 工作模式选择(主从模式 + 四种方式)
  • 数据格式(MSB/LSB)
  • 数据位数(8bit/16bit)

(3)SPI模式使能

(4)SPI中断配置

  • 中断源
  • 中断优先级
  • 中断使能

(5)数据收发

  • 查询模式
  • 中断模式
  • DMA模式


2.编程实例

(1)寄存器版本

#include "msp.h"
#include "driverlib.h"

void main()
{
	WDTCTL = WDTPW + WDTHOLD;
	
	//GPIO复用为SPI
	P1->SEL0 |= (BIT4 | BIT5 | BIT6 | BIT7);
	P1->SEL1 &=~(BIT4 | BIT5 | BIT6 | BIT7);
	

	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_SWRST;
	
	//时钟源选择:3MHz
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_SSEL__SMCLK;
	//传输速率:500KHz
	EUSCI_B0->BRW = 6;
	
	//SPI(四线)、主机、高位优先
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_MODE_2 | EUSCI_B_CTLW0_MST | EUSCI_B_CTLW0_MSB;
	
	//时钟极性1,时钟相位1(第四种模式:空闲时为高电平,上升沿有效)
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_CKPL | EUSCI_B_CTLW0_CKPH;
	
	EUSCI_B0->CTLW0 &=~EUSCI_B_CTLW0_SWRST;
	
	//清除接收中断标志位
	EUSCI_B0->IFG &=~EUSCI_B_IFG_RXIFG0;
	
	//接收中断使能
	EUSCI_B0->IE |= EUSCI_B_IE_RXIE0;
	
	//选择从机
	EUSCI_B0->CTLW0 |= EUSCI_B_CTLW0_STEM;

	//发送数据
	EUSCI_B0->TXBUF = 0xAA;

	while(1);
}

uint8_t recvData = 0;
void EUSCIB0_IRQHandler(void)
{
	//接收中断
	if(EUSCI_B0->IFG & EUSCI_B_IFG_RXIFG0)
	{
		//清除接收中断标志位
		EUSCI_B0->IFG &=~EUSCI_B_IFG_RXIFG0;
		
		//接收数据
		recvData = EUSCI_B0->RXBUF;
	}
}

(2)库函数版本

#include "msp.h"
#include "driverlib.h"

void main()
{
	/* Halting WDT  */
    WDT_A_holdTimer();
	
	/* Selecting P1.5 P1.6 and P1.7 in SPI mode */
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1, GPIO_PIN4 | GPIO_PIN5 | GPIO_PIN6 | GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION);
	
	/* Configuring SPI in 4wire master mode */
	eUSCI_SPI_MasterConfig spiMasterConfig;
	
	spiMasterConfig.selectClockSource		= EUSCI_B_SPI_CLOCKSOURCE_SMCLK;
	spiMasterConfig.clockSourceFrequency	= 3000000;
	spiMasterConfig.desiredSpiClock			= 500000;
	spiMasterConfig.spiMode					= EUSCI_SPI_4PIN_UCxSTE_ACTIVE_LOW;
	spiMasterConfig.clockPolarity			= EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;
	spiMasterConfig.clockPhase				= EUSCI_SPI_PHASE_DATA_CAPTURED_ONFIRST_CHANGED_ON_NEXT;
	spiMasterConfig.msbFirst				= EUSCI_B_SPI_MSB_FIRST;
	
	SPI_initMaster(EUSCI_B0_BASE, &spiMasterConfig);
	
	/* Enable SPI module */
	SPI_enableModule(EUSCI_B0_BASE);
	
	/* Enabling interrupts */
    SPI_enableInterrupt(EUSCI_B0_BASE, EUSCI_SPI_RECEIVE_INTERRUPT);
	
	//选择从机
	SPI_selectFourPinFunctionality(EUSCI_B0_BASE,EUSCI_SPI_ENABLE_SIGNAL_FOR_4WIRE_SLAVE);
	
	
	/* Polling to see if the TX buffer is ready */
    while (!(SPI_getInterruptStatus(EUSCI_B0_BASE,EUSCI_SPI_TRANSMIT_INTERRUPT)));

    /* Transmitting data to slave */
    SPI_transmitData(EUSCI_B0_BASE, 0xAA);

	while(1);
}

uint8_t recvData = 0;
void EUSCIB0_IRQHandler(void)
{
	uint32_t status = SPI_getEnabledInterruptStatus(EUSCI_B0_BASE);
	
    if(status & EUSCI_SPI_RECEIVE_INTERRUPT)
    {
    	//Clear Receive Interrupt Flag
    	SPI_clearInterruptFlag(EUSCI_B0_BASE,EUSCI_SPI_RECEIVE_INTERRUPT);
        /* USCI_B0 TX buffer ready? */
        while (!(SPI_getInterruptStatus(EUSCI_B0_BASE, EUSCI_SPI_TRANSMIT_INTERRUPT)));

        recvData = SPI_receiveData(EUSCI_B0_BASE);
    }
}



版权声明:本文为weixin_45366970原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。