#include "stm32f10x.h"                  // Device header

#define SPIFLASH_PERIPH_TYPE	(SPI2)
#define SPIFLASH_PERIPH_CLOCK	(RCC_APB1Periph_SPI2)

#define SPIFLASH_NSS_GPIO_RCC	(RCC_APB2Periph_GPIOB)
#define SPIFLASH_NSS_GPIO_PORT	(GPIOB)
#define SPIFLASH_NSS_GPIO_PIN	(GPIO_Pin_12)

#define SPIFLASH_SCK_GPIO_RCC	(RCC_APB2Periph_GPIOB)
#define SPIFLASH_SCK_GPIO_PORT	(GPIOB)
#define SPIFLASH_SCK_GPIO_PIN	(GPIO_Pin_13)

#define SPIFLASH_MISO_GPIO_RCC	(RCC_APB2Periph_GPIOB)
#define SPIFLASH_MISO_GPIO_PORT	(GPIOB)
#define SPIFLASH_MISO_GPIO_PIN	(GPIO_Pin_14)

#define SPIFLASH_MOSI_GPIO_RCC	(RCC_APB2Periph_GPIOB)
#define SPIFLASH_MOSI_GPIO_PORT	(GPIOB)
#define SPIFLASH_MOSI_GPIO_PIN	(GPIO_Pin_15)


/**
  * 函    数：SPI写SS引脚电平，SS仍由软件模拟
  * 参    数：BitValue 协议层传入的当前需要写入SS的电平，范围0~1
  * 返 回 值：无
  * 注意事项：此函数需要用户实现内容，当BitValue为0时，需要置SS为低电平，当BitValue为1时，需要置SS为高电平
  */
void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(SPIFLASH_NSS_GPIO_PORT, SPIFLASH_NSS_GPIO_PIN, (BitAction)BitValue);		//根据BitValue，设置SS引脚的电平
}

/**
  * 函    数：SPI初始化
  * 参    数：无
  * 返 回 值：无
  */
void MySPI_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	SPI_InitTypeDef SPI_InitStructure;						//定义结构体变量
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(SPIFLASH_NSS_GPIO_RCC, ENABLE);	//开启GPIOA的时钟
	RCC_APB2PeriphClockCmd(SPIFLASH_SCK_GPIO_RCC, ENABLE);	//开启GPIOA的时钟
	RCC_APB2PeriphClockCmd(SPIFLASH_MISO_GPIO_RCC, ENABLE);	//开启GPIOA的时钟
	RCC_APB2PeriphClockCmd(SPIFLASH_MOSI_GPIO_RCC, ENABLE);	//开启GPIOA的时钟

	if(SPIFLASH_PERIPH_TYPE == SPI1)
	{
		RCC_APB2PeriphClockCmd(SPIFLASH_PERIPH_CLOCK, ENABLE);	//开启SPI1的时钟
	}
	else
	{
		RCC_APB1PeriphClockCmd(SPIFLASH_PERIPH_CLOCK, ENABLE);
	}
	
	/*GPIO初始化*/
	// NSS
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = SPIFLASH_NSS_GPIO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SPIFLASH_NSS_GPIO_PORT, &GPIO_InitStructure);					//初始化为推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = SPIFLASH_SCK_GPIO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SPIFLASH_SCK_GPIO_PORT, &GPIO_InitStructure);					//初始化为复用推挽输出

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = SPIFLASH_MOSI_GPIO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SPIFLASH_MOSI_GPIO_PORT, &GPIO_InitStructure);					//初始化为复用推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = SPIFLASH_MISO_GPIO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(SPIFLASH_MISO_GPIO_PORT, &GPIO_InitStructure);					//将PA6引脚初始化为上拉输入
	
	/*SPI初始化*/
	
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;			//模式，选择为SPI主模式
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;	//方向，选择2线全双工
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//数据宽度，选择为8位
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;		//先行位，选择高位先行
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;	//波特率分频，选择128分频
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;				//SPI极性，选择低极性
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;			//SPI相位，选择第一个时钟边沿采样，极性和相位决定选择SPI模式0
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;				//NSS，选择由软件控制
	SPI_InitStructure.SPI_CRCPolynomial = 7;				//CRC多项式，暂时用不到，给默认值7
	SPI_Init(SPIFLASH_PERIPH_TYPE, &SPI_InitStructure);						//将结构体变量交给SPI_Init，配置SPI1
	
	/*SPI使能*/
	SPI_Cmd(SPIFLASH_PERIPH_TYPE, ENABLE);									//使能SPI1，开始运行
	
	/*设置默认电平*/
	MySPI_W_SS(1);											//SS默认高电平
}

/**
  * 函    数：SPI起始
  * 参    数：无
  * 返 回 值：无
  */
void MySPI_Start(void)
{
	MySPI_W_SS(0);				//拉低SS，开始时序
}

/**
  * 函    数：SPI终止
  * 参    数：无
  * 返 回 值：无
  */
void MySPI_Stop(void)
{
	MySPI_W_SS(1);				//拉高SS，终止时序
}

/**
  * 函    数：SPI交换传输一个字节，使用SPI模式0
  * 参    数：ByteSend 要发送的一个字节
  * 返 回 值：接收的一个字节
  */
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	while (SPI_I2S_GetFlagStatus(SPIFLASH_PERIPH_TYPE, SPI_I2S_FLAG_TXE) != SET);	//等待发送数据寄存器空
	
	SPI_I2S_SendData(SPIFLASH_PERIPH_TYPE, ByteSend);								//写入数据到发送数据寄存器，开始产生时序
	
	while (SPI_I2S_GetFlagStatus(SPIFLASH_PERIPH_TYPE, SPI_I2S_FLAG_RXNE) != SET);	//等待接收数据寄存器非空
	
	return SPI_I2S_ReceiveData(SPIFLASH_PERIPH_TYPE);								//读取接收到的数据并返回
}
