1.SPI与外部flash通信实验。
spi.h
#ifndef __BSP_SPIFLASH_H__ #define __BSP_SPIFLASH_H__ /* 包含头文件 ----------------------------------------------------------------*/ #include "stm32f4xx_hal.h" /* 类型定义 ------------------------------------------------------------------*/ /* 宏定义 --------------------------------------------------------------------*/ //#define SPI_FLASH_ID 0x3015 //W25X16 2MB //#define SPI_FLASH_ID 0x4015 //W25Q16 4MB //#define SPI_FLASH_ID 0X4017 //W25Q64 8MB #define SPI_FLASH_ID 0X4018 //W25Q128 16MB YS-F4Pro默认使用开发 #define FLASH_SPIx SPI2 #define FLASH_SPIx_RCC_CLK_ENABLE() __HAL_RCC_SPI2_CLK_ENABLE() #define FLASH_SPIx_RCC_CLK_DISABLE() __HAL_RCC_SPI2_CLK_DISABLE() #define FLASH_SPI_GPIO_ClK_ENABLE() {__HAL_RCC_GPIOI_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();} #define FLASH_SPI_GPIO_PORT GPIOI #define FLASH_SPI_SCK_PIN GPIO_PIN_1 #define FLASH_SPI_MOSI_PIN GPIO_PIN_3 #define FLASH_SPI_CS_PIN GPIO_PIN_0 #define FLASH_SPI_CS_ENABLE() HAL_GPIO_WritePin(FLASH_SPI_GPIO_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_RESET) #define FLASH_SPI_CS_DISABLE() HAL_GPIO_WritePin(FLASH_SPI_GPIO_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_SET) #define FLASH_SPI_MISO_PORT GPIOC #define FLASH_SPI_MISO_PIN GPIO_PIN_2 /* 扩展变量 ------------------------------------------------------------------*/ extern SPI_HandleTypeDef hspiflash; /* 函数声明 ------------------------------------------------------------------*/ void MX_SPIFlash_Init(void); void SPI_FLASH_SectorErase(uint32_t SectorAddr); void SPI_FLASH_BulkErase(void); void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead); uint32_t SPI_FLASH_ReadID(void); uint32_t SPI_FLASH_ReadDeviceID(void); void SPI_FLASH_StartReadSequence(uint32_t ReadAddr); void SPI_Flash_PowerDown(void); void SPI_Flash_WAKEUP(void); uint8_t SPI_FLASH_ReadByte(void); uint8_t SPI_FLASH_SendByte(uint8_t byte); void SPI_FLASH_WriteEnable(void); void SPI_FLASH_WaitForWriteEnd(void); #endif /* __BSP_SPIFLASH_H__ */
spi.c
#include "spiflash/bsp_spiflash.h" #include "usart/bsp_debug_usart.h" /* 定义私有类型 --------------------------------------------------------------*/ /* 私有宏定义 ----------------------------------------------------------------*/ /* 指令的含义取决于手册 */ #define SPI_FLASH_PageSize 256 #define SPI_FLASH_PerWritePageSize 256 #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg 0x05 #define W25X_WriteStatusReg 0x01 #define W25X_ReadData 0x03 #define W25X_FastReadData 0x0B #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 #define W25X_BlockErase 0xD8 #define W25X_SectorErase 0x20 #define W25X_ChipErase 0xC7 #define W25X_PowerDown 0xB9 #define W25X_ReleasePowerDown 0xAB #define W25X_DeviceID 0xAB #define W25X_ManufactDeviceID 0x90 #define W25X_JedecDeviceID 0x9F #define WIP_Flag 0x01 /* Write In Progress (WIP) flag */ #define Dummy_Byte 0xFF /* 私有变量 ------------------------------------------------------------------*/ SPI_HandleTypeDef hspiflash; /* 扩展变量 ------------------------------------------------------------------*/ /* 私有函数原形 --------------------------------------------------------------*/ /* 函数体 --------------------------------------------------------------------*/ /** * 函数功能: 串行FLASH初始化 * 输入参数: huart:串口句柄类型指针 * 返 回 值: 无 * 说 明: 该函数被HAL库内部调用 */ void MX_SPIFlash_Init(void) { hspiflash.Instance = FLASH_SPIx; hspiflash.Init.Mode = SPI_MODE_MASTER;//主模式 hspiflash.Init.Direction = SPI_DIRECTION_2LINES;///双向(两条线) hspiflash.Init.DataSize = SPI_DATASIZE_8BIT; //8位数据帧长度 hspiflash.Init.CLKPolarity = SPI_POLARITY_LOW; //时钟极性低 hspiflash.Init.CLKPhase = SPI_PHASE_1EDGE;//奇数位 时钟相位 hspiflash.Init.NSS = SPI_NSS_SOFT;///软件片选择 hspiflash.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4.//预分频率系数为4 hspiflash.Init.FirstBit = SPI_FIRSTBIT_MSB;//MSB先行 hspiflash.Init.TIMode = SPI_TIMODE_DISABLE; hspiflash.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//CRC校验失能 hspiflash.Ini.CRCPolynomial = 10;
HAL_SPI_Init(&hspiflash);
}
/**
* 函数功能: SPI外设系统级初始化
* 输入参数: hspi:SPI句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hspi->Instance==FLASH_SPIx)
{
/* SPI外设时钟使能 */
FLASH_SPIx_RCC_CLK_ENABLE();
/* GPIO外设时钟使能 */
FLASH_SPI_GPIO_ClK_ENABLE();
/**SPI2 GPIO Configuration
PI0 ------> SPI2_NSS
PI1 ------> SPI2_SCK
PC2 ------> SPI2_MISO
PI3 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = FLASH_SPI_SCK_PIN|FLASH_SPI_MOSI_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(FLASH_SPI_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = FLASH_SPI_MISO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStruct);
HAL_GPIO_WritePin(FLASH_SPI_GPIO_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_SET);
GPIO_InitStruct.Pin = FLASH_SPI_CS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(FLASH_SPI_GPIO_PORT, &GPIO_InitStruct);
}
}
/**
* 函数功能: SPI外设系统级反初始化
* 输入参数: hspi:SPI句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
if(hspi->Instance==FLASH_SPIx)
{
/* SPI外设时钟禁用 */
FLASH_SPIx_RCC_CLK_DISABLE();
/**SPI2 GPIO Configuration
PI0 ------> SPI2_NSS
PI1 ------> SPI2_SCK
PC2 ------> SPI2_MISO
PI3 ------> SPI2_MOSI
*/
HAL_GPIO_DeInit(FLASH_SPI_GPIO_PORT, FLASH_SPI_SCK_PIN|FLASH_SPI_MOSI_PIN|FLASH_SPI_CS_PIN);
HAL_GPIO_DeInit(FLASH_SPI_MISO_PORT, FLASH_SPI_MISO_PIN);
}
}
/**
* 函数功能: 擦除扇区
* 输入参数: SectorAddr:待擦除扇区地址,要求为4096倍数
* 返 回 值: 无
* 说 明:串行Flash最小擦除块大小为4KB(4096字节),即一个扇区大小,要求输入参数
* 为4096倍数。在往串行Flash芯片写入数据之前要求先擦除空间。
*/
void SPI_FLASH_SectorErase(uint32_t SectorAddr)
{
/* 发送FLASH写使能命令 */
SPI_FLASH_WriteEnable();
SPI_FLASH_WaitForWriteEnd();
/* 擦除扇区 */
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送扇区擦除指令*/
SPI_FLASH_SendByte(W25X_SectorErase);
/*发送擦除扇区地址的高位*/
SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
/* 发送擦除扇区地址的中位 */
SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
/* 发送擦除扇区地址的低位 */
SPI_FLASH_SendByte(SectorAddr & 0xFF);
/* 禁用串行FLASH: CS 高电平 */
FLASH_SPI_CS_DISABLE();
/* 等待擦除完毕*/
SPI_FLASH_WaitForWriteEnd();
}
/**
* 函数功能: 擦除整片
* 输入参数: 无
* 返 回 值: 无
* 说 明:擦除串行Flash整片空间
*/
void SPI_FLASH_BulkErase(void)
{
/* 发送FLASH写使能命令 */
SPI_FLASH_WriteEnable();
/* 整片擦除 Erase */
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送整片擦除指令*/
SPI_FLASH_SendByte(W25X_ChipErase);
/* 禁用串行FLASH: CS高电平 */
FLASH_SPI_CS_DISABLE();
/* 等待擦除完毕*/
SPI_FLASH_WaitForWriteEnd();
}
/**
* 函数功能: 往串行FLASH按页写入数据,调用本函数写入数据前需要先擦除扇区
* 输入参数: pBuffer:待写入数据的指针
* WriteAddr:写入地址
* NumByteToWrite:写入数据长度,必须小于等于SPI_FLASH_PerWritePageSize
* 返 回 值: 无
* 说 明:串行Flash每页大小为256个字节
*/
void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
/* 发送FLASH写使能命令 */
SPI_FLASH_WriteEnable();
/* 寻找串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 写送写指令*/
SPI_FLASH_SendByte(W25X_PageProgram);
/*发送写地址的高位*/
SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
/*发送写地址的中位*/
SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
/*发送写地址的低位*/
SPI_FLASH_SendByte(WriteAddr & 0xFF);
if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
{
NumByteToWrite = SPI_FLASH_PerWritePageSize;
//printf("Err: SPI_FLASH_PageWrite too large!\n");
}
/* 写入数据*/
while (NumByteToWrite--)
{
/* 发送当前要写入的字节数据 */
SPI_FLASH_SendByte(*pBuffer);
/* 指向下一字节数据 */
pBuffer++;
}
/* 禁用串行FLASH: CS 高电平 */
FLASH_SPI_CS_DISABLE();
/* 等待写入完毕*/
SPI_FLASH_WaitForWriteEnd();
}
/**
* 函数功能: 往串行FLASH写入数据,调用本函数写入数据前需要先擦除扇区
* 输入参数: pBuffer:待写入数据的指针
* WriteAddr:写入地址
* NumByteToWrite:写入数据长度
* 返 回 值: 无
* 说 明:该函数可以设置任意写入数据长度
*/
void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = WriteAddr % SPI_FLASH_PageSize;
count = SPI_FLASH_PageSize - Addr;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
if (Addr == 0) /* 若地址与 SPI_FLASH_PageSize 对齐 */
{
if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
else /* 若地址与 SPI_FLASH_PageSize 不对齐 */
{
if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */
{
if (NumOfSingle > count) /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */
{
temp = NumOfSingle - count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
}
else
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
if (NumOfSingle != 0)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
}
}
/**
* 函数功能: 从串行Flash读取数据
* 输入参数: pBuffer:存放读取到数据的指针
* ReadAddr:读取数据目标地址
* NumByteToRead:读取数据长度
* 返 回 值: 无
* 说 明:该函数可以设置任意读取数据长度
*/
void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送 读 指令 */
SPI_FLASH_SendByte(W25X_ReadData);
/* 发送 读 地址高位 */
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/* 发送 读 地址中位 */
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/* 发送 读 地址低位 */
SPI_FLASH_SendByte(ReadAddr & 0xFF);
while (NumByteToRead--) /* 读取数据 */
{
/* 读取一个字节*/
*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
/* 指向下一个字节缓冲区 */
pBuffer++;
}
/* 禁用串行FLASH: CS 高电平 */
FLASH_SPI_CS_DISABLE();
}
/**
* 函数功能: 读取串行Flash型号的ID
* 输入参数: 无
* 返 回 值: uint32_t:串行Flash的型号ID
* 说 明: FLASH_ID IC型号 存储空间大小
0x3015 W25X16 2M byte
0x4015 W25Q16 4M byte
0X4017 W25Q64 8M byte
0X4018 W25Q128 16M byte (YS-F1Pro开发板默认配置)
*/
uint32_t SPI_FLASH_ReadID(void)
{
uint32_t Temp = 0, Temp1 = 0, Temp2 = 0;
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送命令:读取芯片型号ID */
SPI_FLASH_SendByte(W25X_JedecDeviceID);
/* 从串行Flash读取一个字节数据 */
Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
/* 从串行Flash读取一个字节数据 */
Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
/* 从串行Flash读取一个字节数据 */
Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
/* 禁用串行Flash:CS高电平 */
FLASH_SPI_CS_DISABLE();
Temp = Temp1 << 8 | Temp2;
return Temp;
}
/**
* 函数功能: 读取串行Flash设备ID
* 输入参数: 无
* 返 回 值: uint32_t:串行Flash的设备ID
* 说 明:
*/
uint32_t SPI_FLASH_ReadDeviceID(void)
{
uint32_t Temp = 0;
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送命令:读取芯片设备ID * */
SPI_FLASH_SendByte(W25X_DeviceID);
SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_SendByte(Dummy_Byte);
/* 从串行Flash读取一个字节数据 */
Temp = SPI_FLASH_SendByte(Dummy_Byte);
/* 禁用串行Flash:CS高电平 */
FLASH_SPI_CS_DISABLE();
return Temp;
}
/**
* 函数功能: 启动连续读取数据串
* 输入参数: ReadAddr:读取地址
* 返 回 值: 无
* 说 明:Initiates a read data byte (READ) sequence from the Flash.
* This is done by driving the /CS line low to select the device,
* then the READ instruction is transmitted followed by 3 bytes
* address. This function exit and keep the /CS line low, so the
* Flash still being selected. With this technique the whole
* content of the Flash is read with a single READ instruction.
*/
void SPI_FLASH_StartReadSequence(uint32_t ReadAddr)
{
/* Select the FLASH: Chip Select low */
FLASH_SPI_CS_ENABLE();
/* Send "Read from Memory " instruction */
SPI_FLASH_SendByte(W25X_ReadData);
/* Send the 24-bit address of the address to read from -----------------------*/
/* Send ReadAddr high nibble address byte */
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/* Send ReadAddr medium nibble address byte */
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/* Send ReadAddr low nibble address byte */
SPI_FLASH_SendByte(ReadAddr & 0xFF);
}
/**
* 函数功能: 从串行Flash读取一个字节数据
* 输入参数: 无
* 返 回 值: uint8_t:读取到的数据
* 说 明:This function must be used only if the Start_Read_Sequence
* function has been previously called.
*/
uint8_t SPI_FLASH_ReadByte(void)
{
uint8_t d_read,d_send=Dummy_Byte;
if(HAL_SPI_TransmitReceive(&hspiflash,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)
d_read=Dummy_Byte;
return d_read;
}
/**
* 函数功能: 往串行Flash读取写入一个字节数据并接收一个字节数据
* 输入参数: byte:待发送数据
* 返 回 值: uint8_t:接收到的数据
* 说 明:无
*/
uint8_t SPI_FLASH_SendByte(uint8_t byte)
{
uint8_t d_read,d_send=byte;
if(HAL_SPI_TransmitReceive(&hspiflash,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)
d_read=Dummy_Byte;
return d_read;
}
/**
* 函数功能: 使能串行Flash写操作
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void SPI_FLASH_WriteEnable(void)
{
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送命令:写使能 */
SPI_FLASH_SendByte(W25X_WriteEnable);
/* 禁用串行Flash:CS高电平 */
FLASH_SPI_CS_DISABLE();
}
/**
* 函数功能: 等待数据写入完成
* 输入参数: 无
* 返 回 值: 无
* 说 明:Polls the status of the Write In Progress (WIP) flag in the
* FLASH's status register and loop until write opertaion
* has completed.
*/
void SPI_FLASH_WaitForWriteEnd(void)
{
uint8_t FLASH_Status = 0;
/* Select the FLASH: Chip Select low */
FLASH_SPI_CS_ENABLE();
/* Send "Read Status Register" instruction */
SPI_FLASH_SendByte(W25X_ReadStatusReg);
/* Loop as long as the memory is busy with a write cycle */
do
{
/* Send a dummy byte to generate the clock needed by the FLASH
and put the value of the status register in FLASH_Status variable */
FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
}
while ((FLASH_Status & WIP_Flag) == SET); /* Write in progress */
/* Deselect the FLASH: Chip Select high */
FLASH_SPI_CS_DISABLE();
}
/**
* 函数功能: 进入掉电模式
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void SPI_Flash_PowerDown(void)
{
/* Select the FLASH: Chip Select low */
FLASH_SPI_CS_ENABLE();
/* Send "Power Down" instruction */
SPI_FLASH_SendByte(W25X_PowerDown);
/* Deselect the FLASH: Chip Select high */
FLASH_SPI_CS_DISABLE();
}
/**
* 函数功能: 唤醒串行Flash
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void SPI_Flash_WAKEUP(void)
{
/* Select the FLASH: Chip Select low */
FLASH_SPI_CS_ENABLE();
/* Send "Power Down" instruction */
SPI_FLASH_SendByte(W25X_ReleasePowerDown);
/* Deselect the FLASH: Chip Select high */
FLASH_SPI_CS_DISABLE();
}
main.c
#include "stm32f4xx_hal.h"
#include "usart/bsp_debug_usart.h"
#include "spiflash/bsp_spiflash.h"
#include "led/bsp_led.h"
/* 私有类型定义 --------------------------------------------------------------*/
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
/* 私有宏定义 ----------------------------------------------------------------*/
/* 获取缓冲区的长度 */
#define countof(a) (sizeof(a) / sizeof(*(a)))
#define TxBufferSize1 (countof(TxBuffer1) - 1)
#define RxBufferSize1 (countof(TxBuffer1) - 1)
#define BufferSize (countof(Tx_Buffer)-1)
#define FLASH_WriteAddress 0x00000
#define FLASH_ReadAddress FLASH_WriteAddress
#define FLASH_SectorToErase FLASH_WriteAddress
/* 私有变量 ------------------------------------------------------------------*/
uint8_t Tx_Buffer[] = "dome good";
uint8_t Rx_Buffer[BufferSize];
__IO uint32_t DeviceID = 0;
__IO uint32_t FlashID = 0;
__IO TestStatus TransferStatus1 = FAILED;
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
static TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
/* 函数体 --------------------------------------------------------------------*/
/**
* 函数功能: 系统时钟配置
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); //设置调压器输出电压级别1
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 外部晶振,8MHz
RCC_OscInitStruct.HSEState = RCC_HSE_ON; //打开HSE
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; //打开PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
RCC_OscInitStruct.PLL.PLLM = 8; //8分频MHz
RCC_OscInitStruct.PLL.PLLN = 336; //336倍频
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; //2分频,得到168MHz主时钟
RCC_OscInitStruct.PLL.PLLQ = 7; //USB/SDIO/随机数产生器等的主PLL分频系数
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 系统时钟:168MHz
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB时钟: 168MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // APB1时钟:42MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // APB2时钟:84MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
HAL_RCC_EnableCSS(); // 使能CSS功能,优先使用外部晶振,内部时钟源为备用
// HAL_RCC_GetHCLKFreq()/1000 1ms中断一次
// HAL_RCC_GetHCLKFreq()/100000 10us中断一次
// HAL_RCC_GetHCLKFreq()/1000000 1us中断一次
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); // 配置并启动系统滴答定时器
/* 系统滴答定时器时钟源 */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* 系统滴答定时器中断优先级配置 */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/**
* 函数功能: 主函数.
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
int main(void)
{
/* 复位所有外设,初始化Flash接口和系统滴答定时器 */
HAL_Init();
/* 配置系统时钟 */
SystemClock_Config();
/* LED灯初始化 */
LED_GPIO_Init();
/* 初始化串口并配置串口中断优先级 */
MX_DEBUG_USART_Init();
/* 调用格式化输出函数打印输出数据 */
printf("这是一个16M byte串行flash(W25Q128)读写测试实验\n");
MX_SPIFlash_Init();
/* Get SPI Flash Device ID */
DeviceID = SPI_FLASH_ReadDeviceID();
HAL_Delay(100);
/* Get SPI Flash ID */
FlashID = SPI_FLASH_ReadID();
printf("FlashID is 0x%X, Manufacturer Device ID is 0x%X\n", FlashID, DeviceID);
/* Check the SPI Flash ID */
if (FlashID == SPI_FLASH_ID) /* #define sFLASH_ID 0XEF4018 */
{
printf("检测到华邦串行flash W25Q128 !\n");
/* 擦除SPI的扇区以写入 */
SPI_FLASH_SectorErase(FLASH_SectorToErase);
/* 将发送缓冲区的数据写到flash中 */
SPI_FLASH_BufferWrite(Tx_Buffer, FLASH_WriteAddress, BufferSize);
printf("写入的数据为:\n%s \n", Tx_Buffer);
/* 将刚刚写入的数据读出来放到接收缓冲区中 */
SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, BufferSize);
printf("读出的数据为:\n %s\n", Rx_Buffer);
/* 检查写入的数据与读出的数据是否相等 */
TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
if( PASSED == TransferStatus1 )
{
printf("16M串行flash(W25Q128)测试成功!\r");
LED1_ON;
}
else
{
printf("16M串行flash(W25Q128)测试失败!\r");
LED2_ON;
}
}
else
{
printf("获取不到 W25Q128 ID!\n");
LED3_ON;
}
/* 无限循环 */
while (1)
{
}
}
/**
* 函数功能: 比较两个缓冲区中的数据是否相等
* 输入参数: pBuffer1:要比较的缓冲区1的指针
* pBuffer2:要比较的缓冲区2的指针
* BufferLength:缓冲区长度
* 返 回 值: PASSED:相等
* FAILED:不等
* 说 明: 无
*/
static TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
while(BufferLength--)
{
if(*pBuffer1 != *pBuffer2)
{
return FAILED;
}
pBuffer1++;
pBuffer2++;
}
return PASSED;
}
2.flash整数存储
main.c
#include "stm32f4xx_hal.h"
#include "usart/bsp_debug_usart.h"
#include "spiflash/bsp_spiflash.h"
#include "led/bsp_led.h"
/* 私有类型定义 --------------------------------------------------------------*/
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
/* 私有宏定义 ----------------------------------------------------------------*/
/* 获取缓冲区的长度 */
#define FLASH_WriteAddress 0x0000
#define FLASH_ReadAddress FLASH_WriteAddress
#define FLASH_SectorToErase FLASH_WriteAddress
/* 私有变量 ------------------------------------------------------------------*/
uint8_t Tx_Buffer[6] = {1,50,100,150,200,250};
uint8_t Rx_Buffer[6] = {0};
uint32_t DeviceID = 0;
uint32_t FlashID = 0;
__IO TestStatus TransferStatus = FAILED;
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
static TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
/* 函数体 --------------------------------------------------------------------*/
/**
* 函数功能: 系统时钟配置
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); //设置调压器输出电压级别1
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 外部晶振,8MHz
RCC_OscInitStruct.HSEState = RCC_HSE_ON; //打开HSE
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; //打开PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
RCC_OscInitStruct.PLL.PLLM = 8; //8分频MHz
RCC_OscInitStruct.PLL.PLLN = 336; //336倍频
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; //2分频,得到168MHz主时钟
RCC_OscInitStruct.PLL.PLLQ = 7; //USB/SDIO/随机数产生器等的主PLL分频系数
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 系统时钟:168MHz
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB时钟: 168MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // APB1时钟:42MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // APB2时钟:84MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
HAL_RCC_EnableCSS(); // 使能CSS功能,优先使用外部晶振,内部时钟源为备用
// HAL_RCC_GetHCLKFreq()/1000 1ms中断一次
// HAL_RCC_GetHCLKFreq()/100000 10us中断一次
// HAL_RCC_GetHCLKFreq()/1000000 1us中断一次
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); // 配置并启动系统滴答定时器
/* 系统滴答定时器时钟源 */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* 系统滴答定时器中断优先级配置 */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/**
* 函数功能: 主函数.
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
int main(void)
{
uint8_t i;
/* 复位所有外设,初始化Flash接口和系统滴答定时器 */
HAL_Init();
/* 配置系统时钟 */
SystemClock_Config();
/* LED灯初始化 */
LED_GPIO_Init();
/* 初始化串口并配置串口中断优先级 */
MX_DEBUG_USART_Init();
/* 调用格式化输出函数打印输出数据 */
printf("这是一个16M byte串行flash(W25Q128)读写测试实验\n");
MX_SPIFlash_Init();
/* Get SPI Flash Device ID */
DeviceID = SPI_FLASH_ReadDeviceID();
HAL_Delay(100);
/* Get SPI Flash ID */
FlashID = SPI_FLASH_ReadID();
printf("FlashID is 0x%X, Manufacturer Device ID is 0x%X\n", FlashID, DeviceID);
/* Check the SPI Flash ID */
if (FlashID == SPI_FLASH_ID) /* #define sFLASH_ID 0XEF4018 */
{
printf("检测到华邦串行flash W25Q128 !\n");
/* 擦除SPI的扇区以写入 */
SPI_FLASH_SectorErase(FLASH_SectorToErase);
/* 将发送缓冲区的数据写到flash中 */
SPI_FLASH_BufferWrite(Tx_Buffer,FLASH_WriteAddress, sizeof(Tx_Buffer));
printf("写入的数据为:\n");
for(i=0; i<sizeof(Tx_Buffer);i++ )
printf("%d ", Tx_Buffer[i]);
printf("\n");
/* 将刚刚写入的数据读出来放到接收缓冲区中 */
SPI_FLASH_BufferRead(Rx_Buffer, FLASH_ReadAddress, sizeof(Rx_Buffer));
printf("读出的数据为:\n");
for(i=0; i<sizeof(Rx_Buffer);i++ )
printf("%d ", Rx_Buffer[i]);
printf("\n");
/* 检查写入的数据与读出的数据是否相等 */
TransferStatus = Buffercmp(Tx_Buffer, Rx_Buffer, sizeof(Tx_Buffer));
if( PASSED == TransferStatus )
{
printf("16M串行flash(W25Q128)数据读写测试成功!\n");
LED1_ON;
}
else
{
printf("16M串行flash(W25Q128)数据读写测试失败!\n");
LED2_ON;
}
}
else
{
printf("获取不到 W25Q128 ID!\n");
LED3_ON;
}
/* 无限循环 */
while (1)
{
}
}
/**
* 函数功能: 比较两个缓冲区中的数据是否相等
* 输入参数: pBuffer1:要比较的缓冲区1的指针
* pBuffer2:要比较的缓冲区2的指针
* BufferLength:缓冲区长度
* 返 回 值: PASSED:相等
* FAILED:不等
* 说 明: 无
*/
static TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
while(BufferLength--)
{
if(*pBuffer1 != *pBuffer2)
{
return FAILED;
}
pBuffer1++;
pBuffer2++;
}
return PASSED;
}
3.flash小数存储
spi.h
#ifndef __BSP_SPIFLASH_H__
#define __BSP_SPIFLASH_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/* 类型定义 ------------------------------------------------------------------*/
/* 宏定义 --------------------------------------------------------------------*/
//#define SPI_FLASH_ID 0x3015 //W25X16 2MB
//#define SPI_FLASH_ID 0x4015 //W25Q16 4MB
//#define SPI_FLASH_ID 0X4017 //W25Q64 8MB
#define SPI_FLASH_ID 0X4018 //W25Q128 16MB YS-F4Pro开发默认使用
#define FLASH_SPIx SPI2
#define FLASH_SPIx_RCC_CLK_ENABLE() __HAL_RCC_SPI2_CLK_ENABLE()
#define FLASH_SPIx_RCC_CLK_DISABLE() __HAL_RCC_SPI2_CLK_DISABLE()
#define FLASH_SPI_GPIO_ClK_ENABLE() {__HAL_RCC_GPIOI_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();}
#define FLASH_SPI_GPIO_PORT GPIOI
#define FLASH_SPI_SCK_PIN GPIO_PIN_1
#define FLASH_SPI_MOSI_PIN GPIO_PIN_3
#define FLASH_SPI_CS_PIN GPIO_PIN_0
#define FLASH_SPI_CS_ENABLE() HAL_GPIO_WritePin(FLASH_SPI_GPIO_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_RESET)
#define FLASH_SPI_CS_DISABLE() HAL_GPIO_WritePin(FLASH_SPI_GPIO_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_SET)
#define FLASH_SPI_MISO_PORT GPIOC
#define FLASH_SPI_MISO_PIN GPIO_PIN_2
/* 扩展变量 ------------------------------------------------------------------*/
extern SPI_HandleTypeDef hspiflash;
/* 函数声明 ------------------------------------------------------------------*/
void MX_SPIFlash_Init(void);
void SPI_FLASH_SectorErase(uint32_t SectorAddr);
void SPI_FLASH_BulkErase(void);
void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
uint32_t SPI_FLASH_ReadID(void);
uint32_t SPI_FLASH_ReadDeviceID(void);
void SPI_FLASH_StartReadSequence(uint32_t ReadAddr);
void SPI_Flash_PowerDown(void);
void SPI_Flash_WAKEUP(void);
uint8_t SPI_FLASH_ReadByte(void);
uint8_t SPI_FLASH_SendByte(uint8_t byte);
void SPI_FLASH_WriteEnable(void);
void SPI_FLASH_WaitForWriteEnd(void);
#endif /* __BSP_SPIFLASH_H__ */
spi.c
#include "spiflash/bsp_spiflash.h"
#include "usart/bsp_debug_usart.h"
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
#define SPI_FLASH_PageSize 256
#define SPI_FLASH_PerWritePageSize 256
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
#define WIP_Flag 0x01 /* Write In Progress (WIP) flag */
#define Dummy_Byte 0xFF
/* 私有变量 ------------------------------------------------------------------*/
SPI_HandleTypeDef hspiflash;
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
/**
* 函数功能: 串行FLASH初始化
* 输入参数: huart:串口句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void MX_SPIFlash_Init(void)
{
hspiflash.Instance = FLASH_SPIx;
hspiflash.Init.Mode = SPI_MODE_MASTER;//主模式
hspiflash.Init.Direction = SPI_DIRECTION_2LINES;//双向
hspiflash.Init.DataSize = SPI_DATASIZE_8BIT;//8位数据帧长度
hspiflash.Init.CLKPolarity = SPI_POLARITY_LOW;//时钟极性低
hspiflash.Init.CLKPhase = SPI_PHASE_1EDGE;//奇数位
hspiflash.Init.NSS = SPI_NSS_SOFT;//软件
hspiflash.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;//预分频系数为4
hspiflash.Init.FirstBit = SPI_FIRSTBIT_MSB;//MSB先行
hspiflash.Init.TIMode = SPI_TIMODE_DISABLE;
hspiflash.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//CRC校验失能
hspiflash.Init.CRCPolynomial = 10;
HAL_SPI_Init(&hspiflash);
}
/**
* 函数功能: SPI外设系统级初始化
* 输入参数: hspi:SPI句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hspi->Instance==FLASH_SPIx)
{
/* SPI外设时钟使能 */
FLASH_SPIx_RCC_CLK_ENABLE();
/* GPIO外设时钟使能 */
FLASH_SPI_GPIO_ClK_ENABLE();
/**SPI2 GPIO Configuration
PI0 ------> SPI2_NSS
PI1 ------> SPI2_SCK
PC2 ------> SPI2_MISO
PI3 ------> SPI2_MOSI
*/
GPIO_InitStruct.Pin = FLASH_SPI_SCK_PIN|FLASH_SPI_MOSI_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(FLASH_SPI_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = FLASH_SPI_MISO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStruct);
HAL_GPIO_WritePin(FLASH_SPI_GPIO_PORT, FLASH_SPI_CS_PIN, GPIO_PIN_SET);
GPIO_InitStruct.Pin = FLASH_SPI_CS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(FLASH_SPI_GPIO_PORT, &GPIO_InitStruct);
}
}
/**
* 函数功能: SPI外设系统级反初始化
* 输入参数: hspi:SPI句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
if(hspi->Instance==FLASH_SPIx)
{
/* SPI外设时钟禁用 */
FLASH_SPIx_RCC_CLK_DISABLE();
/**SPI2 GPIO Configuration
PI0 ------> SPI2_NSS
PI1 ------> SPI2_SCK
PC2 ------> SPI2_MISO
PI3 ------> SPI2_MOSI
*/
HAL_GPIO_DeInit(FLASH_SPI_GPIO_PORT, FLASH_SPI_SCK_PIN|FLASH_SPI_MOSI_PIN|FLASH_SPI_CS_PIN);
HAL_GPIO_DeInit(FLASH_SPI_MISO_PORT, FLASH_SPI_MISO_PIN);
}
}
/**
* 函数功能: 擦除扇区
* 输入参数: SectorAddr:待擦除扇区地址,要求为4096倍数
* 返 回 值: 无
* 说 明:串行Flash最小擦除块大小为4KB(4096字节),即一个扇区大小,要求输入参数
* 为4096倍数。在往串行Flash芯片写入数据之前要求先擦除空间。
*/
void SPI_FLASH_SectorErase(uint32_t SectorAddr)
{
/* 发送FLASH写使能命令 */
SPI_FLASH_WriteEnable();
SPI_FLASH_WaitForWriteEnd();
/* 擦除扇区 */
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送扇区擦除指令*/
SPI_FLASH_SendByte(W25X_SectorErase);
/*发送擦除扇区地址的高位*/
SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
/* 发送擦除扇区地址的中位 */
SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);
/* 发送擦除扇区地址的低位 */
SPI_FLASH_SendByte(SectorAddr & 0xFF);
/* 禁用串行FLASH: CS 高电平 */
FLASH_SPI_CS_DISABLE();
/* 等待擦除完毕*/
SPI_FLASH_WaitForWriteEnd();
}
/**
* 函数功能: 擦除整片
* 输入参数: 无
* 返 回 值: 无
* 说 明:擦除串行Flash整片空间
*/
void SPI_FLASH_BulkErase(void)
{
/* 发送FLASH写使能命令 */
SPI_FLASH_WriteEnable();
/* 整片擦除 Erase */
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送整片擦除指令*/
SPI_FLASH_SendByte(W25X_ChipErase);
/* 禁用串行FLASH: CS高电平 */
FLASH_SPI_CS_DISABLE();
/* 等待擦除完毕*/
SPI_FLASH_WaitForWriteEnd();
}
/**
* 函数功能: 往串行FLASH按页写入数据,调用本函数写入数据前需要先擦除扇区
* 输入参数: pBuffer:待写入数据的指针
* WriteAddr:写入地址
* NumByteToWrite:写入数据长度,必须小于等于SPI_FLASH_PerWritePageSize
* 返 回 值: 无
* 说 明:串行Flash每页大小为256个字节
*/
void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
/* 发送FLASH写使能命令 */
SPI_FLASH_WriteEnable();
/* 寻找串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 写送写指令*/
SPI_FLASH_SendByte(W25X_PageProgram);
/*发送写地址的高位*/
SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
/*发送写地址的中位*/
SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);
/*发送写地址的低位*/
SPI_FLASH_SendByte(WriteAddr & 0xFF);
if(NumByteToWrite > SPI_FLASH_PerWritePageSize)
{
NumByteToWrite = SPI_FLASH_PerWritePageSize;
//printf("Err: SPI_FLASH_PageWrite too large!\n");
}
/* 写入数据*/
while (NumByteToWrite--)
{
/* 发送当前要写入的字节数据 */
SPI_FLASH_SendByte(*pBuffer);
/* 指向下一字节数据 */
pBuffer++;
}
/* 禁用串行FLASH: CS 高电平 */
FLASH_SPI_CS_DISABLE();
/* 等待写入完毕*/
SPI_FLASH_WaitForWriteEnd();
}
/**
* 函数功能: 往串行FLASH写入数据,调用本函数写入数据前需要先擦除扇区
* 输入参数: pBuffer:待写入数据的指针
* WriteAddr:写入地址
* NumByteToWrite:写入数据长度
* 返 回 值: 无
* 说 明:该函数可以设置任意写入数据长度
*/
void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;
Addr = WriteAddr % SPI_FLASH_PageSize;
count = SPI_FLASH_PageSize - Addr;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
if (Addr == 0) /* 若地址与 SPI_FLASH_PageSize 对齐 */
{
if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
else /* 若地址与 SPI_FLASH_PageSize 不对齐 */
{
if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */
{
if (NumOfSingle > count) /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */
{
temp = NumOfSingle - count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
}
else
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
if (NumOfSingle != 0)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
}
}
/**
* 函数功能: 从串行Flash读取数据
* 输入参数: pBuffer:存放读取到数据的指针
* ReadAddr:读取数据目标地址
* NumByteToRead:读取数据长度
* 返 回 值: 无
* 说 明:该函数可以设置任意读取数据长度
*/
void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送 读 指令 */
SPI_FLASH_SendByte(W25X_ReadData);
/* 发送 读 地址高位 */
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/* 发送 读 地址中位 */
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/* 发送 读 地址低位 */
SPI_FLASH_SendByte(ReadAddr & 0xFF);
while (NumByteToRead--) /* 读取数据 */
{
/* 读取一个字节*/
*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);
/* 指向下一个字节缓冲区 */
pBuffer++;
}
/* 禁用串行FLASH: CS 高电平 */
FLASH_SPI_CS_DISABLE();
}
/**
* 函数功能: 读取串行Flash型号的ID
* 输入参数: 无
* 返 回 值: uint32_t:串行Flash的型号ID
* 说 明: FLASH_ID IC型号 存储空间大小
0x3015 W25X16 2M byte
0x4015 W25Q16 4M byte
0X4017 W25Q64 8M byte
0X4018 W25Q128 16M byte (YS-F1Pro开发板默认配置)
*/
uint32_t SPI_FLASH_ReadID(void)
{
uint32_t Temp = 0, Temp1 = 0, Temp2 = 0;
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送命令:读取芯片型号ID */
SPI_FLASH_SendByte(W25X_JedecDeviceID);
/* 从串行Flash读取一个字节数据 */
Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
/* 从串行Flash读取一个字节数据 */
Temp1 = SPI_FLASH_SendByte(Dummy_Byte);
/* 从串行Flash读取一个字节数据 */
Temp2 = SPI_FLASH_SendByte(Dummy_Byte);
/* 禁用串行Flash:CS高电平 */
FLASH_SPI_CS_DISABLE();
Temp = Temp1 << 8 | Temp2;
return Temp;
}
/**
* 函数功能: 读取串行Flash设备ID
* 输入参数: 无
* 返 回 值: uint32_t:串行Flash的设备ID
* 说 明:
*/
uint32_t SPI_FLASH_ReadDeviceID(void)
{
uint32_t Temp = 0;
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送命令:读取芯片设备ID * */
SPI_FLASH_SendByte(W25X_DeviceID);
SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_SendByte(Dummy_Byte);
SPI_FLASH_SendByte(Dummy_Byte);
/* 从串行Flash读取一个字节数据 */
Temp = SPI_FLASH_SendByte(Dummy_Byte);
/* 禁用串行Flash:CS高电平 */
FLASH_SPI_CS_DISABLE();
return Temp;
}
/**
* 函数功能: 启动连续读取数据串
* 输入参数: ReadAddr:读取地址
* 返 回 值: 无
* 说 明:Initiates a read data byte (READ) sequence from the Flash.
* This is done by driving the /CS line low to select the device,
* then the READ instruction is transmitted followed by 3 bytes
* address. This function exit and keep the /CS line low, so the
* Flash still being selected. With this technique the whole
* content of the Flash is read with a single READ instruction.
*/
void SPI_FLASH_StartReadSequence(uint32_t ReadAddr)
{
/* Select the FLASH: Chip Select low */
FLASH_SPI_CS_ENABLE();
/* Send "Read from Memory " instruction */
SPI_FLASH_SendByte(W25X_ReadData);
/* Send the 24-bit address of the address to read from -----------------------*/
/* Send ReadAddr high nibble address byte */
SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
/* Send ReadAddr medium nibble address byte */
SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);
/* Send ReadAddr low nibble address byte */
SPI_FLASH_SendByte(ReadAddr & 0xFF);
}
/**
* 函数功能: 从串行Flash读取一个字节数据
* 输入参数: 无
* 返 回 值: uint8_t:读取到的数据
* 说 明:This function must be used only if the Start_Read_Sequence
* function has been previously called.
*/
uint8_t SPI_FLASH_ReadByte(void)
{
uint8_t d_read,d_send=Dummy_Byte;
if(HAL_SPI_TransmitReceive(&hspiflash,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)
d_read=Dummy_Byte;
return d_read;
}
/**
* 函数功能: 往串行Flash读取写入一个字节数据并接收一个字节数据
* 输入参数: byte:待发送数据
* 返 回 值: uint8_t:接收到的数据
* 说 明:无
*/
uint8_t SPI_FLASH_SendByte(uint8_t byte)
{
uint8_t d_read,d_send=byte;
if(HAL_SPI_TransmitReceive(&hspiflash,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)
d_read=Dummy_Byte;
return d_read;
}
/**
* 函数功能: 使能串行Flash写操作
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void SPI_FLASH_WriteEnable(void)
{
/* 选择串行FLASH: CS低电平 */
FLASH_SPI_CS_ENABLE();
/* 发送命令:写使能 */
SPI_FLASH_SendByte(W25X_WriteEnable);
/* 禁用串行Flash:CS高电平 */
FLASH_SPI_CS_DISABLE();
}
/**
* 函数功能: 等待数据写入完成
* 输入参数: 无
* 返 回 值: 无
* 说 明:Polls the status of the Write In Progress (WIP) flag in the
* FLASH's status register and loop until write opertaion
* has completed.
*/
void SPI_FLASH_WaitForWriteEnd(void)
{
uint8_t FLASH_Status = 0;
/* Select the FLASH: Chip Select low */
FLASH_SPI_CS_ENABLE();
/* Send "Read Status Register" instruction */
SPI_FLASH_SendByte(W25X_ReadStatusReg);
/* Loop as long as the memory is busy with a write cycle */
do
{
/* Send a dummy byte to generate the clock needed by the FLASH
and put the value of the status register in FLASH_Status variable */
FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);
}
while ((FLASH_Status & WIP_Flag) == SET); /* Write in progress */
/* Deselect the FLASH: Chip Select high */
FLASH_SPI_CS_DISABLE();
}
/**
* 函数功能: 进入掉电模式
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void SPI_Flash_PowerDown(void)
{
/* Select the FLASH: Chip Select low */
FLASH_SPI_CS_ENABLE();
/* Send "Power Down" instruction */
SPI_FLASH_SendByte(W25X_PowerDown);
/* Deselect the FLASH: Chip Select high */
FLASH_SPI_CS_DISABLE();
}
/**
* 函数功能: 唤醒串行Flash
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
void SPI_Flash_WAKEUP(void)
{
/* Select the FLASH: Chip Select low */
FLASH_SPI_CS_ENABLE();
/* Send "Power Down" instruction */
SPI_FLASH_SendByte(W25X_ReleasePowerDown);
/* Deselect the FLASH: Chip Select high */
FLASH_SPI_CS_DISABLE();
}
main.c
#include "stm32f4xx_hal.h"
#include "usart/bsp_debug_usart.h"
#include "spiflash/bsp_spiflash.h"
/* 私有类型定义 --------------------------------------------------------------*/
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
/* 发送缓冲区初始化 */
long double Tx_Buffer[7] = {0};
long double Rx_Buffer[7] = {0};
uint8_t cal_flag = 0;
uint8_t cal_f = 0;
uint32_t DeviceID = 0;
uint32_t FlashID = 0;
__IO TestStatus TransferStatus1 = FAILED;
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
/**
* 函数功能: 系统时钟配置
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); //设置调压器输出电压级别1
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 外部晶振,8MHz
RCC_OscInitStruct.HSEState = RCC_HSE_ON; //打开HSE
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; //打开PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; //PLL时钟源选择HSE
RCC_OscInitStruct.PLL.PLLM = 8; //8分频MHz
RCC_OscInitStruct.PLL.PLLN = 336; //336倍频
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; //2分频,得到168MHz主时钟
RCC_OscInitStruct.PLL.PLLQ = 7; //USB/SDIO/随机数产生器等的主PLL分频系数
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 系统时钟:168MHz
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB时钟: 168MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // APB1时钟:42MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // APB2时钟:84MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
HAL_RCC_EnableCSS(); // 使能CSS功能,优先使用外部晶振,内部时钟源为备用
// HAL_RCC_GetHCLKFreq()/1000 1ms中断一次
// HAL_RCC_GetHCLKFreq()/100000 10us中断一次
// HAL_RCC_GetHCLKFreq()/1000000 1us中断一次
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); // 配置并启动系统滴答定时器
/* 系统滴答定时器时钟源 */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* 系统滴答定时器中断优先级配置 */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/**
* 函数功能: 主函数.
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
int main(void)
{
uint8_t i;
/* 复位所有外设,初始化Flash接口和系统滴答定时器 */
HAL_Init();
/* 配置系统时钟 */
SystemClock_Config();
/* 初始化串口并配置串口中断优先级 */
MX_DEBUG_USART_Init();
/* 调用格式化输出函数打印输出数据 */
printf("这是一个16M byte串行flash(W25Q128)读写测试实验\n");
MX_SPIFlash_Init();
/* Get SPI Flash Device ID */
DeviceID = SPI_FLASH_ReadDeviceID();
HAL_Delay(100);
/* Get SPI Flash ID */
FlashID = SPI_FLASH_ReadID();
printf("FlashID is 0x%X, Manufacturer Device ID is 0x%X\n", FlashID, DeviceID);
/* Check the SPI Flash ID */
if (FlashID == SPI_FLASH_ID) /* #define sFLASH_ID 0XEF4018 */
{
printf("检测到华邦串行flash W25Q128 !\n");
SPI_FLASH_BufferRead(&cal_flag, 0, 1);
if( cal_flag == 0x55)
{
SPI_FLASH_BufferRead((void*)Rx_Buffer, 1, sizeof(Rx_Buffer));
for(i=0;i<7;i++ )
printf("rx = %LF \n",Rx_Buffer[i]);
}
else
{
cal_flag = 0x55;
SPI_FLASH_SectorErase(0);
SPI_FLASH_BufferWrite(&cal_flag, 0, 1);
for( i=0; i<7; i++ )
Tx_Buffer[i] = i +0.1;
SPI_FLASH_BufferWrite((void*)Tx_Buffer, 1, sizeof(Tx_Buffer));
for(i=0; i<7;i++ )
printf("tx = %LF \n",Tx_Buffer[i]);
}
}
else
{
printf("获取不到 W25Q128 ID!\n");
}
/* 无限循环 */
while (1)
{
}
}
4.SPI读写磁编码器
spi.h
#ifndef __BSP_SPI_H__
#define __BSP_SPI_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/* 类型定义 ------------------------------------------------------------------*/
/* 宏定义 --------------------------------------------------------------------*/
#define SPIx SPI1
#define SPIx_RCC_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE()
#define SPIx_RCC_CLK_DISABLE() __HAL_RCC_SPI1_CLK_DISABLE()
#define SPIx_SCK_ClK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define SPIx_SCK_PORT GPIOA
#define SPIx_SCK_PIN GPIO_PIN_5
#define SPIx_MOSI_ClK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MOSI_PORT GPIOB
#define SPIx_MOSI_PIN GPIO_PIN_5
#define SPIx_MISO_ClK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define SPIx_MISO_PORT GPIOB
#define SPIx_MISO_PIN GPIO_PIN_4
#define SPIx_CS_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define SPIx_CS_PORT GPIOC
#define SPIx_CS_PIN GPIO_PIN_13
#define SPIx_CS_ENABLE() HAL_GPIO_WritePin(SPIx_CS_PORT, SPIx_CS_PIN, GPIO_PIN_RESET)
#define SPIx_CS_DISABLE() HAL_GPIO_WritePin(SPIx_CS_PORT, SPIx_CS_PIN, GPIO_PIN_SET)
#define SPI_DATA_SIZE SPI_DATASIZE_16BIT
/* 扩展变量 ------------------------------------------------------------------*/
extern SPI_HandleTypeDef hspix;
/* 函数声明 ------------------------------------------------------------------*/
void SPIx_Init(void);
#if (SPI_DATA_SIZE)==(SPI_DATASIZE_16BIT)
uint16_t SPIx_Write_Buf(uint16_t reg, uint16_t *pBuf, uint16_t uint8_ts);//写数据区
uint16_t SPIx_Read_Buf(uint16_t reg, uint16_t *pBuf, uint16_t uint8_ts); //读数据区
uint16_t SPIx_Read_Reg(uint16_t reg); //读寄存器
uint16_t SPIx_Write_Reg(uint16_t reg, uint16_t value); //写寄存器
uint16_t SPIx_ReadWriteByte(SPI_HandleTypeDef* hspi,uint16_t Byte);
#else
uint8_t SPIx_ReadWriteByte(SPI_HandleTypeDef* hspi,uint8_t Byte);
uint8_t SPIx_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t uint8_ts);//写数据区
uint8_t SPIx_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t uint8_ts); //读数据区
uint8_t SPIx_Read_Reg(uint8_t reg); //读寄存器
uint8_t SPIx_Write_Reg(uint8_t reg, uint8_t value); //写寄存器
#endif
#endif /* __BSP_SPI_H__ */
spi.c
#include "SPI/bsp_SPI.h"
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
/* 私有变量 ------------------------------------------------------------------*/
SPI_HandleTypeDef hspix;
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
/**
* 函数功能: 串行FLASH初始化
* 输入参数: huart:串口句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void SPIx_Init(void)
{
SPIx_RCC_CLK_ENABLE();
hspix.Instance = SPIx;
hspix.Init.Mode = SPI_MODE_MASTER;
hspix.Init.Direction = SPI_DIRECTION_2LINES;
hspix.Init.DataSize = SPI_DATA_SIZE;
hspix.Init.CLKPolarity = SPI_POLARITY_LOW; // 时钟空闲电平极性
hspix.Init.CLKPhase = SPI_PHASE_2EDGE; // 时钟相位, 时钟第一个边沿采样
hspix.Init.NSS = SPI_NSS_SOFT;
hspix.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspix.Init.FirstBit = SPI_FIRSTBIT_MSB; // MSB
hspix.Init.TIMode = SPI_TIMODE_DISABLE;
hspix.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspix.Init.CRCPolynomial = 7;
HAL_SPI_Init(&hspix);
__HAL_SPI_ENABLE(&hspix);
}
/**
* 函数功能: SPI外设系统级初始化
* 输入参数: hspi:SPI句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hspi == &hspix)
{
SPIx_MOSI_ClK_ENABLE();
SPIx_MISO_ClK_ENABLE();
SPIx_SCK_ClK_ENABLE();
SPIx_CS_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PB4 ------> SPI1_MISO
PB5 ------> SPI1_MOSI
*/
HAL_GPIO_WritePin( SPIx_CS_PORT, SPIx_CS_PIN, GPIO_PIN_SET);
GPIO_InitStruct.Pin = SPIx_CS_PIN;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_RTC_50Hz;
HAL_GPIO_Init( SPIx_CS_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = SPIx_SCK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init( SPIx_SCK_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = SPIx_MISO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init( SPIx_MISO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = SPIx_MOSI_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init( SPIx_MOSI_PORT, &GPIO_InitStruct);
}
}
#if (SPI_DATA_SIZE)==(SPI_DATASIZE_16BIT)
/**
* 函数功能: 往SPI设备读取写入一个字节数据并接收一个字节数据
* 输入参数: byte:待发送数据
* 返 回 值: uint8_t:接收到的数据
* 说 明:无
*/
uint16_t SPIx_ReadWriteByte(SPI_HandleTypeDef* hspi,uint16_t Byte)
{
uint16_t d_read = 0xFFFF;
uint16_t d_send = Byte;
SPIx_CS_ENABLE(); //使能SPIx传输
if(HAL_SPI_TransmitReceive(hspi,(uint8_t*)&d_send,(uint8_t*)&d_read,1,0x0F)!=HAL_OK)
{
d_read = 0xFFFF;
}
SPIx_CS_DISABLE(); //禁止SPIx传输
return d_read;
}
/**
* 函数功能: SPI写寄存器
* 输入参数: 无
* 返 回 值: 无
* 说 明:reg:指定寄存器地址,value:写入寄存器的数值
*
*/
uint16_t SPIx_Write_Reg(uint16_t reg,uint16_t value)
{
uint16_t status;
status = SPIx_ReadWriteByte(&hspix,reg);//发送寄存器号
SPIx_ReadWriteByte(&hspix,value); //写入寄存器的值
return(status); //返回状态值
}
/**
* 函数功能: 读取SPI寄存器值
* 输入参数: 无
* 返 回 值: 无
* 说 明:reg:要读的寄存器
*
*/
uint16_t SPIx_Read_Reg(uint16_t reg)
{
uint16_t reg_val;
SPIx_ReadWriteByte(&hspix,reg); //发送寄存器号
reg_val=SPIx_ReadWriteByte(&hspix,0XFFFF);//读取寄存器内容
return(reg_val); //返回状态值
}
/**
* 函数功能: 在指定位置读出指定长度的数据
* 输入参数: 无
* 返 回 值: 此次读到的状态寄存器值
* 说 明:无
*
*/
uint16_t SPIx_Read_Buf(uint16_t reg,uint16_t *pBuf,uint16_t len)
{
uint16_t status,uint8_t_ctr;
status=SPIx_ReadWriteByte(&hspix,reg);//发送寄存器值(位置),并读取状态值
for(uint8_t_ctr=0;uint8_t_ctr<len;uint8_t_ctr++)
{
pBuf[uint8_t_ctr]=SPIx_ReadWriteByte(&hspix,0XFFFF);//读出数据
}
return status; //返回读到的状态值
}
/**
* 函数功能: 在指定位置写指定长度的数据
* 输入参数: 无
* 返 回 值: 无
* 说 明:reg:寄存器(位置) *pBuf:数据指针 len:数据长度
*
*/
uint16_t SPIx_Write_Buf(uint16_t reg, uint16_t *pBuf, uint16_t len)
{
uint16_t status,uint8_t_ctr;
status = SPIx_ReadWriteByte(&hspix,reg);//发送寄存器值(位置),并读取状态值
for(uint8_t_ctr=0; uint8_t_ctr<len; uint8_t_ctr++)
{
SPIx_ReadWriteByte(&hspix,*pBuf++); //写入数据
}
return status; //返回读到的状态值
}
#else
/**
* 函数功能: 往SPI设备读取写入一个字节数据并接收一个字节数据
* 输入参数: byte:待发送数据
* 返 回 值: uint8_t:接收到的数据
* 说 明:无
*/
uint8_t SPIx_ReadWriteByte(SPI_HandleTypeDef* hspi,uint8_t Byte)
{
uint8_t d_read = 0xFF;
uint8_t d_send = Byte;
if(HAL_SPI_TransmitReceive(hspi,(uint8_t*)&d_send,(uint8_t*)&d_read,1,0xFF)!=HAL_OK)
{
d_read = 0xFF;
}
return d_read;
}
/**
* 函数功能: SPI写寄存器
*