STM32F4 + HAL库 + W25Q256的验证

67 篇文章 19 订阅
30 篇文章 4 订阅

前言

今天验证打样板子上的W25Q256, 验证过了。做个笔记。

硬件电路

MCU = STM32F407IGT6
W25 = W25Q256JVEIQ 封装 = WSON-8 8x6mm
SPI方式读写,使用SPI2.
在这里插入图片描述
在这里插入图片描述
W25按照STM32接SPI设备的正常SPI方式连接, 为了布线方便,将SPI2管脚从默认管脚复用到PB12这边。

CubeMX配置

在这里插入图片描述
硬件电路上,SPI时钟线没接上拉电阻,将时钟管脚配置为上拉。
剩下用CubeMX默认选项,不用改。

W25Q256 HAL版驱动

csdn上有个同学写好了(https://blog.csdn.net/sudaroot/article/details/93158309),拿来验证一下,通过了。
那个驱动中,使用的是SPI5, 我这里是SPI2, 就这点区别。硬编码的SPI5句柄,用宏替代。

焊接

W25 = W25Q256JVEIQ 封装 = WSON-8 8x6mm
WSON-8的焊盘在芯片肚皮下面,两边只露出一点管脚,肚皮上还有一大片散热焊盘。用烙铁整的不靠谱,我在PCB上涂上锡膏,用热风枪吹的,因为买的锡膏注射器还在路上,用棉签挑的焊锡膏,涂的到处都是,第一次吹焊,芯片都不平。重新吹下来,将多余锡用烙铁弄掉,第二次吹焊才成功。
热风枪焊接确实挺方便,就看没钢网的情况下,用锡膏注射器效果咋样。
在这里插入图片描述

测试程序

按照扇区(4096字节)对齐进行扇区读写,好使。

焊完板子,实验w25读写之前,要先读下ID, 如果是0xEF,就说明w25q256设备焊的没问题。
在读ID之前,要先调用 BSP_W25Q256_Init(), 剩下的读写操作才正常。

调试这个板子,用JLINKV9各种问题,不知道是不是非原版JLINK的问题。不过正版JLINK也没必要用啊。

开始一直以为是自己板子焊接的挫或者原理图错了或者器件坏了或者器件值焊接错了。后来发现,是手头这个JLINKV9是坑货…, 害的我特意整了一个小板去打样。

只能使用STLINK(本次是STLINKV2)

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "rtc.h"
#include "spi.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdbool.h>
#include <string.h>
#include "w25q256.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

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

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */

uint8_t ucary_w25_section_rd[W25Q256FV_SECTOR_SIZE];
uint8_t ucary_w25_page_rd[W25Q256FV_PAGE_SIZE];

bool is_w25_section_buf_empty(uint8_t* ucary_w25_section_rd)
{
  bool b_rc = true; // empty is true
  int i = 0;
  
  do {
    if (NULL == ucary_w25_section_rd) {
      break;
    }
    
    for (i = 0; i < W25Q256FV_SECTOR_SIZE; i++) {
      if (0xff != ucary_w25_section_rd[i]) {
        b_rc = false;
        break;
      }
    }
    
  } while (0);
  
  return b_rc;
}

bool is_w25_page_buf_empty(uint8_t* ucary_w25_page_rd)
{
  bool b_rc = true; // empty is true
  int i = 0;
  
  do {
    if (NULL == ucary_w25_page_rd) {
      break;
    }
    
    for (i = 0; i < W25Q256FV_PAGE_SIZE; i++) {
      if (0xff != ucary_w25_page_rd[i]) {
        b_rc = false;
        break;
      }
    }
    
  } while (0);
  
  return b_rc;
}

int main(void)
{
  /* USER CODE BEGIN 1 */
  uint8_t u8_w25_ID = 0;
  HAL_StatusTypeDef errorcode = HAL_OK;
  int w25_rc = W25Q256_OK;
  
  memset(ucary_w25_page_rd, 0, sizeof(ucary_w25_page_rd));
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_RTC_Init();
  MX_SPI2_Init();
  /* USER CODE BEGIN 2 */

  u8_w25_ID = 0x00;
  BSP_W25Q256_Init();
  errorcode = BSP_W25Q256_Read_ID(&u8_w25_ID);
  if (HAL_OK != errorcode) {
    LED_Flashing(1, 500);
  }
  
  w25_rc = BSP_W25Q256_Read(ucary_w25_section_rd, 0, W25Q256FV_SECTOR_SIZE);
  if (W25Q256_OK != w25_rc) {
    LED_Flashing(1, 500);
  } else {
    // read page is ok
    if (!is_w25_section_buf_empty(ucary_w25_section_rd)) {
        // earse page first, then write a new page content
        w25_rc = BSP_W25Q256_Erase_Sector(0);
        if (W25Q256_OK != w25_rc) {
          LED_Flashing(1, 500);
        }

        w25_rc = BSP_W25Q256_Read(ucary_w25_section_rd, 0, W25Q256FV_SECTOR_SIZE);
        if (W25Q256_OK != w25_rc) {
          LED_Flashing(1, 500);
        }
    } else {
      strcpy((char*)ucary_w25_section_rd, "hello w25q256:)");
      w25_rc = BSP_W25Q256_Write(ucary_w25_section_rd, 0, W25Q256FV_SECTOR_SIZE);
      if (W25Q256_OK != w25_rc) {
        LED_Flashing(1, 500);
      }
    }
  }
  
  w25_rc = BSP_W25Q256_Read(ucary_w25_section_rd, 0, W25Q256FV_SECTOR_SIZE);
  if (W25Q256_OK != w25_rc) {
    LED_Flashing(1, 500);
  }
  
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    LED_Flashing(0, 500);
    LED_Flashing(0, 500);
    LED_Flashing(0, 500);
    
    LED_Flashing(1, 1000);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.LSEState = RCC_LSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

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

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.h
  * @brief          : Header for main.c file.
  *                   This file contains the common defines of the application.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */

/* USER CODE END ET */

/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */

/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */

/* USER CODE END EM */

/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);

/* USER CODE BEGIN EFP */

/* USER CODE END EFP */

/* Private defines -----------------------------------------------------------*/
#define MCU_LED0_Pin GPIO_PIN_8
#define MCU_LED0_GPIO_Port GPIOH
#define MCU_LED1_Pin GPIO_PIN_9
#define MCU_LED1_GPIO_Port GPIOH
#define MY_SPI2_CS_Pin GPIO_PIN_12
#define MY_SPI2_CS_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */

#define W25Q256_CS_GPIO_Port MY_SPI2_CS_GPIO_Port
#define W25Q256_CS_Pin MY_SPI2_CS_Pin

/* USER CODE END Private defines */

#ifdef __cplusplus
}
#endif

#endif /* __MAIN_H */

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

// @file w25q256.h
#ifndef __W25Q256_H__
#define __W25Q256_H__

/********************************Copyright (c)**********************************\
**
**                   (c) Copyright 2019, Main, China, Sudaroot.
**                           All Rights Reserved
**
**                           By(Sudaroot personally owned)
**                           https://me.csdn.net/sudaroot/
**
**----------------------------------文件信息------------------------------------
** 文件名称: w25q256.h
** 创建人员: Sudaroot
** 创建日期: 2019-07-22
** 文档描述: 
**
**----------------------------------版本信息------------------------------------
** 版本代号: V0.1
** 版本说明: 初始版本
**
**------------------------------------------------------------------------------
\********************************End of Head************************************/
 
#ifndef __W25Q256_H_
#define __W25Q256_H_
 
#ifdef __cplusplus
extern "C" {
#endif
 
/* Includes ------------------------------------------------------------------*/
#include "main.h"
 
/** @addtogroup BSP
  * @{
  */
 
/** @addtogroup Components
  * @{
  */
 
/** @addtogroup W25Q256FV
  * @{
  */
 
/** @defgroup W25Q256FV_Exported_Types
  * @{
  */
 
/**
  * @}
  */
 
/** @defgroup W25Q256FV_Exported_Constants
  * @{
  */
 
/**
  * @brief  W25Q256FV Configuration
  */
#define W25Q256FV_FLASH_SIZE                  0x2000000 /* 256 MBits => 32MBytes */
#define W25Q256FV_BLOCK_SIZE                  0x10000   /* 512 sectors of 64KBytes */
#define W25Q256FV_SECTOR_SIZE                 0x1000    /* 4096 subsectors of 4kBytes */
#define W25Q256FV_PAGE_SIZE                   0x100     /* 65536 pages of 256 bytes */
 
#define W25Q256FV_DUMMY_CYCLES_READ           4
#define W25Q256FV_DUMMY_CYCLES_READ_QUAD      10
 
#define W25Q256FV_BULK_ERASE_MAX_TIME         400000
#define W25Q256FV_BLOCK_ERASE_MAX_TIME        5000
#define W25Q256FV_SECTOR_ERASE_MAX_TIME       2000
#define W25Q256_TIMEOUT_VALUE                 1000
 
/**
  * @brief  W25Q256FV Commands
  */
/* Reset Operations */
#define RESET_ENABLE_CMD                     0x66
#define RESET_MEMORY_CMD                     0x99
 
#define ENTER_QPI_MODE_CMD                   0x38
#define EXIT_QPI_MODE_CMD                    0xFF
 
/* Identification Operations */
#define READ_ID_CMD                          0x90
#define DUAL_READ_ID_CMD                     0x92
#define QUAD_READ_ID_CMD                     0x94
#define READ_JEDEC_ID_CMD                    0x9F
 
/* Read Operations */
#define READ_CMD                             0x03
#define READ_4BTYEADDR_CMD                   0x13
#define FAST_READ_CMD                        0x0B
#define DUAL_OUT_FAST_READ_CMD               0x3B
#define DUAL_INOUT_FAST_READ_CMD             0xBB
#define QUAD_OUT_FAST_READ_CMD               0x6B
#define QUAD_INOUT_FAST_READ_CMD             0xEB
 
/* Write Operations */
#define WRITE_ENABLE_CMD                     0x06
#define WRITE_DISABLE_CMD                    0x04
 
/* Register Operations */
#define READ_STATUS_REG1_CMD                 0x05
#define READ_STATUS_REG2_CMD                 0x35
#define READ_STATUS_REG3_CMD                 0x15
 
#define WRITE_STATUS_REG1_CMD                0x01
#define WRITE_STATUS_REG2_CMD                0x31
#define WRITE_STATUS_REG3_CMD                0x11
 
 
/* Program Operations */
#define PAGE_PROG_CMD                        0x02
#define QUAD_INPUT_PAGE_PROG_CMD             0x32
 
 
/* Erase Operations */
#define SECTOR_ERASE_CMD                     0x20
#define BLOCK_ERASE_CMD                      0xD8
#define CHIP_ERASE_CMD                       0xC7
 
#define PROG_ERASE_RESUME_CMD                0x7A
#define PROG_ERASE_SUSPEND_CMD               0x75
 
/* Address Mode */
#define ENTER_4BYTE_ADDRESS_MODE             0xB7
#define EXIT_4BYTE_ADDRESS_MODE              0xE9
 
/* Flag Status Register */
#define W25Q256FV_FSR_BUSY                    ((uint8_t)0x01)    /*!< busy */
#define W25Q256FV_FSR_WREN                    ((uint8_t)0x02)    /*!< write enable */
#define W25Q256FV_FSR_QE                      ((uint8_t)0x02)    /*!< quad enable */
 
 
#define W25Q256_Enable() 			        HAL_GPIO_WritePin(W25Q256_CS_GPIO_Port, W25Q256_CS_Pin, GPIO_PIN_RESET)
#define W25Q256_Disable() 		            HAL_GPIO_WritePin(W25Q256_CS_GPIO_Port, W25Q256_CS_Pin, GPIO_PIN_SET)
 
#define W25Q256_OK                          ((uint8_t)0x00)
#define W25Q256_ERROR                       ((uint8_t)0x01)
#define W25Q256_BUSY                        ((uint8_t)0x02)
#define W25Q256_TIMEOUT				        ((uint8_t)0x03)
 
 
uint8_t BSP_W25Q256_Init(void);
uint8_t	BSP_W25Q256_Reset(void);
uint8_t BSP_W25Q256_GetStatus(void);
uint8_t BSP_W25Q256_WriteEnable(void);
HAL_StatusTypeDef    BSP_W25Q256_Read_ID(uint8_t *ID);
uint8_t BSP_W25Q256_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size);
uint8_t BSP_W25Q256_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size);
uint8_t BSP_W25Q256_Erase_Sector(uint32_t Address);
uint8_t BSP_W25Q256_Erase_Block(uint32_t Address);
uint8_t BSP_W25Q256_Erase_Chip(void);
uint8_t BSP_W25Q256_Enter4ByteAddressMode(void);
uint8_t BSP_W25Q256_Exit4ByteAddressMode(void);
 
 
/**
  * @}
  */
 
/** @defgroup W25Q256FV_Exported_Functions
  * @{
  */
/**
  * @}
  */
 
/**
  * @}
  */
 
/**
  * @}
  */
 
/**
  * @}
  */
 
#ifdef __cplusplus
}
#endif
 
 
#endif /* __W25Q256_H */
 
 
/********************************End of File************************************/

#endif // #ifndef __W25Q256_H__

// @file w25q256.c
/********************************Copyright (c)**********************************\
**
**                   (c) Copyright 2019, Main, China, Sudaroot.
**                           All Rights Reserved
**
**                           By(Sudaroot personally owned)
**                           https://me.csdn.net/sudaroot/
**
**----------------------------------文件信息------------------------------------
** 文件名称: w25q256.c
** 创建人员: Sudaroot
** 创建日期: 2019-07-22
** 文档描述: 
**
**----------------------------------版本信息------------------------------------
** 版本代号: V0.1
** 版本说明: 初始版本
**
**------------------------------------------------------------------------------
\********************************End of Head************************************/
 
#include "w25q256.h"
extern SPI_HandleTypeDef hspi_w25;
 
 
/**
  * @brief  Initializes the W25Q256FV interface.
  * @retval None
  */
uint8_t BSP_W25Q256_Init(void)
{
    /* Reset W25Q256xx */
    uint8_t res = 0;
    res = BSP_W25Q256_Reset();
    if(res != W25Q256_OK) return res;
    
    res = BSP_W25Q256_Enter4ByteAddressMode();
    return res;
}
 
/**
  * @brief  This function reset the W25Q256.
  * @retval None
  */
uint8_t BSP_W25Q256_Reset(void)
{
    uint32_t tickstart = HAL_GetTick();
    uint8_t cmd[2] = {RESET_ENABLE_CMD, RESET_MEMORY_CMD};
        
    W25Q256_Enable();
    /* Send the reset command */
    HAL_SPI_Transmit(&hspi_w25, cmd, 2, W25Q256_TIMEOUT_VALUE);
    W25Q256_Disable();
    
        /* Wait the end of Flash writing */
    while(BSP_W25Q256_GetStatus() == W25Q256_BUSY)
    {
        /* Check for the Timeout */
        if((HAL_GetTick() - tickstart) > W25Q256_TIMEOUT_VALUE)
        {
            return W25Q256_TIMEOUT;
        }
    }
 
    return W25Q256_OK;
 
}
 
/**
  * @brief  Reads current status of the W25Q256FV.
  * @retval W25Q256FV memory status
  */
uint8_t BSP_W25Q256_GetStatus(void)
{
    uint8_t cmd[] = {READ_STATUS_REG1_CMD};
    uint8_t status;
 
    W25Q256_Enable();
    /* Send the read status command */
    HAL_SPI_Transmit(&hspi_w25, cmd, 1, W25Q256_TIMEOUT_VALUE);
    /* Reception of the data */
    HAL_SPI_Receive(&hspi_w25, &status, 1, W25Q256_TIMEOUT_VALUE);
    W25Q256_Disable();
 
    /* Check the value of the register */
    if((status & W25Q256FV_FSR_BUSY) != 0)
    {
        return W25Q256_BUSY;
    }
    else
    {
        return W25Q256_OK;
    }
}
 
 
/**
  * @brief  This function send a Enter 4-Byte Address Mode (B7h)
  * @retval None
  */
uint8_t BSP_W25Q256_Enter4ByteAddressMode(void)
{
    uint8_t cmd[] = {ENTER_4BYTE_ADDRESS_MODE};
    uint32_t tickstart = HAL_GetTick();
 
    /*Select the FLASH: Chip Select low */
    W25Q256_Enable();
    /* Send the read ID command */
    HAL_SPI_Transmit(&hspi_w25, cmd, 1, W25Q256_TIMEOUT_VALUE);
    /*Deselect the FLASH: Chip Select high */
    W25Q256_Disable();
 
    /* Wait the end of Flash writing */
    while(BSP_W25Q256_GetStatus() == W25Q256_BUSY)
    {
        /* Check for the Timeout */
        if((HAL_GetTick() - tickstart) > W25Q256_TIMEOUT_VALUE)
        {
            return W25Q256_TIMEOUT;
        }
    }
 
    return W25Q256_OK;
}
 
 
 
/**
  * @brief  This function send a Exit 4-Byte Address Mode (E9h)
  * @retval None
  */
uint8_t BSP_W25Q256_Exit4ByteAddressMode(void)
{
    uint8_t cmd[] = {EXIT_4BYTE_ADDRESS_MODE};
    uint32_t tickstart = HAL_GetTick();
 
    /*Select the FLASH: Chip Select low */
    W25Q256_Enable();
    /* Send the read ID command */
    HAL_SPI_Transmit(&hspi_w25, cmd, 1, W25Q256_TIMEOUT_VALUE);
    /*Deselect the FLASH: Chip Select high */
    W25Q256_Disable();
 
    /* Wait the end of Flash writing */
    while(BSP_W25Q256_GetStatus() == W25Q256_BUSY)
    {
        /* Check for the Timeout */
        if((HAL_GetTick() - tickstart) > W25Q256_TIMEOUT_VALUE)
        {
            return W25Q256_TIMEOUT;
        }
    }
 
    return W25Q256_OK;
}
 
 
 
 
 
/**
  * @brief  This function send a Write Enable and wait it is effective.
  * @retval None
  */
uint8_t BSP_W25Q256_WriteEnable(void)
{
    uint8_t cmd[] = {WRITE_ENABLE_CMD};
    uint32_t tickstart = HAL_GetTick();
 
    /*Select the FLASH: Chip Select low */
    W25Q256_Enable();
    /* Send the read ID command */
    HAL_SPI_Transmit(&hspi_w25, cmd, 1, W25Q256_TIMEOUT_VALUE);
    /*Deselect the FLASH: Chip Select high */
    W25Q256_Disable();
 
    /* Wait the end of Flash writing */
    while(BSP_W25Q256_GetStatus() == W25Q256_BUSY)
    {
        /* Check for the Timeout */
        if((HAL_GetTick() - tickstart) > W25Q256_TIMEOUT_VALUE)
        {
            return W25Q256_TIMEOUT;
        }
    }
 
    return W25Q256_OK;
}
 
/**
  * @brief  Read Manufacture/Device ID.
	* @param  return value address
  * @retval None
  */
HAL_StatusTypeDef BSP_W25Q256_Read_ID(uint8_t *ID)
{
    uint8_t cmd[4] = {READ_ID_CMD, 0x00, 0x00, 0x00};
    HAL_StatusTypeDef e_rc = HAL_OK;
 
    W25Q256_Enable();
    
    do {
      /* Send the read ID command */
      e_rc = HAL_SPI_Transmit(&hspi_w25, cmd, 4, W25Q256_TIMEOUT_VALUE);
      if (HAL_OK != e_rc) {
        break;
      }
      /* Reception of the data */
      e_rc = HAL_SPI_Receive(&hspi_w25, ID, 2, W25Q256_TIMEOUT_VALUE);
      if (HAL_OK != e_rc) {
        break;
      }
    } while (0);

    W25Q256_Disable();
 
    return e_rc;
}
 
/**
  * @brief  Reads an amount of data from the QSPI memory.
  * @param  pData: Pointer to data to be read
  * @param  ReadAddr: Read start address
  * @param  Size: Size of data to read
  * @retval QSPI memory status
  */
uint8_t BSP_W25Q256_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size)
{
    uint8_t cmd[5];
    
    /* Check parameter */
    if(ReadAddr >= W25Q256FV_FLASH_SIZE || (ReadAddr + Size) >= W25Q256FV_FLASH_SIZE)
        return W25Q256_ERROR;
    
    /* Configure the command */
    cmd[0] = READ_CMD;
    cmd[1] = (uint8_t)(ReadAddr >> 24);   
    cmd[2] = (uint8_t)(ReadAddr >> 16);
    cmd[3] = (uint8_t)(ReadAddr >> 8);
    cmd[4] = (uint8_t)(ReadAddr);
 
    W25Q256_Enable();
    /* Send the read ID command */
    HAL_SPI_Transmit(&hspi_w25, cmd, 5, W25Q256_TIMEOUT_VALUE);
 
    /* Reception of the data */
    if (HAL_SPI_Receive(&hspi_w25, pData, Size, W25Q256_TIMEOUT_VALUE) != HAL_OK)
    {
        return W25Q256_ERROR;
    }
 
    W25Q256_Disable();
    return W25Q256_OK;
}
 
/**
  * @brief  Writes an amount of data to the QSPI memory.
  * @param  pData: Pointer to data to be written
  * @param  WriteAddr: Write start address
  * @param  Size: Size of data to write,No more than 256byte.
  * @retval QSPI memory status
  */
uint8_t BSP_W25Q256_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size)
{
    uint8_t cmd[5];
    uint32_t end_addr, current_size, current_addr;
    uint32_t tickstart = HAL_GetTick();
 
    /* Check parameter */
    if(WriteAddr >= W25Q256FV_FLASH_SIZE || (WriteAddr + Size) >= W25Q256FV_FLASH_SIZE)
        return W25Q256_ERROR;
    
    /* Calculation of the size between the write address and the end of the page */
    current_addr = 0;
 
    while (current_addr <= WriteAddr)
    {
        current_addr += W25Q256FV_PAGE_SIZE;
    }
 
    current_size = current_addr - WriteAddr;
 
    /* Check if the size of the data is less than the remaining place in the page */
    if (current_size > Size)
    {
        current_size = Size;
    }
 
    /* Initialize the adress variables */
    current_addr = WriteAddr;
    end_addr = WriteAddr + Size;
 
    /* Perform the write page by page */
    do
    {
        /* Configure the command */
        cmd[0] = PAGE_PROG_CMD;
        cmd[1] = (uint8_t)(current_addr >> 24);
        cmd[2] = (uint8_t)(current_addr >> 16);
        cmd[3] = (uint8_t)(current_addr >> 8);
        cmd[4] = (uint8_t)(current_addr);
 
        /* Enable write operations */
        BSP_W25Q256_WriteEnable();
 
        W25Q256_Enable();
 
        /* Send the command */
        if (HAL_SPI_Transmit(&hspi_w25, cmd, 5, W25Q256_TIMEOUT_VALUE) != HAL_OK)
        {
            return W25Q256_ERROR;
        }
 
        /* Transmission of the data */
        if (HAL_SPI_Transmit(&hspi_w25, pData, current_size, W25Q256_TIMEOUT_VALUE) != HAL_OK)
        {
            return W25Q256_ERROR;
        }
 
        W25Q256_Disable();
 
        /* Wait the end of Flash writing */
        while(BSP_W25Q256_GetStatus() == W25Q256_BUSY)
        {
            /* Check for the Timeout */
            if((HAL_GetTick() - tickstart) > W25Q256_TIMEOUT_VALUE)
            {
                return W25Q256_TIMEOUT;
            }
        }
 
        /* Update the address and size variables for next page programming */
        current_addr += current_size;
        pData += current_size;
        current_size = ((current_addr + W25Q256FV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q256FV_PAGE_SIZE;
    }
    while (current_addr < end_addr);
 
 
    return W25Q256_OK;
}
 
 
 
 
 
 
uint8_t BSP_W25Q256_Erase_Sector(uint32_t Address)
{
    uint8_t cmd[5];
    uint32_t tickstart = HAL_GetTick();
    
        /* Check parameter */
    if(Address >= W25Q256FV_FLASH_SIZE)
        return W25Q256_ERROR;
    
    cmd[0] = SECTOR_ERASE_CMD;
    cmd[1] = (uint8_t)(Address >> 24);
    cmd[2] = (uint8_t)(Address >> 16);
    cmd[3] = (uint8_t)(Address >> 8);
    cmd[4] = (uint8_t)(Address);
 
    /* Enable write operations */
    BSP_W25Q256_WriteEnable();
 
    /*Select the FLASH: Chip Select low */
    W25Q256_Enable();
    /* Send the read ID command */
    HAL_SPI_Transmit(&hspi_w25, cmd, 5, W25Q256_TIMEOUT_VALUE);
    /*Deselect the FLASH: Chip Select high */
    W25Q256_Disable();
 
    /* Wait the end of Flash writing */
    while(BSP_W25Q256_GetStatus() == W25Q256_BUSY)
    {
        /* Check for the Timeout */
        if((HAL_GetTick() - tickstart) > W25Q256FV_SECTOR_ERASE_MAX_TIME)
        {
            return W25Q256_TIMEOUT;
        }
    }
    return W25Q256_OK;
}
 
 
 
/**
  * @brief  Erases the specified block of the QSPI memory.
  * @param  BlockAddress: Block address to erase
  * @retval QSPI memory status
  */
uint8_t BSP_W25Q256_Erase_Block(uint32_t Address)
{
    uint8_t cmd[5];
    uint32_t tickstart = HAL_GetTick();
    
    if(Address >= W25Q256FV_FLASH_SIZE)
        return W25Q256_ERROR;
    
    cmd[0] = BLOCK_ERASE_CMD;
    cmd[1] = (uint8_t)(Address >> 24);
    cmd[2] = (uint8_t)(Address >> 16);
    cmd[3] = (uint8_t)(Address >> 8);
    cmd[4] = (uint8_t)(Address);
 
    /* Enable write operations */
    BSP_W25Q256_WriteEnable();
 
    /*Select the FLASH: Chip Select low */
    W25Q256_Enable();
    /* Send the read ID command */
    HAL_SPI_Transmit(&hspi_w25, cmd, 5, W25Q256_TIMEOUT_VALUE);
    /*Deselect the FLASH: Chip Select high */
    W25Q256_Disable();
 
    /* Wait the end of Flash writing */
    while(BSP_W25Q256_GetStatus() == W25Q256_BUSY)
    {
        /* Check for the Timeout */
        if((HAL_GetTick() - tickstart) > W25Q256FV_BLOCK_ERASE_MAX_TIME)
        {
            return W25Q256_TIMEOUT;
        }
    }
    return W25Q256_OK;
}
 
/**
  * @brief  Erases the entire QSPI memory.This function will take a very long time.
  * @retval QSPI memory status
  */
uint8_t BSP_W25Q256_Erase_Chip(void)
{
    uint8_t cmd[4];
    uint32_t tickstart = HAL_GetTick();
    cmd[0] = CHIP_ERASE_CMD;
 
    /* Enable write operations */
    BSP_W25Q256_WriteEnable();
 
    /*Select the FLASH: Chip Select low */
    W25Q256_Enable();
    /* Send the read ID command */
    HAL_SPI_Transmit(&hspi_w25, cmd, 1, W25Q256_TIMEOUT_VALUE);
    /*Deselect the FLASH: Chip Select high */
    W25Q256_Disable();
 
    /* Wait the end of Flash writing */
    while(BSP_W25Q256_GetStatus() != W25Q256_BUSY)
    {
        /* Check for the Timeout */
        if((HAL_GetTick() - tickstart) > W25Q256FV_BULK_ERASE_MAX_TIME)
        {
            return W25Q256_TIMEOUT;
        }
    }
    return W25Q256_OK;
}
 
 
 
/********************************End of File************************************/
/**
  ******************************************************************************
  * @file    spi.c
  * @brief   This file provides code for the configuration
  *          of the SPI instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "spi.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

SPI_HandleTypeDef hspi2;
SPI_HandleTypeDef hspi_w25;

/* SPI2 init function */
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();
  }

  hspi_w25 = hspi2;
}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspInit 0 */

  /* USER CODE END SPI2_MspInit 0 */
    /* SPI2 clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI2 GPIO Configuration
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_13;
    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_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
    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_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI2_MspInit 1 */

  /* USER CODE END SPI2_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{

  if(spiHandle->Instance==SPI2)
  {
  /* USER CODE BEGIN SPI2_MspDeInit 0 */

  /* USER CODE END SPI2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI2_CLK_DISABLE();

    /**SPI2 GPIO Configuration
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);

  /* USER CODE BEGIN SPI2_MspDeInit 1 */

  /* USER CODE END SPI2_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值