【>>>>>以下所写如果难以理解的部分或有什么建议,可留言交流<<<<<】
spi编程要点:
1 初始化spi结构体
2 功能操作函数
1主体函数部分main.c
uint8_t readbuff[4096];
uint8_t Writebuff[4096];
int main(void)
{
uint32_t id;
uint16_t i;
//串口
USART_Config();
//spi配置
SPI_FLASH_Config();
//读取设备id
id=SPI_Read_ID();
printf("0x%x\r\n",id);
//清除扇区
SPI_ERASE_SECTOR(0);
for(i=0;i<4096;i++)
{
Writebuff[i]=i;
}
//往spi-flash 里写入数据
SPI_Write_Data(0,Writebuff,4096);
//从里面读取数据
SPI_Read_Data(0,readbuff,4096);
for(i=0;i<4096;i++)
{
printf("0x%x",readbuff[i]);
if(i%10==0)
{
printf("\n");
}
}
}
2 相关函数bsp_flash_spi.c
#include "bsp_spi.h"
uint16_t FLASH_ADDRESS;
static __IO uint32_t SPITimeout = SPIT_LONG_TIMEOUT;
static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
/*spi_flash 配置*/
void SPI_FLASH_Config(void){
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
// 打开SPI GPIO的时钟
FLASH_SPI_GPIO_APBxClkCmd(FLASH_SPI_GPIO_CLK, ENABLE);
// 打开SPI外设的时钟
FLASH_SPI_APBxClkCmd(FLASH_SPI_CLK, ENABLE);
// 将FLASH_SPI SCL 的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCLK_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(FLASH_SPI_SCLK_GPIO_PORT, &GPIO_InitStructure);
// 将FLASH_SPI MOSI 的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
// 将FLASH_SPI MISO 的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(FLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
//初始化CS引脚,因为是用软件,所以为推挽输出模式
GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(FLASH_SPI_CS_GPIO_PORT, &GPIO_InitStructure);
FLASH_SPI_CS_HIGH;
// 配置SPI的工作参数
SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge;
SPI_InitStructure.SPI_CPOL=SPI_CPOL_High;
SPI_InitStructure.SPI_CRCPolynomial=0;//不使用CRC功能
SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;
SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;
SPI_InitStructure.SPI_Mode=SPI_Mode_Master;
SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;
SPI_Init(FLASH_SPIx,&SPI_InitStructure);
// // 串口中断优先级配置
// NVIC_Configuration();
//
// // 使能串口接收中断
// USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
//
// 使能SPI
SPI_Cmd(FLASH_SPIx, ENABLE);
}
/*写使能函数*/
void SPI_Write_Enable(void){
FLASH_SPI_CS_LOW;
SPI_FLASH_Send_Byte(Write_Enable);
FLASH_SPI_CS_HIGH;
}
/*发送一字节,并接收一字节*/
uint16_t SPI_FLASH_Send_Byte(uint8_t data){
//检查并等待至TX缓冲区为空
while(SPI_I2S_GetFlagStatus(FLASH_SPIx,SPI_I2S_FLAG_TXE)==RESET){
if(SPITimeout--==0)
{
return SPI_TIMEOUT_UserCallback(0);
}
}
//程序执行到此,TX缓冲区已空
SPI_I2S_SendData(FLASH_SPIx,data);
//检查并等待至rx缓冲区为空
while(SPI_I2S_GetFlagStatus(FLASH_SPIx,SPI_I2S_FLAG_RXNE)==RESET);
return SPI_I2S_ReceiveData(FLASH_SPIx);
}
/**
* @brief Basic management of the timeout situation.
* @param errorCode:错误代码,可以用来定位是哪个环节出错.
* @retval 返回0,表示SPI读取失败.
*/
/*超时回调函数*/
static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)
{
/* Block communication and all processes */
FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);
return 0;
}
/*读取一字节*/
//uint8_t SPI_FLASH_Read_Byte(void){
// return SPI_FLASH_Send_Byte(DUMMY);
//}
/*读取设备id*/
uint32_t SPI_Read_ID(void)
{
uint32_t flash_id;
FLASH_SPI_CS_LOW;
SPI_FLASH_Send_Byte(Read_jedecc_ID);
flash_id =SPI_FLASH_Send_Byte(DUMMY);
flash_id<<=8;
flash_id |=SPI_FLASH_Send_Byte(DUMMY);
flash_id<<=8;
flash_id |=SPI_FLASH_Send_Byte(DUMMY);
FLASH_SPI_CS_HIGH;
return flash_id;
}
/*读取数据*/
void SPI_Read_Data(uint32_t addr,uint8_t*buff,uint32_t numBytetoRead){
//SPI_Write_Enable();
FLASH_SPI_CS_LOW;
SPI_FLASH_Send_Byte(Read_data);
SPI_FLASH_Send_Byte(addr>>16&0xff);
SPI_FLASH_Send_Byte(addr>>8&0xff);
SPI_FLASH_Send_Byte(addr&0xff);
while(numBytetoRead--)
{
*buff=SPI_FLASH_Send_Byte(DUMMY);
buff++;
}
FLASH_SPI_CS_HIGH;
SPI_WaitForWriteEnd();
}
/*写数据*/
void SPI_Write_Data(uint32_t addr,uint8_t*Writebuff,uint32_t numBytetoRead){
FLASH_SPI_CS_LOW;
SPI_Write_Enable();
SPI_WaitForWriteEnd();
SPI_FLASH_Send_Byte(Write_Data);
SPI_FLASH_Send_Byte((addr & 0xFF0000) >> 16);
SPI_FLASH_Send_Byte((addr & 0xFF00) >> 8);
SPI_FLASH_Send_Byte((addr & 0xFF));
while(numBytetoRead--)
{
SPI_FLASH_Send_Byte(*Writebuff);
Writebuff++;
}
FLASH_SPI_CS_HIGH;
SPI_WaitForWriteEnd();
}
/*擦出扇区*/
void SPI_ERASE_SECTOR(uint32_t addr){
FLASH_SPI_CS_LOW;
SPI_Write_Enable();
SPI_WaitForWriteEnd();
SPI_FLASH_Send_Byte(ERASE_SECTOR);
SPI_FLASH_Send_Byte((addr & 0xFF0000) >> 16);
SPI_FLASH_Send_Byte((addr & 0xFF00) >> 8);
SPI_FLASH_Send_Byte(addr & 0xFF);
FLASH_SPI_CS_HIGH;
SPI_WaitForWriteEnd();
}
/等待操作完成/
void SPI_WaitForWriteEnd(void){
uint8_t status_reg=0;
SPI_FLASH_Send_Byte(READ_STATUS);
do{
status_reg=SPI_FLASH_Send_Byte(DUMMY);
}while((status_reg&0x01)==1);
FLASH_SPI_CS_HIGH;
}
3 相关头文件bsp_spi_flash.h
/*spi_flash*/
#ifndef _BSP_SPI_H
#define _BSP_SPI_H
#include "stm32f10x.h"
#include <stdio.h>
/*等待超时时间*/
#define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define SPIT_LONG_TIMEOUT ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))
#define FLASH_ERROR(fmt,arg...) printf("<<-EEPROM-ERROR->> "fmt"\n",##arg)
//板配spi获取信息时所需的各种命令
#define USE_BD 1
#define DUMMY 0x00
#define Read_jedecc_ID 0x9f
#define ERASE_SECTOR 0x20
#define READ_STATUS 0x05
#define Write_Enable 0x06
#define Read_data 0x03
#define Write_Data 0x02
#define FLASH_SPIx SPI1
#define FLASH_SPI_APBxClkCmd RCC_APB2PeriphClockCmd
#define FLASH_SPI_CLK RCC_APB2Periph_SPI1
#define FLASH_SPI_BAUDRATE 400000
// USART GPIO 引脚宏定义
#define FLASH_SPI_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#if (USE_BD ==1)
#define FLASH_SPI_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define FLASH_SPI_CS_GPIO_PORT GPIOA
#define FLASH_SPI_CS_GPIO_PIN GPIO_Pin_4
#else
#define FLASH_SPI_GPIO_CLK (RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC)
#define FLASH_SPI_CS_GPIO_PORT GPIOC
#define FLASH_SPI_CS_GPIO_PIN GPIO_Pin_0
#endif
#define FLASH_SPI_SCLK_GPIO_PORT GPIOA
#define FLASH_SPI_SCLK_GPIO_PIN GPIO_Pin_5
#define FLASH_SPI_MOSI_GPIO_PORT GPIOA
#define FLASH_SPI_MOSI_GPIO_PIN GPIO_Pin_7
#define FLASH_SPI_MISO_GPIO_PORT GPIOA
#define FLASH_SPI_MISO_GPIO_PIN GPIO_Pin_6
/*宏定义*/
#define FLASH_SPI_CS_HIGH GPIO_SetBits(FLASH_SPI_CS_GPIO_PORT,FLASH_SPI_CS_GPIO_PIN)
#define FLASH_SPI_CS_LOW GPIO_ResetBits(FLASH_SPI_CS_GPIO_PORT,FLASH_SPI_CS_GPIO_PIN)
void SPI_Write_Enable(void);
void SPI_FLASH_Config(void);
uint16_t SPI_FLAHS_Send_Byte(uint8_t data);
static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);
uint8_t SPI_FLASH_Read_Byte(void);
uint32_t SPI_Read_ID(void);
void SPI_Read_Data(uint32_t addr,uint8_t*buff,uint32_t numBytetoRead);
void SPI_Write_Data(uint32_t addr,uint8_t*Writebuff,uint32_t numBytetoRead);
void SPI_ERASE_SECTOR(uint32_t addr);
void SPI_WaitForWriteEnd(void);
#endif/* _BSP_SPI_H*/