这一张我们主要讲解一下STM32CUBEMX新版本 片外FLASH+FATFS文件系统。
这里我们要想配置SPI和文件系统 并验证需要的准备工作如下:
这里配置的是SPI2,还需要软件控制片选增加一个PB12作为输出的片选脚,这里SPI2就配置好了。
在MiddleWare下FATFS勾选User-define,在底下参数栏里面设置简体中文以及块大小,我们选取的是W25Q128,块的大小是4096。如果是SD卡就不需要更改大小为512。这里文件系统就配置好了。
void MX_SPI2_Init(void)
{
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi2.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
Error_Handler();
}
SPI2->CR1 |= SPI_CR1_SPE;
}
SPI2初始化代码添加SPI使能代码。
FLASH.C
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17
#define M25P64_FLASH_ID 0x202017//C22017
#define M25P40_FLASH_ID 0x202013
/* USER CODE BEGIN Includes */
#define sFLASH_CMD_WRITE 0x02 /*!< Write to Memory instruction */
#define sFLASH_CMD_WRSR 0x01 /*!< Write Status Register instruction */
#define sFLASH_CMD_WREN 0x06 /*!< Write enable instruction */
#define sFLASH_CMD_READ 0x03 /*!< Read from Memory instruction */
#define sFLASH_CMD_RDSR 0x05 /*!< Read Status Register instruction */
#define sFLASH_CMD_RDID 0x9F /*!< Read identification */
#define sFLASH_CMD_SE 0x20 /*!< Sector Erase instruction (4k)*/
#define sFLASH_CMD_BE 0xD8 /*!< Block Erase instruction (64k)*/
#define sFLASH_CMD_CE 0xC7 /*!< Chip Erase instruction (Chip Erase)*/
#define sFLASH_WIP_FLAG 0x01 /*!< Write In Progress (WIP) flag */
#define sFLASH_CMD_RDID 0x9F /*!< Read identification */
#define sFLASH_CMD_DeviceID 0xAB
#define sFLASH_CMD_ManufactDeviceID 0x90
#define sFLASH_CMD_JedecDeviceID 0x9F
#define sFLASH_DUMMY_BYTE 0xFF
uint8_t sFlashBuff[4096];
//片选CS拉低
void sFLASH_CS_LOW(void)
{
HAL_GPIO_WritePin(SPI2_CS_GPIO_Port,SPI2_CS_Pin,GPIO_PIN_RESET);
}
//片选CS拉高
void sFLASH_CS_HIGH(void)
{
HAL_GPIO_WritePin(SPI2_CS_GPIO_Port,SPI2_CS_Pin,GPIO_PIN_SET);
}
//FLASH写使能
void sFLASH_WriteEnable(void)
{
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send "Write Enable" instruction */
sFLASH_SendByte(sFLASH_CMD_WREN);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
}
//FLASH 发送一个字节
uint8_t sFLASH_SendByte(uint8_t byte)
{
unsigned char dr;
/*!< Loop while DR register in not emplty */
//while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
while((SPI2->SR & SPI_SR_TXE) == 0);
/*!< Send byte through the SPI1 peripheral */
//SPI_I2S_SendData(SPI1, byte);
SPI2->DR = byte;
/*!< Wait to receive a byte */
//while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
while((SPI2->SR & SPI_SR_RXNE) == 0);
/*!< Return the byte read from the SPI bus */
//return SPI_I2S_ReceiveData(SPI1);
dr = SPI2->DR;
return dr;
}
//FLASH读取一个字节
uint8_t sFLASH_ReadByte(void)
{
return (sFLASH_SendByte(sFLASH_DUMMY_BYTE));
}
//FLASH等待写完成
void sFLASH_WaitForWriteEnd(void)
{
uint8_t flashstatus = 0;
HAL_Delay(1);
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
HAL_Delay(1);
/*!< Send "Read Status Register" instruction */
sFLASH_SendByte(sFLASH_CMD_RDSR);
/*!< 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 */
flashstatus = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
}
while ((flashstatus & sFLASH_WIP_FLAG) == SET); /* Write in progress */
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
}
//FLASH擦除一个扇区
void sFLASH_EraseSector(uint32_t SectorAddr)
{
/*!< Send write enable instruction */
sFLASH_WriteEnable();
/*!< Sector Erase */
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send Sector Erase instruction */
sFLASH_SendByte(sFLASH_CMD_SE);
/*!< Send SectorAddr high nibble address byte */
sFLASH_SendByte((SectorAddr & 0xFF0000) >> 16);
/*!< Send SectorAddr medium nibble address byte */
sFLASH_SendByte((SectorAddr & 0xFF00) >> 8);
/*!< Send SectorAddr low nibble address byte */
sFLASH_SendByte(SectorAddr & 0xFF);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
/*!< Wait the end of Flash writing */
sFLASH_WaitForWriteEnd();
}
//FLASH擦除整个片
void sFLASH_EraseChip(void)
{
/*!< Send write enable instruction */
sFLASH_WriteEnable();
/*!< Bulk Erase */
/*!< Select the FLASH: Chip Select low */
sFLASH_CS_LOW();
/*!< Send Bulk Erase instruction */
sFLASH_SendByte(sFLASH_CMD_CE);
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
/*!< Wait the end of Flash writing */
sFLASH_WaitForWriteEnd();
}
//FLASH写一个页
void sFLASH_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
sFLASH_WriteEnable();
sFLASH_CS_LOW();
sFLASH_SendByte(sFLASH_CMD_WRITE);
sFLASH_SendByte((WriteAddr & 0xFF0000) >> 16);
sFLASH_SendByte((WriteAddr & 0xFF00) >> 8);
sFLASH_SendByte(WriteAddr & 0xFF);
while (NumByteToWrite--)
{
sFLASH_SendByte(*pBuffer);
pBuffer++;
}
sFLASH_CS_HIGH();
sFLASH_WaitForWriteEnd();
}
//FLASH读取0-65536个
void sFLASH_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
sFLASH_CS_LOW();
sFLASH_SendByte(sFLASH_CMD_READ);
sFLASH_SendByte((ReadAddr & 0xFF0000) >> 16);
sFLASH_SendByte((ReadAddr& 0xFF00) >> 8);
sFLASH_SendByte(ReadAddr & 0xFF);
while (NumByteToRead--) /*!< while there is data to be read */
{
*pBuffer = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
pBuffer++;
}
sFLASH_CS_HIGH();
}
//读取FLASH ID
uint32_t sFLASH_ReadID(void)
{
uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
sFLASH_CS_LOW();
HAL_Delay(1);
sFLASH_SendByte(sFLASH_CMD_RDID);
Temp0 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
Temp1 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
Temp2 = sFLASH_SendByte(sFLASH_DUMMY_BYTE);
sFLASH_CS_HIGH();
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
return Temp;
}
//无检验写SPI FLASH
void sFLASH_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint16_t pageremain;
pageremain=256-WriteAddr%256; //单页剩余的字节数
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
while(1)
{
sFLASH_WritePage(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)
{
break;//写入结束了
}
else //NumByteToWrite>pageremain
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain; //减去已经写入了的字节数
if(NumByteToWrite>256)
{
pageremain=256; //一次可以写入256个字节
}
else
{
pageremain=NumByteToWrite; //不够256个字节了
}
}
}
}
//带擦除的写0-65536个字节函数
void sFLASH_WriteBuffer(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
uint8_t * psFlashBuff;
psFlashBuff=sFlashBuff;
secpos=WriteAddr/4096;//扇区地址
secoff=WriteAddr%4096;//在扇区内的偏移
secremain=4096-secoff;//扇区剩余空间大小
if(NumByteToWrite<=secremain)
{
secremain=NumByteToWrite;//不大于4096个字节
}
while(1)
{
sFLASH_ReadBuffer(psFlashBuff,secpos*4096,4096);//读出整个扇区的内容
sFLASH_EraseSector(secpos*4096); //擦除这个扇区
for(i=0;i<secremain;i++) //复制
{
psFlashBuff[i+secoff]=pBuffer[i];
}
sFLASH_Write_NoCheck(psFlashBuff,secpos*4096,4096);//写入整个扇区
if(NumByteToWrite==secremain)
{
break;//写入结束了
}
else//写入未结束
{
secpos++;//扇区地址增1
secoff=0;//偏移位置为0
pBuffer+=secremain; //指针偏移
WriteAddr+=secremain; //写地址偏移
NumByteToWrite-=secremain; //字节数递减
if(NumByteToWrite>4096)
{
secremain=4096;//下一个扇区还是写不完
}
else
{
secremain=NumByteToWrite; //下一个扇区可以写完了
}
}
}
}
FLASH.H
#ifndef _H_SPIFLASH_H
#define _H_SPIFLASH_H
/**Includes************************************************************************************/
#include "stm32f1xx_hal.h"
#include "spi.h"
/**Function declaration************************************************************************/
void sFLASH_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
void sFLASH_EraseChip(void);
void sFLASH_WritePage(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void sFLASH_WriteBuffer(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void sFLASH_ReadBuffer(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
uint32_t sFLASH_ReadID(void);
#endif
main.c
检测FLASH_ID判断FLASH是否初始化成功
uint32_t Flash_ID = 0;
Flash_ID = sFLASH_ReadID();
#define PAGE_SIZE 256
#define SECTOR_SIZE 4096
#define SECTOR_COUNT 200
#define BLOCK_SIZE 65536
#define FLASH_PAGES_PER_SECTOR SECTOR_SIZE/PAGE_SIZE
FATFS fs;
FIL file; /* 文件对象 */
FRESULT f_res; /* 文件操作结果 */
UINT fnum; /* 文件成功读写数量 */
BYTE ReadBuffer[1024]={0}; /* 读缓冲区 */
BYTE WriteBuffer[]= "WH is the high hand\n";
BYTE work[512];
char USER_Path[4];
void mount_disk(void)
{
f_res = f_mount(&fs, USER_Path, 0);
return;
}
void format_disk(void)
{
uint8_t res = 0;
//这里根据版本不同函数输入参数不一样
f_res = f_mkfs(USER_Path, 1, 4096);
}
UINT bw;
void create_file(void)
{
FIL file;
FIL *pf = &file;
uint8_t res;
f_res = f_open(pf, "0:/test.txt", FA_OPEN_ALWAYS | FA_WRITE);
f_res = f_write(&file, WriteBuffer, sizeof(WriteBuffer), &bw);
f_res = f_close(pf);
}
void read_file(void)
{
FIL file;
FRESULT res;
uint8_t rbuf[100] = {0};
f_res = f_open(&file, "0:/test.txt", FA_READ);
f_res = f_read(&file, ReadBuffer, sizeof(WriteBuffer), &bw);
f_res = f_close(&file);
}
void FileTest(void)
{
mount_disk();
format_disk();
create_file();
read_file();
}
//初始化函数修改如下
DSTATUS USER_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
/* USER CODE BEGIN INIT */
Stat = STA_NOINIT;
if(sFLASH_ReadID() != 0){
Stat &= ~STA_NOINIT;
}
return Stat;
/* USER CODE END INIT */
}
//状态函修改如下
DSTATUS USER_status (
BYTE pdrv /* Physical drive number to identify the drive */
)
{
/* USER CODE BEGIN STATUS */
Stat &= ~STA_NOINIT;
return Stat;
/* USER CODE END STATUS */
}
//读取函数修改
DRESULT USER_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
/* USER CODE BEGIN READ */
DRESULT res = RES_ERROR;
UINT i;
for(i = 0;i < count;i++)
{
sFLASH_ReadBuffer(buff + i * 4096,sector * 4096 + i * 4096,4096 );
}
res = RES_OK;
return res;
/* USER CODE END READ */
}
//写入函数修改
DRESULT USER_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
/* USER CODE BEGIN WRITE */
DRESULT res = RES_ERROR;
UINT i;
for(i = 0;i < count;i++)
{
sFLASH_WriteBuffer((void *)(buff + i * 4096),sector * 4096 + i * 4096,4096 );
}
res = RES_OK;
/* USER CODE HERE */
return res;
/* USER CODE END WRITE */
}
//枚举函数修改
DRESULT USER_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
/* USER CODE BEGIN IOCTL */
DRESULT res = RES_OK;
switch(cmd)
{
case CTRL_SYNC :
break;
case CTRL_TRIM:
break;
case GET_BLOCK_SIZE:
*(DWORD*)buff = BLOCK_SIZE;
break;
case GET_SECTOR_SIZE:
*(DWORD*)buff = SECTOR_SIZE;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = SECTOR_COUNT;
break;
default:
res = RES_PARERR;
break;
}
return res;
/* USER CODE END IOCTL */
}
最后在main.c文件下
调用测试代码
FileTest();
运行成功
这样SPI FLASH+FATFS配置就完成了!~~~
QQ:1320300083