|
求助:
我自己制作了一个W25Q28,QSPI接口的MDK下载算法。但是使用的时候出现下面的错误。
No Algorithm found for: 08000000H - 08005BAFH
Erase skipped!
Error: Flash Download failed - "Cortex-M7"
Flash Load finished at 10:32:07
这是怎么回事呢。 我已经验证过我的W25Q128芯片的驱动,能正常的读,写,映射。
具体代码如下
/**************************************************************************//**
* @file FlashPrg.c
* @brief Flash Programming Functions adapted for New Device Flash
* @version V1.0.0
* @date 10. January 2018
******************************************************************************/
/*
* Copyright (c) 2010-2018 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "FlashOS.h" // FlashOS Structures
#include "bsp_gpio.h"
#include "w25qxxx_qspi.h"
#include "bsp_system.h"
#include "bsp_rcc.h"
#include "bsp_power.h"
#include "system_config.h"
/*
必需的闪存编程函数(由FlashOS调用):
int Init (unsigned long adr, // 初始化闪存,参数adr为闪存起始地址
unsigned long clk, // 时钟信号相关参数(具体取决于硬件,可能是时钟频率等)
unsigned long fnc); // 功能相关参数(具体含义依实际情况而定)
int UnInit (unsigned long fnc); // 反初始化闪存,参数fnc用于指定相关功能
int EraseSector (unsigned long adr); // 擦除扇区函数,参数adr为要擦除扇区的起始地址
int ProgramPage (unsigned long adr, // 编程页函数,参数adr为要编程页的起始地址
unsigned long sz, // 编程数据的大小(以字节等为单位,依实际而定)
unsigned char *buf); // 指向要写入闪存数据缓冲区的指针
可选的闪存编程函数(由FlashOS调用):
int BlankCheck (unsigned long adr, // 空白检查,参数adr为要检查区域的起始地址
unsigned long sz, // 要检查区域的大小(字节等单位)
unsigned char pat); // 空白检查时对比的模式(比如全0xFF等,依闪存特性而定)
int EraseChip (void); // 擦除整个设备(闪存芯片)
unsigned long Verify (unsigned long adr, // 验证函数,参数adr为要验证区域的起始地址
unsigned long sz, // 要验证区域的大小
unsigned char *buf); // 指向用于验证对比数据缓冲区的指针
- 如果闪存空间未映射到CPU内存空间,那么空白检查(BlankCheck)函数就是必需的。
- 如果闪存空间未映射到CPU内存空间,那么验证(Verify)函数就是必需的。
- 如果未提供擦除整个芯片(EraseChip)函数,那么将会调用针对所有扇区的擦除扇区(EraseSector)函数。
*/
//初始化系统
void bsp_system_init(void)
{
System_ClockSource sys_config;
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PLLInitTypeDef PLL_Config;
//
NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
//1.初始化电源
bsp_pwr_ex_config_supply(PWR_LDO_SUPPLY);
bsp_pwr_set_stop_mode_regul_voltage_scaling(PWR_REGULATOR_VOLTAGE_SCALE1);
bsp_pwr_voltage_scaling_config(PWR_REGULATOR_VOLTAGE_SCALE1);
while(!bsp_pwr_is_active_flag_VOS());
//2.初始化时钟
bsp_rcc_APB4_GRP1_enable_clock(APB4_GRP1_PERIPH_SYSCFG);
bsp_pwr_voltage_scaling_config(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!bsp_pwr_is_active_flag_VOS());
sys_config.source = SYSTEM_SOURCE_PLL;
sys_config.PLL.PLLSource = PLL_CLOCK_SOURCE;
sys_config.PLL.PLLFRACN = 0;
sys_config.PLL.PLLM = PLL1_M;
sys_config.PLL.PLLN = PLL1_N;
sys_config.PLL.PLLP = PLL1_P;
sys_config.PLL.PLLQ = PLL1_Q;
sys_config.PLL.PLLR = PLL1_R;
bsp_rcc_system_clock_init(&sys_config);
PLL_Config.PLLM = PLL2_M;
PLL_Config.PLLN = PLL2_N;
PLL_Config.PLLP = PLL2_P;
PLL_Config.PLLQ = PLL2_Q;
PLL_Config.PLLR = PLL2_R;
PLL_Config.PLLFRACN = 0;
PLL_Config.PLLSource = PLL_CLOCK_SOURCE;
bsp_rcc_PLL2_config(&PLL_Config);
PLL_Config.PLLM = PLL3_M;
PLL_Config.PLLN = PLL3_N;
PLL_Config.PLLP = PLL3_P;
PLL_Config.PLLQ = PLL3_Q;
PLL_Config.PLLR = PLL3_R;
PLL_Config.PLLFRACN = 0;
PLL_Config.PLLSource = PLL_CLOCK_SOURCE;
bsp_rcc_PLL3_config(&PLL_Config);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 |
RCC_CLOCKTYPE_PCLK2 |
RCC_CLOCKTYPE_D3PCLK1 |
RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = SYSTEM_SOURCE_PLL;
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;
bsp_rcc_clock_init(&RCC_ClkInitStruct);
SCB_EnableICache(); /* 使能 I-Cache */
SCB_EnableDCache(); /* 使能 D-Cache */
}
void w25q128_init(void)
{
QSPI_Pin_Config pins = {0};
pins.CLK_pin = QSPI_CLK_PIN;
pins.CLK_port = QSPI_CLK_PORT;
pins.IO0_pin = QSPI_SD0_PIN;
pins.IO0_port = QSPI_SD0_PORT;
pins.IO1_pin = QSPI_SD1_PIN;
pins.IO1_port = QSPI_SD1_PORT;
pins.IO2_pin = QSPI_SD2_PIN;
pins.IO2_port = QSPI_SD2_PORT;
pins.IO3_pin = QSPI_SD3_PIN;
pins.IO3_port = QSPI_SD3_PORT;
pins.NCS_pin = QSPI_CS_PIN;
pins.NCS_port = QSPI_CS_PORT;
w25qxxx_qspi_init(&pins, 0);
}
/*
* Initialize Flash Programming Functions
* Parameter: adr: Device Base Address
* clk: Clock Frequency (Hz)
* fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
* Return Value: 0 - OK, 1 - Failed
*/
int Init (unsigned long adr, unsigned long clk, unsigned long fnc)
{
bsp_system_init();
w25q128_init();
return (0); // Finished without Errors
}
/*
* De-Initialize Flash Programming Functions
* Parameter: fnc: Function Code (1 - Erase, 2 - Program, 3 - Verify)
* Return Value: 0 - OK, 1 - Failed
*/
int UnInit (unsigned long fnc) {
/* Add your Code */
return (0); // Finished without Errors
}
/*
* Erase complete Flash Memory
* Return Value: 0 - OK, 1 - Failed
*/
int EraseChip (void) {
/* Add your Code */
w25q128_eraser_chip();
return (0); // Finished without Errors
}
/*
* Erase Sector in Flash Memory
* Parameter: adr: Sector Address
* Return Value: 0 - OK, 1 - Failed
*/
int EraseSector (unsigned long adr) {
/* Add your Code */
unsigned int addr = adr - 0x90000000;
if(addr < 16 * 1024 * 1024 && addr > 0)
w25q128_qspi_erase_block_64K(addr);
else
return 1;
return (0); // Finished without Errors
}
/*
* Program Page in Flash Memory
* Parameter: adr: Page Start Address
* sz: Page Size
* buf: Page Data
* Return Value: 0 - OK, 1 - Failed
*/
int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {
/* Add your Code */
unsigned int addr = adr - 0x90000000;
if(addr < 16 * 1024 * 1024 && addr > 0)
w25q128_qspi_write_buffer(buf,addr,sz);
else
return 1;
return (0); // Finished without Errors
}
int BlankCheck (unsigned long adr, // 空白检查,参数adr为要检查区域的起始地址
unsigned long sz, // 要检查区域的大小(字节等单位)
unsigned char pat) // 空白检查时对比的模式(比如全0xFF等,依闪存特性而定)
{
unsigned int *addr = (unsigned int *)(adr - 0x90000000);
w25q128_qspi_memory_mapped();
for(int i = 0; i < sz/4; i++)
{
if(*addr != 0xffffffff)
return 1;
addr++;
}
return 0;
}
unsigned long Verify (unsigned long adr, // 验证函数,参数adr为要验证区域的起始地址
unsigned long sz, // 要验证区域的大小
unsigned char *buf) // 指向用于验证对比数据缓冲区的指针
{
unsigned char *addr = (unsigned char *)(adr - 0x90000000);
w25q128_qspi_memory_mapped();
for(int i = 0; i < sz; i++)
{
if(*addr != buf)
return 1;
addr++;
}
return 0;
}
|
|