最近完成的一个项目因为SPI管脚被别的资源占用了,只能通过模拟SPI对存储器进行操作。最后测试发现模拟SPI的速度也很快,和硬件SPI相比感觉不到太大的差异。现将模拟SPI的程序分享如下:
管脚定义,大家可以根据需要自行修改,任何一个GPIO都可以模拟SPI
#define SPI_WP_PIN GPIO_Pin_6
#define SPI_WP_PORT GPIOC
#define SPI_CS_PIN GPIO_Pin_15
#define SPI_CS_PORT GPIOA
#define SPI_CLK_PIN GPIO_Pin_3
#define SPI_CLK_PORT GPIOB
#define SPI_MOSI_PIN GPIO_Pin_12
#define SPI_MOSI_PORT GPIOC
#define SPI_MISO_PIN GPIO_Pin_4
#define SPI_MISO_PORT GPIOB
#define SPI_BASE SPI3
#define SPI_FLASH_CS_LOW() GPIO_ResetBits(SPI_CS_PORT, SPI_CS_PIN) /* Select SPI MEM1: ChipSelect pin low */
#define SPI_FLASH_CS_HIGH() GPIO_SetBits(SPI_CS_PORT, SPI_CS_PIN) /* Deselect SPI MEM1: ChipSelect pin high */
#define SPI_FLASH_WP_LOW() GPIO_ResetBits(SPI_WP_PORT, SPI_WP_PIN) //PC4
#define SPI_FLASH_WP_HIGH() GPIO_SetBits(SPI_WP_PORT, SPI_WP_PIN) //PC4
模拟SPI MOSI MOSI CLK
//模拟MOSI
void SPI_MOSI(unsigned char Status)
{
if(Status)
GPIO_WriteBit(SPI_MOSI_PORT,SPI_MOSI_PIN,Bit_SET);
else
GPIO_WriteBit(SPI_MOSI_PORT,SPI_MOSI_PIN,Bit_RESET);
}
//模拟CLK
void SPI_CLK(unsigned char Status)
{
if(Status)
GPIO_WriteBit(SPI_CLK_PORT,SPI_CLK_PIN,Bit_SET);
else
GPIO_WriteBit(SPI_CLK_PORT,SPI_CLK_PIN,Bit_RESET);
}
//模拟MISO
unsigned char SPI_MISO(void)
{
if(GPIO_ReadInputDataBit(SPI_MISO_PORT,SPI_MISO_PIN))
return 1;
else
return 0;
}
SPI初始化
void gd25qxxInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = SPI_MOSI_PIN; //PA5:SCK,PA7:MOSI
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(SPI_MOSI_PORT, &GPIO_InitStructure);
SPI_MOSI(1);
GPIO_InitStructure.GPIO_Pin = SPI_CLK_PIN; //PA5:SCK,PA7:MOSI
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(SPI_CLK_PORT, &GPIO_InitStructure);
SPI_CLK(1);
GPIO_InitStructure.GPIO_Pin = SPI_MISO_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(SPI_MISO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = SPI_CS_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(SPI_CS_PORT, &GPIO_InitStructure);
SPI_FLASH_CS_HIGH();
GPIO_InitStructure.GPIO_Pin = SPI_WP_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(SPI_WP_PORT, &GPIO_InitStructure);
SPI_FLASH_WP_HIGH();
}
SPI数据输入输出
uint8_t gd25qxxSendByte(uint8_t byte)
{
unsigned char i,Result = 0;;
for(i=0;i<8;i++)
{
if(byte & 0x80) SPI_MOSI(1);
else SPI_MOSI(0);
byte <<= 1;
SPI_CLK(0);
SPI_CLK(1);
Result <<= 1;
if(SPI_MISO()) Result |= 0x01;
}
SPI_CLK(0);
return(Result);
}
示例:
uint32_t gd25qxxReadID(void)
{
uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
/* Select the FLASH: Chip Select low */
SPI_FLASH_CS_LOW();
/* Send "RDID " instruction */
gd25qxxSendByte(0x9F);
/* Read a byte from the FLASH */
Temp0 = gd25qxxSendByte(DUMMY_BYTE);
/* Read a byte from the FLASH */
Temp1 = gd25qxxSendByte(DUMMY_BYTE);
/* Read a byte from the FLASH */
Temp2 = gd25qxxSendByte(DUMMY_BYTE);
/* Deselect the FLASH: Chip Select high */
SPI_FLASH_CS_HIGH();
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
return Temp;
}