stm32+w25q256

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "quadspi.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "string.h"
#include <stdio.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
  */
int main(void)
{

  /* USER CODE BEGIN 1 */
	uint32_t address = 0;
	uint8_t data_to_write[4];
	uint32_t flashsize;
	uint32_t counter = 1;
	// 初始化写入数据
	for (uint16_t i = 0; i < 4; i++) {
		data_to_write[i] = i % 256;  // 用示例数据初始化数组
	}
  /* 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_QUADSPI_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	norflash_init();
	flashsize = 32 * 1024 * 1024;
	const uint32_t sector_size = 4096;
	while (address < flashsize)
	{
		// 将计数器的值写入数据数组
		data_to_write[0] = (counter >> 24) & 0xFF;
		data_to_write[1] = (counter >> 16) & 0xFF;
		data_to_write[2] = (counter >> 8) & 0xFF;
		data_to_write[3] = counter & 0xFF;

		// 写入数据到当前地址
		norflash_write(data_to_write, address, 4);

		// 读取数据进行验证(可选)
		uint8_t rectemp[4];
		norflash_read(rectemp, address, 4);

		// 打印数据,调试用
		print("Address: %lu, Data: %u\r\n", address, (rectemp[0] << 24) | (rectemp[1] << 16) | (rectemp[2] << 8) | rectemp[3]);

		// 更新地址和计数器
		address += sector_size;
		counter++;

		HAL_Delay(10);  // 根据实际需要调整延迟
	}

	print("Flash write complete.\r\n");

  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

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

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 5;
  RCC_OscInitStruct.PLL.PLLN = 160;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  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_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != 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 */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    quadspi.c
  * @brief   This file provides code for the configuration
  *          of the QUADSPI instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "quadspi.h"

/* USER CODE BEGIN 0 */
#include "string.h"
#include "usart.h"
/* USER CODE END 0 */

QSPI_HandleTypeDef hqspi;

/* QUADSPI init function */
void MX_QUADSPI_Init(void)
{

  /* USER CODE BEGIN QUADSPI_Init 0 */

  /* USER CODE END QUADSPI_Init 0 */

  /* USER CODE BEGIN QUADSPI_Init 1 */

  /* USER CODE END QUADSPI_Init 1 */
  hqspi.Instance = QUADSPI;
  hqspi.Init.ClockPrescaler = 1;
  hqspi.Init.FifoThreshold = 4;
  hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
  hqspi.Init.FlashSize = 24;
  hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_3_CYCLE;
  hqspi.Init.ClockMode = QSPI_CLOCK_MODE_3;
  hqspi.Init.FlashID = QSPI_FLASH_ID_1;
  hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
  if (HAL_QSPI_Init(&hqspi) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN QUADSPI_Init 2 */
  hqspi.Init.FlashSize = POSITION_VAL(0X2000000) - 1;
  if (HAL_QSPI_Init(&hqspi) != HAL_OK)
    {
      Error_Handler();
    }
  /* USER CODE END QUADSPI_Init 2 */

}

void HAL_QSPI_MspInit(QSPI_HandleTypeDef* qspiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  if(qspiHandle->Instance==QUADSPI)
  {
  /* USER CODE BEGIN QUADSPI_MspInit 0 */

  /* USER CODE END QUADSPI_MspInit 0 */

  /** Initializes the peripherals clock
  */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_QSPI;
    PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_D1HCLK;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
      Error_Handler();
    }

    /* QUADSPI clock enable */
    __HAL_RCC_QSPI_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOF_CLK_ENABLE();
    /**QUADSPI GPIO Configuration
    PB6     ------> QUADSPI_BK1_NCS
    PF6     ------> QUADSPI_BK1_IO3
    PF7     ------> QUADSPI_BK1_IO2
    PF8     ------> QUADSPI_BK1_IO0
    PF9     ------> QUADSPI_BK1_IO1
    PB2     ------> QUADSPI_CLK
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN QUADSPI_MspInit 1 */
  /* USER CODE END QUADSPI_MspInit 1 */
  }
}

void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef* qspiHandle)
{

  if(qspiHandle->Instance==QUADSPI)
  {
  /* USER CODE BEGIN QUADSPI_MspDeInit 0 */

  /* USER CODE END QUADSPI_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_QSPI_CLK_DISABLE();

    /**QUADSPI GPIO Configuration
    PB6     ------> QUADSPI_BK1_NCS
    PF6     ------> QUADSPI_BK1_IO3
    PF7     ------> QUADSPI_BK1_IO2
    PF8     ------> QUADSPI_BK1_IO0
    PF9     ------> QUADSPI_BK1_IO1
    PB2     ------> QUADSPI_CLK
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_2);

    HAL_GPIO_DeInit(GPIOF, GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9);

  /* USER CODE BEGIN QUADSPI_MspDeInit 1 */

  /* USER CODE END QUADSPI_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

uint8_t qspi_transmit(uint8_t *buf, uint32_t datalen)
{
    hqspi.Instance->DLR = datalen - 1;  /* 配置数据长度 */
    if (HAL_QSPI_Transmit(&hqspi, buf, 5000) == HAL_OK)
    {
        return HAL_OK;
    }
    else
    {
        return HAL_ERROR;
    }
}

uint8_t qspi_receive(uint8_t *buf, uint32_t datalen)
{
    hqspi.Instance->DLR = datalen - 1;   /* 配置数据长度 */
    if (HAL_QSPI_Receive(&hqspi, buf, 5000) == HAL_OK)
    {
        return HAL_OK;
    }
    else
    {
        return HAL_ERROR;
    }
}

uint8_t qspi_wait_flag(uint32_t flag, uint8_t sta, uint32_t wtime)
{
    uint8_t flagsta = 0;

    while (wtime)
    {
        flagsta = (QUADSPI->SR & flag) ? 1 : 0; /* 获取状�?�标�??? */

        if (flagsta == sta)
        {
            break;
        }

        wtime--;
    }

    if (wtime)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

/**
 * @brief       QSPI发�?�命�???
 * @param       cmd : 要发送的指令
 * @param       addr: 发�?�到的目的地�???
 * @param       mode: 模式,详细位定义如�???:
 *   @arg       mode[1:0]: 指令模式; 00,无指�???;  01,单线传输指令; 10,双线传输指令; 11,四线传输指令.
 *   @arg       mode[3:2]: 地址模式; 00,无地�???;  01,单线传输地址; 10,双线传输地址; 11,四线传输地址.
 *   @arg       mode[5:4]: 地址长度; 00,8位地�???; 01,16位地�???;     10,24位地�???;     11,32位地�???.
 *   @arg       mode[7:6]: 数据模式; 00,无数�???;  01,单线传输数据; 10,双线传输数据; 11,四线传输数据.
 * @param       dmcycle: 空指令周期数
 * @retval      �???
 */
void qspi_send_cmd(uint8_t cmd, uint32_t addr, uint8_t mode, uint8_t dmcycle)
{
    QSPI_CommandTypeDef qspi_command_handle;

    qspi_command_handle.Instruction = cmd;                              /* 指令 */
    qspi_command_handle.Address = addr;                                 /* 地址 */
    qspi_command_handle.DummyCycles = dmcycle;                          /* 设置空指令周期数 */

    if(((mode >> 0) & 0x03) == 0)
    qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_NONE;        /* 指令模式 */
    else if(((mode >> 0) & 0x03) == 1)
    qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_1_LINE;      /* 指令模式 */
    else if(((mode >> 0) & 0x03) == 2)
    qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_2_LINES;     /* 指令模式 */
    else if(((mode >> 0) & 0x03) == 3)
    qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_4_LINES;     /* 指令模式 */

    if(((mode >> 2) & 0x03) == 0)
    qspi_command_handle.AddressMode = QSPI_ADDRESS_NONE;                /* 地址模式 */
    else if(((mode >> 2) & 0x03) == 1)
    qspi_command_handle.AddressMode = QSPI_ADDRESS_1_LINE;              /* 地址模式 */
    else if(((mode >> 2) & 0x03) == 2)
    qspi_command_handle.AddressMode = QSPI_ADDRESS_2_LINES;             /* 地址模式 */
    else if(((mode >> 2) & 0x03) == 3)
    qspi_command_handle.AddressMode = QSPI_ADDRESS_4_LINES;             /* 地址模式 */

    if(((mode >> 4)&0x03) == 0)
    qspi_command_handle.AddressSize = QSPI_ADDRESS_8_BITS;              /* 地址长度 */
    else if(((mode >> 4) & 0x03) == 1)
    qspi_command_handle.AddressSize = QSPI_ADDRESS_16_BITS;             /* 地址长度 */
    else if(((mode >> 4) & 0x03) == 2)
    qspi_command_handle.AddressSize = QSPI_ADDRESS_24_BITS;             /* 地址长度 */
    else if(((mode >> 4) & 0x03) == 3)
    qspi_command_handle.AddressSize = QSPI_ADDRESS_32_BITS;             /* 地址长度 */

    if(((mode >> 6) & 0x03) == 0)
    qspi_command_handle.DataMode=QSPI_DATA_NONE;                        /* 数据模式 */
    else if(((mode >> 6) & 0x03) == 1)
    qspi_command_handle.DataMode = QSPI_DATA_1_LINE;                    /* 数据模式 */
    else if(((mode >> 6) & 0x03) == 2)
    qspi_command_handle.DataMode = QSPI_DATA_2_LINES;                   /* 数据模式 */
    else if(((mode >> 6) & 0x03) == 3)
    qspi_command_handle.DataMode = QSPI_DATA_4_LINES;                   /* 数据模式 */

    qspi_command_handle.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次都发送指�??? */
    qspi_command_handle.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;  /* 无交替字�??? */
    qspi_command_handle.DdrMode = QSPI_DDR_MODE_DISABLE;                /* 关闭DDR模式 */
    qspi_command_handle.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

    HAL_QSPI_Command(&hqspi, &qspi_command_handle, 5000);
}

uint16_t g_norflash_type = BY25Q256;      /* 默认是BY25Q256 */
uint8_t g_norflash_mode = 0;              /* QSPI模式标志�???0,SPI模式�???1,QPI模式 */

/**
 * @brief       初始化SPI NOR FLASH
 * @param       �???
 * @retval      �???
 */
void norflash_init(void)
{
    uint8_t temp;
    MX_QUADSPI_Init();
    norflash_qspi_disable();             /* �???出QPI模式(避免芯片之前进入这个模式,导致下载失败) */
    norflash_qe_enable();                /* 使能QSPI模式 */
    g_norflash_type = norflash_read_id();/* 读取FLASH ID */
    print("FLASH ID :%d\n", norflash_read_id());
    if (g_norflash_type == W25Q256)
        {
            temp = norflash_read_sr(3);      /* 读取状�?�寄存器3,判断地�??模式 */

            if ((temp & 0X01) == 0)          /* 如果不是4字节地址模式,则进�??4字节地址模式 */
            {
                norflash_write_enable();     /* 写使�?? */

                /* QPI,使能4字节地址指令,地址�??0,无数据_8位地�??_无地�??_4线传输指�??,无空周期,0个字节数�?? */
                qspi_send_cmd(FLASH_Enable4ByteAddr, 0, (0 << 6) | (0 << 4) | (0 << 2) | (3 << 0), 0);
            }

            norflash_write_enable();         /* 写使�?? */

            /* QPI,设置读参数指�??,地址�??0,4线传数据_8位地�??_无地�??_4线传输指�??,无空周期,1个字节数�?? */
            qspi_send_cmd(FLASH_SetReadParam, 0, (3 << 6) | (0 << 4) | (0 << 2) | (3 << 0), 0);
            temp = 3 << 4;                   /* 设置P4&P5=11,8个dummy clocks,104M */
            qspi_transmit(&temp, 1);         /* 发�??1个字�?? */
        }
}


/**
 * @brief       读取SPI FLASH,仅支持QSPI模式
 * @note        在指定地�???�???始读取指定长度的数据
 * @param       pbuf    : 数据存储�???
 * @param       addr    : �???始读取的地址(�???�???32bit)
 * @param       datalen : 要读取的字节�???(�???�???65535)
 * @retval      �???
 */
void norflash_read(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
    /* QPI,快�?�读数据,地址为ReadAddr,4线传输数据_32位地�???_4线传输地�???_4线传输指�???,8空周�???,NumByteToRead个数�??? */
    qspi_send_cmd(FLASH_FastReadData, addr, (3 << 6) | (3 << 4) | (3 << 2) | (3 << 0), 8);
    qspi_receive(pbuf, datalen);
}

/**
 * @brief       SPI在一�???(0~65535)内写入少�???256个字节的数据
 * @note        在指定地�???�???始写入最�???256字节的数�???
 * @param       pbuf    : 数据存储�???
 * @param       addr    : �???始写入的地址(�???�???32bit)
 * @param       datalen : 要写入的字节�???(�???�???256),该数不应该超过该页的剩余字节�???!!!
 * @retval      �???
 */
static void norflash_write_page(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
    norflash_write_enable();                    /* 写使�??? */
    /* QPI,页写指令,地址为WriteAddr,4线传输数据_32位地�???_4线传输地�???_4线传输指�???,无空周期,NumByteToWrite个数�??? */
    qspi_send_cmd(FLASH_PageProgram, addr, (3 << 6) | (3 << 4) | (3 << 2) | (3 << 0), 0);
    qspi_transmit(pbuf, datalen);
    norflash_wait_busy();                       /* 等待写入结束 */
}

/**
 * @brief       无检验写SPI FLASH
 * @note        必须确保�???写的地址范围内的数据全部�???0XFF,否则在非0XFF处写入的数据将失�???!
 *              具有自动换页功能
 *              在指定地�???�???始写入指定长度的数据,但是要确保地�???不越�???!
 *
 * @param       pbuf    : 数据存储�???
 * @param       addr    : �???始写入的地址(�???�???32bit)
 * @param       datalen : 要写入的字节�???(�???�???65535)
 * @retval      �???
 */
static void norflash_write_nocheck(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
    uint16_t pageremain;
    pageremain = 256 - addr % 256;              /* 单页剩余的字节数 */

    if (datalen <= pageremain)
    {
        pageremain = datalen;                   /* 不大�???256个字�??? */
    }

    while (1)
    {
        norflash_write_page(pbuf, addr, pageremain);

        if (datalen == pageremain)
        {
            break;                              /* 写入结束�??? */
        }
        else
        {
            pbuf += pageremain;
            addr += pageremain;

            datalen -= pageremain;              /* 减去已经写入了的字节�??? */

            if (datalen > 256)
            {
                pageremain = 256;               /* �???次可以写�???256个字�??? */
            }
            else
            {
                pageremain = datalen;           /* 不够256个字节了 */
            }
        }
    }
}

/**
 * @brief       写SPI FLASH
 * @note        在指定地�???�???始写入指定长度的数据 , 该函数带擦除操作!
 *              SPI FLASH �???般是: 256个字节为�???个Page, 4Kbytes为一个Sector, 16个扇区为1个Block
 *              擦除的最小单位为Sector.
 *
 * @param       pbuf    : 数据存储�???
 * @param       addr    : �???始写入的地址(�???�???32bit)
 * @param       datalen : 要写入的字节�???(�???�???65535)
 * @retval      �???
 */
uint8_t g_norflash_buf[4096];

void norflash_write(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;
    uint16_t i;
    uint8_t *norflash_buf;
    norflash_buf = g_norflash_buf;
    secpos = addr / 4096;                                       /* 扇区地址 */
    secoff = addr % 4096;                                       /* 在扇区内的偏�??? */
    secremain = 4096 - secoff;                                  /* 扇区剩余空间大小 */

    //printf("ad:%X,nb:%X\r\n",addr, datalen);                  /* 测试�??? */
    if (datalen <= secremain)secremain = datalen;               /* 不大�???4096个字�??? */

    while (1)
    {
        norflash_read(norflash_buf, secpos * 4096, 4096);       /* 读出整个扇区的内�??? */

        for (i = 0; i < secremain; i++)                         /* 校验数据 */
        {
           if (norflash_buf[secoff + i] != 0XFF)
           {
               break;          /* �???要擦�??? */
           }

        }

        if (i < secremain)                                      /* �???要擦�??? */
        {
            norflash_erase_sector(secpos);                      /* 擦除这个扇区 */

            for (i = 0; i < secremain; i++)                     /* 复制 */
            {
                norflash_buf[i + secoff] = pbuf[i];
            }

            norflash_write_nocheck(norflash_buf, secpos * 4096, 4096);  /* 写入整个扇区 */

        }
        else
        {
            norflash_write_nocheck(pbuf, addr, secremain);      /* 写已经擦除了�???,直接写入扇区剩余区间. */
        }

        if (datalen == secremain)
        {
            break;                      /* 写入结束�??? */
        }
        else                            /* 写入未结�??? */
        {
            secpos++;                   /* 扇区地址�???1 */
            secoff = 0;                 /* 偏移位置�???0 */

            pbuf += secremain;          /* 指针偏移 */
            addr += secremain;          /* 写地�???偏移 */
            datalen -= secremain;       /* 字节数�?�减 */

            if (datalen > 4096)
            {
                secremain = 4096;       /* 下一个扇区还是写不完 */
            }
            else
            {
                secremain = datalen;    /* 下一个扇区可以写完了 */
            }
        }
    }
}

/**
 * @brief       擦除整个芯片
 * @note        等待时间超长...
 * @param       �???
 * @retval      �???
 */
void norflash_erase_chip(void)
{
    norflash_write_enable();                    /* SET WEL */
    norflash_wait_busy();
    /* QPI,写全片擦除指�???,地址�???0,无数据_8位地�???_无地�???_4线传输指�???,无空周期,0个字节数�??? */
    qspi_send_cmd(FLASH_ChipErase, 0, (0 << 6) | (0 << 4) | (0 << 2) | (3 << 0), 0);
    norflash_wait_busy();                       /* 等待芯片擦除结束 */
}

/**
 * @brief       擦除�???个扇�???
 * @note        注意,这里是扇区地�???,不是字节地址!!
 *              擦除�???个扇区的�???少时�???:150ms
 *
 * @param       saddr : 扇区地址 根据实际容量设置
 * @retval      �???
 */
void norflash_erase_sector(uint32_t saddr)
{

    //printf("fe:%x\r\n",Dst_Addr);           /* 监视falsh擦除情况,测试�??? */
    saddr *= 4096;
    norflash_write_enable();                  /* SET WEL */
    norflash_wait_busy();
    /* QPI,写扇区擦除指�???,地址�???0,无数据_32位地�???_4线传输地�???_4线传输指�???,无空周期,0个字节数�??? */
    qspi_send_cmd(FLASH_SectorErase, saddr, (0 << 6) | (3 << 4) | (3 << 2) | (3 << 0), 0);
    norflash_wait_busy();                     /* 等待擦除完成 */
}

/**
 * @brief       等待空闲
 * @param       �???
 * @retval      �???
 */
void norflash_wait_busy(void)
{
    while ((norflash_read_sr(1) & 0x01) == 0x01);   /* 等待BUSY位清�??? */
}


void norflash_qspi_disable(void)
{
  QSPI_CommandTypeDef qspi_command_handle = {0};

  qspi_command_handle.Instruction = 0x35; // 读取状�?�寄存器2命令
  qspi_command_handle.Address = 0;
  qspi_command_handle.DummyCycles = 0;
  qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_1_LINE;
  qspi_command_handle.AddressMode = QSPI_ADDRESS_NONE;
  qspi_command_handle.AddressSize = QSPI_ADDRESS_8_BITS;
  qspi_command_handle.DataMode = QSPI_DATA_4_LINES;
  qspi_command_handle.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次都发送指�????? */
  qspi_command_handle.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  qspi_command_handle.DdrMode = QSPI_DDR_MODE_DISABLE;                /* 关闭DDR模式 */
  qspi_command_handle.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;


  if (HAL_QSPI_Command(&hqspi, &qspi_command_handle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
}

uint8_t norflash_read_sr(uint8_t regno)
{
    QSPI_CommandTypeDef qspi_command_handle;
    uint8_t byte = 0, command = 0;

    switch (regno)
    {
        case 1:
            command = FLASH_ReadStatusReg1;  /* 读状态寄存器1指令 */
            break;

        case 2:
            command = FLASH_ReadStatusReg2;  /* 读状态寄存器2指令 */
            break;

        case 3:
            command = FLASH_ReadStatusReg3;  /* 读状态寄存器3指令 */
            break;

        default:
            command = FLASH_ReadStatusReg1;
            break;
    }
    /* QPI MODE */
    // 读取状�?�寄存器2
    qspi_command_handle.Instruction = command; // 读取状�?�寄存器2命令
    qspi_command_handle.Address = 0;
    qspi_command_handle.DummyCycles = 0;
    qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_4_LINES;
    qspi_command_handle.AddressMode = QSPI_ADDRESS_NONE;
    qspi_command_handle.AddressSize = QSPI_ADDRESS_8_BITS;
    qspi_command_handle.DataMode = QSPI_DATA_4_LINES;
    qspi_command_handle.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次都发送指�????? */
    qspi_command_handle.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    qspi_command_handle.DdrMode = QSPI_DDR_MODE_DISABLE;                /* 关闭DDR模式 */
    qspi_command_handle.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

    if (HAL_QSPI_Command(&hqspi, &qspi_command_handle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
      Error_Handler();
    }

    qspi_receive(&byte, 1);
    return byte;
}

/**
 * @brief       25QXX写使�?????
 * @note        将S1寄存器的WEL置位
 * @param       �?????
 * @retval      �?????
 */
void norflash_write_enable(void)
{
	QSPI_CommandTypeDef qspi_command_handle;

	qspi_command_handle.Instruction = FLASH_WriteEnable;            // 指令
	qspi_command_handle.Address = 0;                   // 地址
	qspi_command_handle.DummyCycles = 0;               // 空指令周期数
	qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_4_LINES; // 四线传输指令模式
	qspi_command_handle.AddressMode = QSPI_ADDRESS_NONE;             // 无地�?????模式
	qspi_command_handle.AddressSize = QSPI_ADDRESS_8_BITS;           // 8位地�?????长度
	qspi_command_handle.DataMode = QSPI_DATA_NONE;                   // 无数据模�?????
	qspi_command_handle.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;         // 每次都发送指�?????
	qspi_command_handle.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; // 无交替字�?????
	qspi_command_handle.DdrMode = QSPI_DDR_MODE_DISABLE;             // 关闭DDR模式
	qspi_command_handle.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; // 关闭DDR模式
	HAL_QSPI_Command(&hqspi, &qspi_command_handle, 5000);
}

void norflash_write_sr(uint8_t regno, uint8_t sr)
{
	QSPI_CommandTypeDef qspi_command_handle;
    uint8_t command = 0;

    switch (regno)
    {
        case 1:
            command = FLASH_WriteStatusReg1;  /* 写状态寄存器1指令 */
            break;

        case 2:
            command = FLASH_WriteStatusReg2;  /* 写状态寄存器2指令 */
            break;

        case 3:
            command = FLASH_WriteStatusReg3;  /* 写状态寄存器3指令 */
            break;

        default:
            command = FLASH_WriteStatusReg1;
            break;
    }
    qspi_command_handle.Instruction = command; // 读取状�?�寄存器2命令
    qspi_command_handle.Address = 0;
    qspi_command_handle.DummyCycles = 0;
    qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_4_LINES;
    qspi_command_handle.AddressMode = QSPI_ADDRESS_NONE;
    qspi_command_handle.AddressSize = QSPI_ADDRESS_8_BITS;
    qspi_command_handle.DataMode = QSPI_DATA_4_LINES;
    qspi_command_handle.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次都发送指�????? */
    qspi_command_handle.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    qspi_command_handle.DdrMode = QSPI_DDR_MODE_DISABLE;                /* 关闭DDR模式 */
    qspi_command_handle.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

    if (HAL_QSPI_Command(&hqspi, &qspi_command_handle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
    {
    	Error_Handler();
    }

    qspi_transmit(&sr, 1);
}


void norflash_qe_enable(void)
{
  QSPI_CommandTypeDef qspi_command_handle = {0};
  uint8_t reg = norflash_read_sr(2);

  if ((reg & 0x02) == 0){
	  norflash_write_enable();
	  reg |= 1 << 1;
	  norflash_write_sr(2, reg);
  }

  qspi_command_handle.Instruction = FLASH_EnterQPIMode; // 读取状�?�寄存器2命令
  qspi_command_handle.Address = 0;
  qspi_command_handle.DummyCycles = 0;
      qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_1_LINE;
      qspi_command_handle.AddressMode = QSPI_ADDRESS_NONE;
      qspi_command_handle.AddressSize = QSPI_ADDRESS_8_BITS;
      qspi_command_handle.DataMode = QSPI_DATA_4_LINES;
      qspi_command_handle.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;            /* 每次都发送指�????? */
      qspi_command_handle.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
      qspi_command_handle.DdrMode = QSPI_DDR_MODE_DISABLE;                /* 关闭DDR模式 */
      qspi_command_handle.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;

  if (HAL_QSPI_Command(&hqspi, &qspi_command_handle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }
}

uint16_t norflash_read_id(void)
{
  QSPI_CommandTypeDef qspi_command_handle = {0};
  uint8_t temp[2];
  uint16_t deviceid;

  qspi_command_handle.Instruction = FLASH_ManufactDeviceID;            // 指令
  	qspi_command_handle.Address = 0;                   // 地址
  	qspi_command_handle.DummyCycles = 0;               // 空指令周期数
  	qspi_command_handle.InstructionMode = QSPI_INSTRUCTION_4_LINES; // 四线传输指令模式
  	qspi_command_handle.AddressMode = QSPI_ADDRESS_4_LINES;             // 24地址模式
  	qspi_command_handle.AddressSize = QSPI_ADDRESS_24_BITS;           // 8位地�?????长度
  	qspi_command_handle.DataMode = QSPI_DATA_4_LINES;                   // 4数据模式
  	qspi_command_handle.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;         // 每次都发送指�?????
  	qspi_command_handle.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; // 无交替字�?????
  	qspi_command_handle.DdrMode = QSPI_DDR_MODE_DISABLE;             // 关闭DDR模式
  	qspi_command_handle.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; // 关闭DDR模式

  if (HAL_QSPI_Command(&hqspi, &qspi_command_handle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    Error_Handler();
  }

  if (qspi_receive(temp, 2) != HAL_OK)
  {
    Error_Handler();
  }
  deviceid = (temp[0] << 8) | temp[1];
  return deviceid;
}
/* USER CODE END 1 */
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    quadspi.h
  * @brief   This file contains all the function prototypes for
  *          the quadspi.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __QUADSPI_H__
#define __QUADSPI_H__

#ifdef __cplusplus
extern "C" {
#endif

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

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

extern QSPI_HandleTypeDef hqspi;

/* USER CODE BEGIN Private defines */
#define W25Q80      0XEF13          /* W25Q80   芯片ID */
#define W25Q16      0XEF14          /* W25Q16   芯片ID */
#define W25Q32      0XEF15          /* W25Q32   芯片ID */
#define W25Q64      0XEF16          /* W25Q64   芯片ID */
#define W25Q128     0XEF17          /* W25Q128  芯片ID */
#define W25Q256     0XEF18          /* W25Q256  芯片ID */
#define BY25Q64     0X6816          /* BY25Q64  芯片ID */
#define BY25Q128    0X6817          /* BY25Q128 芯片ID */
#define BY25Q256    0X6818          /* BY25Q256 芯片ID */
#define NM25Q64     0X5216          /* NM25Q64  芯片ID */
#define NM25Q128    0X5217          /* NM25Q128 芯片ID */

extern uint16_t norflash_TYPE;      /* 定义FLASH芯片型号 */

/* 指令�?? */
#define FLASH_WriteEnable           0x06
#define FLASH_WriteDisable          0x04
#define FLASH_ReadStatusReg1        0x05
#define FLASH_ReadStatusReg2        0x35
#define FLASH_ReadStatusReg3        0x15
#define FLASH_WriteStatusReg1       0x01
#define FLASH_WriteStatusReg2       0x31
#define FLASH_WriteStatusReg3       0x11
#define FLASH_ReadData              0x03
#define FLASH_FastReadData          0x0B
#define FLASH_FastReadDual          0x3B
#define FLASH_FastReadQuad          0xEB
#define FLASH_PageProgram           0x02
#define FLASH_PageProgramQuad       0x32
#define FLASH_BlockErase            0xD8
#define FLASH_SectorErase           0x20
#define FLASH_ChipErase             0xC7
#define FLASH_PowerDown             0xB9
#define FLASH_ReleasePowerDown      0xAB
#define FLASH_DeviceID              0xAB
#define FLASH_ManufactDeviceID      0x90
#define FLASH_JedecDeviceID         0x9F
#define FLASH_Enable4ByteAddr       0xB7
#define FLASH_Exit4ByteAddr         0xE9
#define FLASH_SetReadParam          0xC0
#define FLASH_EnterQPIMode          0x38
#define FLASH_ExitQPIMode           0xFF
/* USER CODE END Private defines */

void MX_QUADSPI_Init(void);

/* USER CODE BEGIN Prototypes */
/* 静�?�函�?? */
static void norflash_wait_busy(void);                                               /* 等待空闲 */
static void norflash_qe_enable(void);                                               /* 使能QE�?? */
static void norflash_qspi_disable(void);                                            /* �??出QPI模式 */
static void norflash_write_page(uint8_t *pbuf, uint32_t addr, uint16_t datalen);    /* 写入page */
static void norflash_write_nocheck(uint8_t *pbuf, uint32_t addr, uint16_t datalen); /* 写flash,不带擦除 */

/* 普�?�函�?? */
void norflash_init(void);                                               /* 初始�??25QXX */
uint16_t norflash_read_id(void);                                        /* 读取FLASH ID */
void norflash_write_enable(void);                                       /* 写使�?? */
void norflash_write_disable(void);                                      /* 写保�?? */
uint8_t norflash_read_sr(uint8_t regno);                                /* 读取状�?�寄存器 */
void norflash_write_sr(uint8_t regno, uint8_t sr);                      /* 写状态寄存器 */

void norflash_erase_chip(void);                                         /* 整片擦除 */
void norflash_erase_sector(uint32_t saddr);                             /* 扇区擦除 */
void norflash_read(uint8_t *pbuf, uint32_t addr, uint16_t datalen);     /* 读取flash */
void norflash_write(uint8_t *pbuf, uint32_t addr, uint16_t datalen);    /* 写入flash */

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __QUADSPI_H__ */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要明确的是,STM32和W25Q64是完全不同的产品,它们分别是微控制器和闪存存储器。而FATFS是一个用于嵌入式系统的文件系统。因此,题目中的"STM32 W25Q64 FATFS速度慢"可能涉及到两个方面的问题,即STM32的操作速度与W25Q64芯片的读写速度,以及FATFS文件系统的读写性能。以下我将就这两个方面进行回答。 首先,STM32的速度问题可能与控制器的硬件和软件设计有关。可能是使用了低速的系统时钟频率或者是编写的代码存在效率上的问题。解决这个问题的方法是重新评估系统的时钟配置,以获得更高的处理速度,并且可以通过优化代码来提高程序的执行效率。 其次,W25Q64芯片的读写速度取决于其本身的性能和连接方式。要确保读写速度最大化,首先要确保正确选择了合适的SPI总线时钟,并进行合适的SPI通信设置。其次,在读写数据时需要考虑到W25Q64芯片的数据传输速率以及是否使用了缓存等功能。最后,检查硬件电路的设计与布线是否符合要求,并根据需要进行优化。 最后,FATFS文件系统的读写性能可能与文件系统的配置有关。在初始化FATFS时,需要选择合适的参数来优化文件系统的性能。例如,可以选择合适的簇大小和对齐方式,以减少磁盘片段和提高读写速度。此外,可以根据实际需求进行文件缓存的大小调整,以提高磁盘访问效率。 总结而言,如果STM32的速度慢、W25Q64芯片的读写速度慢或者FATFS的读写性能慢,需要综合考虑硬件和软件层面的因素,并根据具体问题进行适当的优化和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值