软件环境:STM32CubeMX5.3 、TouchGFX 4.10.0 Designer、uVision5.28.0.0
硬件环境:正点原子阿波罗STM32F767开发板、4.3寸LCD接口屏(480×272)、W25Q256
本博客源码链接:https://github.com/ningjw/stm32f7_os/tree/01683d112abdf378b2db0a7df6fa847afd277478
使用TouchGFX设计界面时,TouchGFX会将所有的图片资源转换成c数组形式,而图片资源占用的空间是特别大的,而STM32F767内部Flash有限,所以我们需要将图片资源放入QSPI FLASH中,接下来就教你解决这个问题。
1. 我们随便打开工程里的一个图片资源数组(Application/User/TouchGFX/generated 分类下),可以发现所有的图片资源都使用了LOCATION_EXTFLASH_ATTRIBUTE 进行修饰
2. 在Config.hpp文件中,可以发现LOCATION_EXTFLASH_ATTRIBUTE 的定义如下,增加该属性表示该数组会优先存放在名为“ExtFlashSection”的内存区域中:
#define LOCATION_EXTFLASH_ATTRIBUTE __attribute__ ((section ("ExtFlashSection"))) __attribute__ ((aligned(4)))
3. 默认是没有“ExtFlashSection”区域的,我们需要通过编写分散加载文件来配置“ExtFlashSection”段,首先通过下面的Edit按钮打开KEIL自己生成的sct文件,将该文件复制下来,并重命名为FLASH.sct
4. 在FLASH.sct文件中增加一个LR_EROM1加载域(命名可以随意),该加载域中定义了ExtFlashSection、FontFlashSection、TextFlashSection段,这样下载的时候图片资源就自动下载到该区域里面了,完整的代码如下:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x00200000 0x00100000 { ; load region size_region
ER_IROM1 0x00200000 0x00100000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_IRAM1 0x20000000 0x00080000 { ; RW data
.ANY (+RW +ZI)
}
}
LR_EROM1 0x90000000 0x02000000 { ; load region size_region
ER_EROM1 0x90000000 0x02000000 { ; load address = execution address
*.o (ExtFlashSection)
*.o (FontFlashSection)
*.o (TextFlashSection)
}
}
5. 通过以上配置后,在下载代码的时候,会出现“No Algorithm found for: 90000000H - 9000FFFFH”等等错误,这是因为你还没有为该段区域配置下载算法。
首先需要下载一个STM32F767_W25Q256.FLM文件(链接:https://download.csdn.net/download/ningjianwen/11643298),将该文件放入C:\Keil_v5\ARM\Flash目录,然后旧可以在以下界面添加该算法了,这里有以下几点需要注意:
6. 我们还需要在程序中将QSPI 配置为memory-mapped mode,这样我们才可以像访问内存一样访问QSPI FLASH空间。
关于QSPI的驱动可以参考博客:https://blog.csdn.net/Ningjianwen/article/details/96477565
我们需要做的是在编写好初始化W25Q256程序后,调用一个进入内存映射模式的函数,该函数如下:
/**
* @brief Configure the QSPI in memory-mapped mode
* @param None
* @retval QSPI memory status
*/
void W25QXX_MemoryMappedMode(void)
{
QSPI_CommandTypeDef s_command;
QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
/* Configure the command for the read instruction */
s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
s_command.Instruction = W25X_FastReadData;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = QSPI_ADDRESS_32_BITS;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DataMode = QSPI_DATA_4_LINES;
s_command.DummyCycles = 8;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Configure the memory mapped mode */
s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
s_mem_mapped_cfg.TimeOutPeriod = 0; //1;
if (HAL_QSPI_MemoryMapped(&hqspi, &s_command, &s_mem_mapped_cfg) != HAL_OK)
{
Error_Handler();
}
}