×
单片机 > 单片机程序设计 > 详情

STM32HAL----USB串行FLASH模拟U盘

发布时间:2020-06-06 发布时间:
|

其实本身是很容易实现的,但中途遇到了一个以往较少注意到的问题:堆栈空间。


参考这个:https://www.cnblogs.com/qsyll0916/p/8013136.html


总的来说,就是因为堆空间分配不足,导致没有足够的空间给USB作缓冲。这个问题网上很多人遇到过,但是


解决这问题帖子没找到。原子的HAL例程是将FLASH当成512字节扇区进行读写的,原因是为了同时挂载SD卡(512)


而堆空间STM32默认就是0x200,512字节。所以原子哥没有遇到这问题。至于硬石的代码,我发现他的程序


误以为USB缓冲使用的是栈空间,当然,实际上使用的是堆空间。所以他修改了启动文件的堆栈大小为:


Stack_Size           EQU     0x1200

Heap_Size            EQU     0x200

正确应为:


Stack_Size           EQU     0x200

Heap_Size            EQU     0x1200


因此,硬石的教程里面没有USB串行FLASH模拟U盘的章节,我猜测他是没调通这个功能,哈哈。


言归正传,STM32CubeMX配置图:



我的FLASH是复用SPI1,PB3、4、5引脚。CS引脚为PB0

USB:选择Device Only  , Mass  Storage  Class这两个选项

RCC与SYS:SWD下载程序,以及选择外部晶振

PA6、PA7:这个是我板子上的两个LED的接口,不用理会。

SPI1复用PB3、4、5:先点PB3,然后在弹出的选项中选择SPI1_SCK,PB4、5方法相同

                                 然后再在左边选项卡开启SPI1,这样SPI1就复用到PB3、4、5了。 


时钟树配置:这个不贴图了,配制成正确的时钟就好。


Configuration:

首先修改SPI1的CS引脚,因为默认SPI1是软件控制的,我使用了PB0控制它:



USB Configuration

这里修改了USB读/写缓冲区的大小,设为4096。因为我的串行FLASH的扇区为4096字节。

当然,如果是SD卡,使用默认的512就可以了。



Project -> Setting


我使用的是MDK,文件名进行了修改,然后修改了堆的大小。

Code Generator:


把这个勾选上,不同外设建立不同.c .h文件。

至此,修改完成,可以生成代码了。

生成代码后,将DeBug里面,Flash Download的Reset And Run勾上,因为生成的工程默认不勾。


还有在Target里面:Use MicroLIB

使用微软的库,这个默认是勾上的。你不用它的库也可以手动取消掉。



生成的代码文件里面,主要修改:"usbd_storage_if.c"

/**

  ******************************************************************************

  * @file           : usbd_storage_if.c

  * @version        : v1.0_Cube

  * @brief          : Memory management layer.

  ******************************************************************************

  * This notice applies to any and all portions of this file

  * that are not between comment pairs USER CODE BEGIN and

  * USER CODE END. Other portions of this file, whether 

  * inserted by the user or by software development tools

  * are owned by their respective copyright owners.

  *

  * Copyright (c) 2018 STMicroelectronics International N.V. 

  * All rights reserved.

  *

  * Redistribution and use in source and binary forms, with or without 

  * modification, are permitted, provided that the following conditions are met:

  *

  * 1. Redistribution of source code must retain the above copyright notice, 

  *    this list of conditions and the following disclaimer.

  * 2. Redistributions in binary form must reproduce the above copyright notice,

  *    this list of conditions and the following disclaimer in the documentation

  *    and/or other materials provided with the distribution.

  * 3. Neither the name of STMicroelectronics nor the names of other 

  *    contributors to this software may be used to endorse or promote products 

  *    derived from this software without specific written permission.

  * 4. This software, including modifications and/or derivative works of this 

  *    software, must execute solely and exclusively on microcontroller or

  *    microprocessor devices manufactured by or for STMicroelectronics.

  * 5. Redistribution and use of this software other than as permitted under 

  *    this license is void and will automatically terminate your rights under 

  *    this license. 

  *

  * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 

  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 

  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 

  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY

  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 

  * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 

  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 

  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 

  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,

  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  *

  ******************************************************************************

  */

 

/* Includes ------------------------------------------------------------------*/

#include "usbd_storage_if.h"

#include "spi.h"

/* USER CODE BEGIN INCLUDE */

 

/* USER CODE END INCLUDE */

 

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

 

/* USER CODE BEGIN PV */

/* Private variables ---------------------------------------------------------*/

 

/* USER CODE END PV */

 

/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY

  * @brief Usb device.

  * @{

  */

 

/** @defgroup USBD_STORAGE

  * @brief Usb mass storage device module

  * @{

  */

 

/** @defgroup USBD_STORAGE_Private_TypesDefinitions

  * @brief Private types.

  * @{

  */

 

/* USER CODE BEGIN PRIVATE_TYPES */

 

/* USER CODE END PRIVATE_TYPES */

 

/**

  * @}

  */

 

/** @defgroup USBD_STORAGE_Private_Defines

  * @brief Private defines.

  * @{

  */

 

#define STORAGE_LUN_NBR                  1

#define STORAGE_BLK_NBR                  512

#define STORAGE_BLK_SIZ                  4096

 

/* USER CODE BEGIN PRIVATE_DEFINES */

 

/* USER CODE END PRIVATE_DEFINES */

 

/**

  * @}

  */

 

/** @defgroup USBD_STORAGE_Private_Macros

  * @brief Private macros.

  * @{

  */

 

/* USER CODE BEGIN PRIVATE_MACRO */

 

/* USER CODE END PRIVATE_MACRO */

 

/**

  * @}

  */

 

/** @defgroup USBD_STORAGE_Private_Variables

  * @brief Private variables.

  * @{

  */

 

/* USER CODE BEGIN INQUIRY_DATA_FS */

/** USB Mass storage Standard Inquiry Data. */

const int8_t STORAGE_Inquirydata_FS[] = {/* 36 */

  

  /* LUN 0 */

  0x00,

  0x80,

  0x02,

  0x02,

  (STANDARD_INQUIRY_DATA_LEN - 5),

  0x00,

  0x00,

  0x00,

  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */

  'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product      : 16 Bytes */

  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',

  '0', '.', '0' ,'1'                      /* Version      : 4 Bytes */

}; 

/* USER CODE END INQUIRY_DATA_FS */

 

/* USER CODE BEGIN PRIVATE_VARIABLES */

 

/* USER CODE END PRIVATE_VARIABLES */

 

/**

  * @}

  */

 

/** @defgroup USBD_STORAGE_Exported_Variables

  * @brief Public variables.

  * @{

  */

 

extern USBD_HandleTypeDef hUsbDeviceFS;

 

/* USER CODE BEGIN EXPORTED_VARIABLES */

 

/* USER CODE END EXPORTED_VARIABLES */

 

/**

  * @}

  */

 

/** @defgroup USBD_STORAGE_Private_FunctionPrototypes

  * @brief Private functions declaration.

  * @{

  */

 

static int8_t STORAGE_Init_FS(uint8_t lun);

static int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size);

static int8_t STORAGE_IsReady_FS(uint8_t lun);

static int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);

static int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);

static int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);

static int8_t STORAGE_GetMaxLun_FS(void);

 

/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */

 

/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */

 

/**

  * @}

  */

 

USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =

{

  STORAGE_Init_FS,

  STORAGE_GetCapacity_FS,

  STORAGE_IsReady_FS,

  STORAGE_IsWriteProtected_FS,

  STORAGE_Read_FS,

  STORAGE_Write_FS,

  STORAGE_GetMaxLun_FS,

  (int8_t *)STORAGE_Inquirydata_FS

};

 

/* Private functions ---------------------------------------------------------*/

/**

  * @brief  Initializes over USB FS IP

  * @param  lun:

  * @retval USBD_OK if all operations are OK else USBD_FAIL

  */

int8_t STORAGE_Init_FS(uint8_t lun)

{

  /* USER CODE BEGIN 2 */

  return (USBD_OK);

  /* USER CODE END 2 */

}

 

/**

  * @brief  .

  * @param  lun: .

  * @param  block_num: .

  * @param  block_size: .

  * @retval USBD_OK if all operations are OK else USBD_FAIL

  */

int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)

{

  /* USER CODE BEGIN 3 */

  *block_num  = STORAGE_BLK_NBR;

  *block_size = STORAGE_BLK_SIZ;

  return (USBD_OK);

  /* USER CODE END 3 */

}

 

/**

  * @brief  .

  * @param  lun: .

  * @retval USBD_OK if all operations are OK else USBD_FAIL

  */

int8_t STORAGE_IsReady_FS(uint8_t lun)

{

  if(SPI_FLASH_ReadID() == FLASH_ID)

    return (USBD_OK);

else

return -1;

}

 

/**

  * @brief  .

  * @param  lun: .

  * @retval USBD_OK if all operations are OK else USBD_FAIL

  */

int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)

{

  /* USER CODE BEGIN 5 */

  return (USBD_OK);

  /* USER CODE END 5 */

}

 

/**

  * @brief  .

  * @param  lun: .

  * @retval USBD_OK if all operations are OK else USBD_FAIL

  */

int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)

{

  SPI_FLASH_BufferRead(buf, blk_addr*STORAGE_BLK_SIZ, blk_len*STORAGE_BLK_SIZ);

  return (USBD_OK);

}

 

/**

  * @brief  .

  * @param  lun: .

  * @retval USBD_OK if all operations are OK else USBD_FAIL

  */

int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)

{

SPI_FLASH_SectorErase(blk_addr*STORAGE_BLK_SIZ);

  SPI_FLASH_BufferWrite(buf, blk_addr*STORAGE_BLK_SIZ,blk_len*STORAGE_BLK_SIZ);

  return (USBD_OK);

}

 

/**

  * @brief  .

  * @param  None

  * @retval .

  */

int8_t STORAGE_GetMaxLun_FS(void)

{

  /* USER CODE BEGIN 8 */

  return (STORAGE_LUN_NBR - 1);

  /* USER CODE END 8 */

}

 

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */

 

/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

 

/**

  * @}

  */

 

/**

  * @}

  */

 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


底层的SPI FLASH的函数,需要自己构建,我的代码如下:


/**

  ******************************************************************************

  * File Name          : SPI.c

  * Description        : This file provides code for the configuration

  *                      of the SPI instances.

  ******************************************************************************

  * This notice applies to any and all portions of this file

  * that are not between comment pairs USER CODE BEGIN and

  * USER CODE END. Other portions of this file, whether 

  * inserted by the user or by software development tools

  * are owned by their respective copyright owners.

  *

  * Copyright (c) 2018 STMicroelectronics International N.V. 

  * All rights reserved.

  *

  * Redistribution and use in source and binary forms, with or without 

  * modification, are permitted, provided that the following conditions are met:

  *

  * 1. Redistribution of source code must retain the above copyright notice, 

  *    this list of conditions and the following disclaimer.

  * 2. Redistributions in binary form must reproduce the above copyright notice,

  *    this list of conditions and the following disclaimer in the documentation

  *    and/or other materials provided with the distribution.

  * 3. Neither the name of STMicroelectronics nor the names of other 

  *    contributors to this software may be used to endorse or promote products 

  *    derived from this software without specific written permission.

  * 4. This software, including modifications and/or derivative works of this 

  *    software, must execute solely and exclusively on microcontroller or

  *    microprocessor devices manufactured by or for STMicroelectronics.

  * 5. Redistribution and use of this software other than as permitted under 

  *    this license is void and will automatically terminate your rights under 

  *    this license. 

  *

  * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 

  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 

  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 

  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY

  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 

  * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 

  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 

  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 

  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,

  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  *

  ******************************************************************************

  */

 

/* Includes ------------------------------------------------------------------*/

#include "spi.h"

 

#include "gpio.h"

 

#define SPI_FLASH_PageSize              256

 

 

/* USER CODE BEGIN 0 */

 

/* USER CODE END 0 */

 

SPI_HandleTypeDef hspi1;

 

uint8_t d_read,d_send;

 

/* SPI1 init function */

void MX_SPI1_Init(void)

{

 

  hspi1.Instance = SPI1;

  hspi1.Init.Mode = SPI_MODE_MASTER;

  hspi1.Init.Direction = SPI_DIRECTION_2LINES;

  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;

  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;

  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;

  hspi1.Init.NSS = SPI_NSS_SOFT;

  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;

  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;

  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;

  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

  hspi1.Init.CRCPolynomial = 10;

  if (HAL_SPI_Init(&hspi1) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

 

}

 

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)

{

 

  GPIO_InitTypeDef GPIO_InitStruct;

  if(spiHandle->Instance==SPI1)

  {

  /* USER CODE BEGIN SPI1_MspInit 0 */

 

  /* USER CODE END SPI1_MspInit 0 */

    /* SPI1 clock enable */

    __HAL_RCC_SPI1_CLK_ENABLE();

  

    /**SPI1 GPIO Configuration    

    PB3     ------> SPI1_SCK

    PB4     ------> SPI1_MISO

    PB5     ------> SPI1_MOSI 

    */

    GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

 

  /* USER CODE BEGIN SPI1_MspInit 1 */

 

  /* USER CODE END SPI1_MspInit 1 */

  }

}

 

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)

{

 

  if(spiHandle->Instance==SPI1)

  {

  /* USER CODE BEGIN SPI1_MspDeInit 0 */

 

  /* USER CODE END SPI1_MspDeInit 0 */

    /* Peripheral clock disable */

    __HAL_RCC_SPI1_CLK_DISABLE();

  

    /**SPI1 GPIO Configuration    

    PB3     ------> SPI1_SCK

    PB4     ------> SPI1_MISO

    PB5     ------> SPI1_MOSI 

    */

    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);

 

  /* USER CODE BEGIN SPI1_MspDeInit 1 */

 

  /* USER CODE END SPI1_MspDeInit 1 */

  }

 

 

/********************************************FLASH API********************************************************/

 

//函数功能: 从串行Flash读取一个字节数据

uint8_t SPI_FLASH_ReadByte(void)

{

  if(HAL_SPI_TransmitReceive(&hspi1,&d_send,&d_read,1,0xFFFFFF)!=HAL_OK)

    d_read=0xff;

  

  return d_read;    

}

 

 

// 函数功能: 往串行Flash读取写入一个字节数据并接收一个字节数据

uint8_t SPI_FLASH_SendByte(uint8_t byte)

{

  if(HAL_SPI_TransmitReceive(&hspi1,&byte,&d_read,1,0xFFFFFF)!=HAL_OK)

   return 1;

  

   return 0; 

}

 

 

 

 

 

 

 

 

 

//读取Flash ID

uint32_t SPI_FLASH_ReadID(void)

{

  uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;

 

  /* 选择串行FLASH: CS低电平 */

  FLASH_L

 

  /* 发送命令:读取芯片型号ID */

  SPI_FLASH_SendByte(0x9F);

 

  Temp0 = SPI_FLASH_ReadByte();

  Temp1 = SPI_FLASH_ReadByte();

  Temp2 = SPI_FLASH_ReadByte();

 

  /* 禁用串行Flash:CS高电平 */

  FLASH_H

  

  Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;

  return Temp;

}

 

 

//从Flash读取数据

void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)

{

  FLASH_L

 

  SPI_FLASH_SendByte(0x03);

 

  SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);

  SPI_FLASH_SendByte((ReadAddr & 0xFF00) >> 8);

  SPI_FLASH_SendByte(ReadAddr  & 0xFF);

 

  while (NumByteToRead--) /* 读取数据 */

  {

    *pBuffer = SPI_FLASH_ReadByte();

    pBuffer++;

  }

 

  FLASH_H

}

 

 

 

void SPI_FLASH_PageWrite(uint8_t* pBuffer,uint32_t addr,uint16_t NumByteToRead)

{

 uint16_t i;

    SPI_FLASH_WriteEnable();            //SET WEL

 FLASH_L

 SPI_FLASH_SendByte(0x02);

    SPI_FLASH_SendByte((uint8_t)((addr)>>16)); //发送24bit地址    

    SPI_FLASH_SendByte((uint8_t)((addr)>>8));   

    SPI_FLASH_SendByte((uint8_t)addr); 

 for(i=0;i

 {

SPI_FLASH_SendByte(pBuffer[i]);//循环写数  

}

 FLASH_H                             //取消片选 

 SPI_FLASH_WaitForWriteEnd(); //等待写入结束

}

 

 

//FLASH写函数

void SPI_FLASH_BufferWrite(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t NumByteToWrite)   

{  

uint32_t pageremain;   

pageremain=256-WriteAddr%256; //单页剩余的字节数    

if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节

while(1)

{   

SPI_FLASH_PageWrite(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个字节了

}

}    

 

 

/* 函数功能: 擦除扇区 */

void SPI_FLASH_SectorErase(uint32_t SectorAddr)

{

  SPI_FLASH_WriteEnable();

  SPI_FLASH_WaitForWriteEnd();

 

  FLASH_L

  SPI_FLASH_SendByte(0x20);

  SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);

  SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);

  SPI_FLASH_SendByte(SectorAddr & 0xFF);

 

  FLASH_H

 

  SPI_FLASH_WaitForWriteEnd();

}

 

 

/* 函数功能: 擦除整个芯片 */

void SPI_FLASH_BulkErase(void)

{

  SPI_FLASH_WriteEnable();

 

  FLASH_L

  SPI_FLASH_SendByte(0xC7);

  FLASH_H

 

  SPI_FLASH_WaitForWriteEnd();

}

 

 

//写使能

void SPI_FLASH_WriteEnable(void)

{

  FLASH_L

  SPI_FLASH_SendByte(0x06);

  FLASH_H

}

 

 

 

//等待写入完毕

void SPI_FLASH_WaitForWriteEnd(void)

{

  uint8_t FLASH_Status = 0;

 

  FLASH_L

 

  SPI_FLASH_SendByte(0x05);

 

  do

  {

    FLASH_Status = SPI_FLASH_ReadByte();  

  }

  while ((FLASH_Status & 0x01) == SET); 

 

  FLASH_H

}

 

 

 

/**

  * 函数功能: 进入掉电模式

  * 输入参数: 无

  * 返 回 值: 无

  * 说    明:无

  */

void SPI_Flash_PowerDown(void)   

  FLASH_L

 

  SPI_FLASH_SendByte(0xB9);

 

  FLASH_H

}   

 

/**

  * 函数功能: 唤醒串行Flash

  * 输入参数: 无

  * 返 回 值: 无

  * 说    明:无

  */

void SPI_Flash_WAKEUP(void)   

{

  FLASH_L

 

  SPI_FLASH_SendByte(0xAB);

 

  FLASH_H 

}   

 

 

 

 

 

/**

  * @}

  */

 

/**

  * @}

  */

 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

SPI.H:


/**

  ******************************************************************************

  * File Name          : SPI.h

  * Description        : This file provides code for the configuration

  *                      of the SPI instances.

  ******************************************************************************

  * This notice applies to any and all portions of this file

  * that are not between comment pairs USER CODE BEGIN and

  * USER CODE END. Other portions of this file, whether 

  * inserted by the user or by software development tools

  * are owned by their respective copyright owners.

  *

  * Copyright (c) 2018 STMicroelectronics International N.V. 

  * All rights reserved.

  *

  * Redistribution and use in source and binary forms, with or without 

  * modification, are permitted, provided that the following conditions are met:

  *

  * 1. Redistribution of source code must retain the above copyright notice, 

  *    this list of conditions and the following disclaimer.

  * 2. Redistributions in binary form must reproduce the above copyright notice,

  *    this list of conditions and the following disclaimer in the documentation

  *    and/or other materials provided with the distribution.

  * 3. Neither the name of STMicroelectronics nor the names of other 

  *    contributors to this software may be used to endorse or promote products 

  *    derived from this software without specific written permission.

  * 4. This software, including modifications and/or derivative works of this 

  *    software, must execute solely and exclusively on microcontroller or

  *    microprocessor devices manufactured by or for STMicroelectronics.

  * 5. Redistribution and use of this software other than as permitted under 

  *    this license is void and will automatically terminate your rights under 

  *    this license. 

  *

  * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS" 

  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 

  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 

  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY

  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 

  * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,

  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 

  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 

  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 

  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,

  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  *

  ******************************************************************************

  */

/* Define to prevent recursive inclusion -------------------------------------*/

#ifndef __spi_H

#define __spi_H

#ifdef __cplusplus

 extern "C" {

#endif

 

/* Includes ------------------------------------------------------------------*/

#include "stm32f4xx_hal.h"

#include "main.h"

 

 

#define  FLASH_ID    0xEF4015  

 

#define  FLASH_L   GPIOB->BSRR = GPIO_PIN_0<<16U;

#define  FLASH_H GPIOB->BSRR = GPIO_PIN_0;  

 

 

/* USER CODE BEGIN Includes */

 

/* USER CODE END Includes */

 

extern SPI_HandleTypeDef hspi1;

 

/* USER CODE BEGIN Private defines */

 

/* USER CODE END Private defines */

 

extern void _Error_Handler(char *, int);

 

void MX_SPI1_Init(void);

 

/* USER CODE BEGIN Prototypes */

 

/* USER CODE END Prototypes */

 

#ifdef __cplusplus

}

#endif

#endif /*__ spi_H */

 

 

 

 

/***************FLASH API******************/

 

uint32_t SPI_FLASH_ReadID(void);

 

void SPI_FLASH_BufferWrite(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t NumByteToWrite);

 

void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);

 

void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);

 

void SPI_FLASH_SectorErase(uint32_t SectorAddr);

 

void SPI_FLASH_BulkErase(void);

 

void SPI_FLASH_WriteEnable(void);

 

void SPI_FLASH_WaitForWriteEnd(void);

 

void SPI_Flash_PowerDown(void);

 

void SPI_Flash_WAKEUP(void);

 

 

 

 

/**

  * @}

  */

 

/**

  * @}

  */

 

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


SPI代码,大部分用的是硬石的。我自己也有写,但就是想试试别人的代码。当然他代码也存在一些问题,他没有将


uint8_t SPI_FLASH_ReadByte(void);

uint8_t SPI_FLASH_SendByte(uint8_t byte);

的功能区分开,导致这两个函数实现一样的功能(SPI寄存器数据回环),我修改了一下,使它们读写功能分开,


而且更精简一些。


void SPI_FLASH_BufferWrite(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t NumByteToWrite);

这个函数的是原子的,因为硬石写得太啰嗦 - . -




修改完SPI以及"usbd_storage_if.c",编译过后烧写进芯片。

烧写完后需要重新插拔USB,然后就会弹出新的U盘,你U盘中没有文件系统的话,会要求你格式化的。结果如图:



我的FLASH是W25Q16,所以显示2MB容量。





『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址