最近项目用到STM32F0驱动TFT显示,因存在字库及图片资源,有限的内部Flash肯定无法胜任这些资源,所以外挂了个GD25Q32芯片作为资源,设计板子时候没考虑到外部flash初始化数据的需求,这样开发过程频繁的修改flash数据就面临一大难题。
仔细分析认为只有几个方法:
1、飞线直接用外部的USB烧录器在线烧录,看似解决问题,但日后升级就很尴尬,不可能每个板子都飞线一次吧?
2、通过调试串口自定义协议,实现间接升级flash数据,看似合情合理,可还要面临开发个PC端APP实现协议对接,时间伤不起。
3、网上一搜,果然也有不少人碰到同样问题,之前没注意STLINK也支持在线烧录,不正是我需要的吗?大喜,分析看到官方提供了一些驱动例程都不是基于我的硬件,只好自己改,话不多说直接开工。
随便找个接近的例程,复制文件夹再重新命名为自己项目文件夹,此例用25Q32_STM32F072-EVAL,见下图:
替换用到的STD库文件,参考工程为STMF1系列,此处需要替换为STM32F0系列,包括源文件及头文件等,见下图:
然后进入工程,修改工程MCU为STM32F0系列,输出文件改成自己容易识别的。
下一步就是调整硬件对应的GPIO及代码移植了,注意,F1和F0系列的时钟有点不同,下面是重要修改部分,增加了AF功能开启,GPIO时钟也对应修改:
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
* @param None
* @retval None
*/
void sFLASH_LowLevel_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*!< sFLASH_SPI_CS_GPIO, sFLASH_SPI_MOSI_GPIO, sFLASH_SPI_MISO_GPIO
and sFLASH_SPI_SCK_GPIO Periph clock enable */
RCC_AHBPeriphClockCmd(sFLASH_CS_GPIO_CLK | sFLASH_SPI_MOSI_GPIO_CLK | sFLASH_SPI_MISO_GPIO_CLK |
sFLASH_SPI_SCK_GPIO_CLK, ENABLE);
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SYSCFG, ENABLE) ;
/*!< sFLASH_SPI Periph clock enable */
RCC_APB2PeriphClockCmd(sFLASH_SPI_CLK, ENABLE);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_0);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_0);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_0);
/*!< Configure sFLASH_SPI pins: SCK */
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_SCK_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_Init(sFLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH_SPI pins: MOSI */
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_MOSI_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(sFLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH_SPI pins: MISO */
GPIO_InitStructure.GPIO_Pin = sFLASH_SPI_MISO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(sFLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH_CS_PIN pin: sFLASH Card CS pin */
GPIO_InitStructure.GPIO_Pin = sFLASH_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_Init(sFLASH_CS_GPIO_PORT, &GPIO_InitStructure);
GPIO_SetBits(sFLASH_CS_GPIO_PORT, sFLASH_CS_PIN);
}
然后是在Dev_inf.c定义flash规格,此处英文备注容易误导,试了好几次才弄清楚,我对注释做了更正直观一些,继续保留英文风格不伤大雅:
#if defined (__ICCARM__)
__root struct StorageInfo const StorageInfo = {
#else
struct StorageInfo const StorageInfo = {
#endif
"GD25Q32_STM32F0XX-EVAL", // Device Name + version number
SPI_FLASH, // Device Type
0x00000000, // Device Start Address, STM32 external flash start at 0H
4*1024*1024, // Device Size in Bytes (4MBytes/32Mbits)
0x00000100, // Programming Page Size 256Bytes
0xFF, // Initial Content of Erased Memory
// Specify Size and Address of Sectors (view example below)
0x00000040, 0x00010000, // Block count : 64 ,each block has 64k byte
0x00000000, 0x00000000, // end flag
};
对应的spi读写函数也有点修改:
/**
* @brief Sends a byte through the SPI interface and return the byte received
* from the SPI bus.
* @param byte: byte to send.
* @retval The value of the received byte.
*/
uint8_t sFLASH_SendByte(uint8_t byte)
{
/*!< Loop while DR register in not emplty */
while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_TXE) == RESET);
/*!< Send byte through the SPI1 peripheral */
SPI_SendData8(sFLASH_SPI, byte);
/*!< Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(sFLASH_SPI, SPI_I2S_FLAG_RXNE) == RESET);
/*!< Return the byte read from the SPI bus */
return SPI_ReceiveData8(sFLASH_SPI);
}
编译后生成对应的stldr文件,因为项目文件夹与其他平行,所以生成的代码也在STLINK扫描的文件夹中,这样在STLINK中的External loader 菜单的add external loader 就会自动出现这个选择,见下图:
点击Validate就可以验证了。
注意,注意,注意!重要事情说3次,外挂Flash起始地址为0,注意烧录时候选择正确地址烧写bin文件,选择烧录后校验比较安全,毕竟是全部读回烧写的数据100%无误。
烧录后,可以直接在内存视图看到刚才烧录的数据了:
测试2M文件用了不到1分钟,通过更改spi分频还可以加快,我用了4分频。
至于具体字库及图片合并在另一文章讨论,因找不到合适软件,我做了个混合多个资源工具,自动生成资源地址定义,类似MFC资源索引。
本文仅针对外部flash烧录移植做了抛砖引玉的介绍,具体其他型号可以根据需求自行更改,有需求的也可以到我的下载中下载完整工程,代码在ST原装MCU和国产替代APM都测试通过,其他规格估计不行,因为STM32 STLINK 本身就不识别非ST芯片,目前只有Device ID兼容的高仿才可以用到这个便利功能。