概要
SPI(Serial Peripheral Interface)是一种用于串行数据传输的通信协议,通常用于在数字集成电路之间进行通信。3线SPI是SPI协议的一种变种,它使用了三根线(或信号线)来进行通信,包括主设备的片选(NCS)、输入输出(SDIO)和时钟线(SCLK)。这种协议通常用于资源受限的系统或需要节省引脚的应用中。
3线SPI的优点之一是它只需要少量的引脚就能完成通信,这对于资源受限的嵌入式系统非常有用。然而,由于只有一个双向数据线,因此无法同时进行全双工通信,这意味着主设备和从设备不能同时发送和接收数据,通信效率可能会受到一定影响。
SPI初始化代码
SPI_Init函数中,首先对GPIO进行了初始化设置,包括SCLK(时钟信号)、NCS(片选信号)和IRO(输入/输出信号)还有IRON芯片的中断脚配置。然而mxs_reg_write和mxs_reg_read函数分别用于向特定寄存器写入数据和从特定寄存器读取数据。在这两个函数中,使用了mixo_hal_spi_write和mixo_hal_spi_read函数进行SPI数据传输。mixo_hal_spi_write和mixo_hal_spi_read函数分别用于SPI的数据写入和读取操作。这里主要涉及到了SPI的时钟信号和数据信号的控制。delay_us函数用于实现微秒级的延迟,这在处理SPI通信时可能会用到。SPI_Set_SDIO_Input和SPI_Set_SDIO_Output函数用于配置SDIO引脚为输入或输出模式。SDIO通常用于SPI接口中的数据线。
#include "header.h"
void SPI_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
SPI_SCLK_GPIO_CLK_ENABLE();
// SPI_NCS_GPIO_CLK_ENABLE();
SPI_IRO_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = SPI_SCLK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(SPI_SCLK_GPIO_PORT, &GPIO_InitStruct);
// HAL_GPIO_WritePin(SPI_SCLK_GPIO_PORT,SPI_SCLK_PIN,GPIO_PIN_SET);
// GPIO_InitStruct.Pin = SPI_NCS_PIN;
// GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
// GPIO_InitStruct.Pull = GPIO_NOPULL;
// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
// HAL_GPIO_Init(SPI_NCS_GPIO_PORT, &GPIO_InitStruct);
// HAL_GPIO_WritePin(SPI_NCS_GPIO_PORT,SPI_NCS_PIN,GPIO_PIN_RESET);
GPIO_InitStruct.Pin = SPI_IRO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SPI_IRO_GPIO_PORT, &GPIO_InitStruct);
}
void mxs_reg_write(uint8_t regAddr, uint8_t regData)
{
regAddr |= 0x80;
mixo_hal_spi_write(regAddr);
delay_us(10);
mixo_hal_spi_write(regData);
delay_us(20);
}
void mxs_reg_read(uint8_t regAddr, uint8_t* regData)
{
regAddr &= 0x7F;
mixo_hal_spi_write(regAddr);
delay_us(10);
mixo_hal_spi_read(regData);
delay_us(20);
}
void mixo_hal_spi_write(uint8_t data)
{
SPI_Set_SDIO_Output();
for (int j = 0; j < 8; j++)
{
SPI_SCLK_LOW();
if ((data & 0x80) != 0)
{
SPI_SDIO_HIGH();
}
else
{
SPI_SDIO_LOW();
}
data <<= 1;
delay_us(10);
SPI_SCLK_HIGH();
delay_us(10);
}
}
void mixo_hal_spi_read(uint8_t* buffer)
{
//uint8_t i = 0;
uint8_t tmp = 0;
SPI_Set_SDIO_Input();
for (int j = 0; j < 8; j++)
{
tmp <<= 1;
SPI_SCLK_LOW();
delay_us(10);
if (HAL_GPIO_ReadPin(SPI_SDIO_GPIO_PORT, SPI_SDIO_PIN))
{
tmp |= 1;
}
else
{
tmp |= 0;
}
SPI_SCLK_HIGH();
delay_us(10);
}
*buffer = tmp;
}
void delay_us(int us)
{
unsigned t1, t2, delta, sysclk; sysclk = 24;
t1 = SysTick->VAL;
while (1)
{
t2 = SysTick->VAL;
delta = t2 < t1 ? (t1 - t2) : (SysTick->LOAD - t2 + t1) ;
if (delta >= us * sysclk)
break;
}
}
void SPI_Set_SDIO_Input(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
SPI_SDIO_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = SPI_SDIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(SPI_SDIO_GPIO_PORT, &GPIO_InitStruct);
}
void SPI_Set_SDIO_Output(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
SPI_SDIO_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = SPI_SDIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(SPI_SDIO_GPIO_PORT, &GPIO_InitStruct);
}
SPI.h
#ifndef __SPI_H
#define __SPI_H
#include "stdint.h"
#define SPI_SDIO_PIN GPIO_PIN_1
#define SPI_SDIO_GPIO_PORT GPIOA
#define SPI_SDIO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define SPI_SCLK_PIN GPIO_PIN_0
#define SPI_SCLK_GPIO_PORT GPIOB
#define SPI_SCLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
//#define SPI_NCS_PIN GPIO_PIN_1
//#define SPI_NCS_GPIO_PORT GPIOC
//#define SPI_NCS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define SPI_IRO_PIN GPIO_PIN_7
#define SPI_IRO_GPIO_PORT GPIOB
#define SPI_IRO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPI_SDIO_HIGH() HAL_GPIO_WritePin(SPI_SDIO_GPIO_PORT,SPI_SDIO_PIN,GPIO_PIN_SET)
#define SPI_SDIO_LOW() HAL_GPIO_WritePin(SPI_SDIO_GPIO_PORT,SPI_SDIO_PIN,GPIO_PIN_RESET)
#define SPI_SCLK_HIGH() HAL_GPIO_WritePin(SPI_SCLK_GPIO_PORT,SPI_SCLK_PIN,GPIO_PIN_SET)
#define SPI_SCLK_LOW() HAL_GPIO_WritePin(SPI_SCLK_GPIO_PORT,SPI_SCLK_PIN,GPIO_PIN_RESET)
#define SPI_NCS_HIGH() HAL_GPIO_WritePin(SPI_NCS_GPIO_PORT,SPI_NCS_PIN,GPIO_PIN_SET)
#define SPI_NCS_LOW() HAL_GPIO_WritePin(SPI_NCS_GPIO_PORT,SPI_NCS_PIN,GPIO_PIN_RESET)
void SPI_Init(void);//初始化
void mxs_reg_write(uint8_t regAddr, uint8_t regData);
void mxs_reg_read(uint8_t regAddr, uint8_t* regData);
void mixo_hal_spi_write(uint8_t data);
void mixo_hal_spi_read(uint8_t* buffer);
void SPI_Delay(uint32_t us);
void SPI_Set_SDIO_Input(void);
void SPI_Set_SDIO_Output(void);
void delay_us(int us);
#endif
小结
3线SPI严格来说并不是SPI协议,因为只有SDIO进行数据传输而已,所以只是半双工传输, mxs_reg_write和mxs_reg_read里面分别有一个将最高位至1和0操作,这要根据使用的芯片手册提供的方法去配置。