STM32H750VB 外部程序QSPI模式,不成功。
本帖最后由 673835452 于 2021-12-16 10:33 编辑STM32H750VB
硬件:使用W25Q128JV和W25Q64JV都试过了, 原理图和PCB图如下图所示,PCB做了等长处理
软件:目前烧录算法可以使用,并且开启校验模式。可以查到尝试ID,可以写读数据。
问题:STM32H750VB 内部128K存boot 外部qspi flash存app程序 。
目前无法跳转app,程序参考硬汉、野火、原子的都不行。运行到跳转字段时的时候晶振就不起振了。
boot mian函数:
int main(void)
{
/* USER CODE BEGIN 1 */
MPU_Config();
CPU_CACHE_Enable();
/* 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();
//HAL_GPIO_WritePin(LOCK_GPIO_GPIO_Port,LOCK_GPIO_Pin,GPIO_PIN_SET);
MX_USART1_UART_Init();
// MX_SPI1_Init();
// MX_SPI2_Init();
/* USER CODE BEGIN 2 */
printf("boot ok\r\n");
clock_information();
//
MX_QUADSPI_Init();
W25QXX_Init();
printf("id:%X\r\n",W25QXX_MftrDeviceID());
QSPI_EnableMemoryMappedMode();
SCB_DisableICache();
SCB_DisableDCache();
JumpToApp();/* 跳转到应用程序 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
boot映射代码:测试映射应该也没问题
uint8_t QSPI_EnableMemoryMappedMode(void)
{
QSPI_CommandTypeDef cmd;
QSPI_MemoryMappedTypeDef mem;
// Configure the command for the read instruction
cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
cmd.Instruction = W25X_FastRead;
cmd.AddressMode = QSPI_ADDRESS_4_LINES;
cmd.AddressSize = QSPI_ADDRESS_24_BITS;
cmd.DataMode = QSPI_DATA_4_LINES;
cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
cmd.DummyCycles = 8;
cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
// Configure the memory mapped mode
mem.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
mem.TimeOutPeriod = 0;
if (HAL_QSPI_MemoryMapped(&hqspi, &cmd, &mem) != HAL_OK)
{
return 1;
}
return 0;
}
boot跳转程序:
void JumpToApp(void)
{
uint32_t i=0;
void (*AppJump)(void); /* 声明一个函数指针 */
__IO uint32_t AppAddr = 0x90000000;/* APP 地址 0x90000000*/
/* 关闭全局中断 */
DISABLE_INT();
/* 设置所有时钟到默认状态,使用HSI时钟 */
HAL_RCC_DeInit();
/* 关闭滴答定时器,复位到默认值 */
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL = 0;
/* 关闭所有中断,清除所有中断挂起标志 */
for (i = 0; i < 8; i++)
{
NVIC->ICER=0xFFFFFFFF;
NVIC->ICPR=0xFFFFFFFF;
}
/* 使能全局中断 */
ENABLE_INT();
/* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */
AppJump = (void (*)(void)) (*((uint32_t *) (AppAddr + 4)));
/* 设置主堆栈指针 */
__set_MSP(*(uint32_t *)AppAddr);
/* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */
__set_CONTROL(0);
/* 跳转到系统BootLoader */
AppJump();
/* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */
while (1)
{
}
}app mian函数:
int main(void)
{
/* USER CODE BEGIN 1 */
SCB->VTOR = QSPI_BASE;
// __enable_irq();
SCB_EnableICache();
SCB_EnableDCache();
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
MPU_Config( );
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();
HAL_GPIO_WritePin(LOCK_GPIO_GPIO_Port,LOCK_GPIO_Pin,GPIO_PIN_RESET);
// MX_QUADSPI_Init();
MX_USART1_UART_Init();
//MX_SPI1_Init();
//MX_SPI2_Init();
/* USER CODE BEGIN 2 */
printf("APP ok!\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
HAL_GPIO_WritePin(LOCK_GPIO_GPIO_Port,LOCK_GPIO_Pin,GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(LOCK_GPIO_GPIO_Port,LOCK_GPIO_Pin,GPIO_PIN_RESET);
HAL_Delay(100);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}APP MDK 设置:
。。。你自己在app里把时钟都复位了,还指望晶振不变? wye11083 发表于 2021-12-16 12:37
。。。你自己在app里把时钟都复位了,还指望晶振不变?
你好SystemClock_Config(); 这是时钟初始化,cubemx 生成的
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_SCALE0);
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 = 192;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 5;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
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_4) != HAL_OK)
{
Error_Handler();
}
} 673835452 发表于 2021-12-16 13:37
你好SystemClock_Config(); 这是时钟初始化,cubemx 生成的
app代码里面不要配时钟!闲着没事干了。app只执行用户算法代码。所有初始化都在bootloader里面做!
想想你的电脑,配置cpu /内存是在进入桌面之后你再手动配吗?这样的电脑你觉得有几个人能用起来?单片机一样的道理。 时钟只能在boot里配置 楼上两位不对,BootLoader和App可以分别配置时钟,这个不影响,而且这样可以多个项目使用同一BootLoader。现在关键是您跳转后,App是否有开始执行??并且,App的中断向量起始地址需要在App的程序里面设置(MDK没得设),App能进入,就再重新配置时钟等,反正App里您可以视为一个完全独立的单机程序,唯一不同只是起始地址和向量表地址不同而已。 中断向量表基址在System_stm32h7xx.c里的SystemInit函数内,SCB->VTOR = FLASH_BANK1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ 本帖最后由 saccapanna 于 2021-12-16 18:40 编辑
Boot 与 APP 解耦分离的思路是对的,两个程序各不相关。
但是要注意,你在 Boot 中,初始化时钟,然后 QSPI 的时钟使用的那一路?
不要在 APP 启动时,再把 QSPI 的时钟关闭了吧,QSPI的驱动和映射不能复位吧?不然相当于读取 QSPI 失效了,当然无法运行。 也就是说,你可以重新初始化时钟,可以做一切硬件的初始化,但是无论做什么,你必须要确保 QSPI 工作正常,并且映射正常。除非,你把 FLASH 数据全部加载到 RAM 中运行,反正 STM32H750 SRAM 足够大。 QSPI FLASH 数据全部加载到 RAM 有没有人成功过?不知道抗干扰怎么样? 没有做分散文件吧? saccapanna 发表于 2021-12-16 18:39
Boot 与 APP 解耦分离的思路是对的,两个程序各不相关。
但是要注意,你在 Boot 中,初始化时钟,然后 QSPI ...
APP启动没有把QSPI时钟复位,
BOOT复位时钟注释掉也不行。 ackyee 发表于 2021-12-17 10:05
没有做分散文件吧?
bootapp 模式应该不需要做分散文件吧,参考别人的都没有做
boot我只做自升级,所有配置都在APP,比如手机下载完成后自动安装,boot只负责安装或者固件初始化啥的,一般都是向量地址错了所以跑不起来 QSPI时钟要用HCLK3的,不能用PLL之后的。另外,QSPI FLASH里的程序 ,不要再次初始化QSPI了 radar_12345 发表于 2021-12-16 22:45
QSPI FLASH 数据全部加载到 RAM 有没有人成功过?不知道抗干扰怎么样?
理论是应该是完全没问题的,我目前128KB,没用外部FLASH,升级部分就是运行在RAM中的。
不过完全加载到 SRAM 运行没有试验过,稳定性不知道。
加载完毕后,配置 MMU,把RAM的一段空间,设置为只读,应该问题不大。
页:
[1]