0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

从零编写STM32H7的MDK SPI FLASH下载算法

嵌入式应用研究院 来源:AIoT开源项目分享 2023-02-13 11:05 次阅读

Part1前言

当我们要下载编译好的镜像到Flash时,首先要做的一步就是选择合适的Flash下载算法,而这个算法本身就是一个FLM文件:
ba495eb6-ab47-11ed-bfe3-dac502259ad0.png

代码既可以下载到内部flash,也可以下载到外部flash,或者一部分下载到内部,一部分下载到外部。

Part2一、将代码中的图片资源下载到外部flash

在UI设计中往往需要大量的图片和字体,图片和字体资源在代码中以静态数组的形式存在,这些大数组在内部flash中一般存放不下,所以需要把这些占用资源比较大的数组放在外部flash中,然后通过QSPI地址映射的方式访问,或者通过SPI将flash中的资源分批读取到RAM缓存中使用。

通过MDK打开分散加载文件,配置“ExtFlashSection”段:

;*************************************************************
;***Scatter-LoadingDescriptionFilegeneratedbyuVision***
;*************************************************************

LR_IROM10x080000000x00020000{;loadregionsize_region
ER_IROM10x080000000x00020000{;loadaddress=executionaddress
*.o(RESET,+First)
*(InRoot$$Sections)
.ANY(+RO)
.ANY(+XO)
}
RW_IRAM10x200000000x00020000{;RWdata
.ANY(+RW+ZI)
}
RW_IRAM20x240000000x00080000{
.ANY(+RW+ZI)
}
}

LR_EROM10x900000000x01000000{;loadregionsize_region
ER_EROM10x900000000x01000000{;loadaddress=executionaddress
*.o(ExtFlashSection)
*.o(FontFlashSection)
*.o(TextFlashSection)
}
}

添加LR_EROM1 段,起始地址为0x90000000 ,大小为0x01000000 。

在代码中将图片资源分配到ExtFlashSection段

#defineLOCATION_ATTRIBUTE(name)__attribute__((section(name)))__attribute__((aligned(4)))

KEEPexternconstunsignedcharimage_watch_seconds[]LOCATION_ATTRIBUTE("ExtFlashSection")=//4x202ARGB8888pixels.
{
0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0x00,
0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0xff,
0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0x00,
0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0x00,
0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0xff,
0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0xff,
0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0x00,
0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0x00,
0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0xff,
0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0x00,
0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0xff,
0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0xff,
0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0xff,0xf8,0xfc,0xf8,0x00,
0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0x00,0xf8,0xfc,0xf8,0x00,
0xf8,0xfc,0xf8,0x00
};

编译代码

ba57c58c-ab47-11ed-bfe3-dac502259ad0.png

查看map文件,image_watch_seconds这个数组已经被分配到了0X90138690这个地址了,这个地址正是LR_EROM1 所在的区间。

Part3二、MDK下载算法原理

1程序能够通过下载算法下载到芯片的原理

通过MDK创建一批与地址信息无关的函数,实现的功能主要有初始化,擦除,编程,读取,校验等,然后MDK调试下载阶段,会将算法文件加载到芯片的内部RAM里面(加载地址可以通过MDK设置),然后MDK通过与这个算法文件的交互,实现程序下载,调试阶段数据读取等操作。

2算法程序中擦除操作执行流程

ba6f50da-ab47-11ed-bfe3-dac502259ad0.png

算法程序中擦除操作执行流程

加载算法到芯片RAM。

执行初始化函数Init。

执行擦除操作,根据用户的MDK配置,这里可以选择整个芯片擦除或者扇区擦除。

执行Uinit函数。

操作完毕。

3制作FLM文件步骤

ARM:CMSIS Pack文件夹(通常是C:KeilARMPackARMCMSIS version Device_Template_Flash)中的工程复制到一个新文件夹中,取消文件夹的只读属性,重命名项目文件NewDevice.uvprojx以表示新的flash 设备名称,例如MyDevice.uvprojx。

打开工程,从工具栏中,使用下拉选择目标来选择处理器架构。

打开对话框Project - Options for Target - Output并更改Name of Executable字段的内容以表示设备,例如MyDevice。

调整文件FlashPrg中的编程算法。

调整文件FlashDev中的设备参数

使用Project - Build Target生成新的 Flash 编程算法。

以上步骤是利用官方的工程模板修改代码,这种方式网上已有很多教程(推荐使用这种方法),不再重复介绍,接下来介绍一种不使用模板工程制作的方法,目的是为了了解其实现原理。

Part4三、使用STM32CubeMX新建工程

4新建工程

硬件平台: RT-Thread官方ART-PI H750开发版

软件: STM32CubeMX,MDK

选择MCU型号(STM32H750XBH6)

ba7f747e-ab47-11ed-bfe3-dac502259ad0.png

选择MCU型号

配置SPI

baa37bb2-ab47-11ed-bfe3-dac502259ad0.png


配置SPI

配置UART

babdbb94-ab47-11ed-bfe3-dac502259ad0.png

配置UART

配置时钟

bacf7ff0-ab47-11ed-bfe3-dac502259ad0.png

配置时钟树

设置调试接口

bae35e4e-ab47-11ed-bfe3-dac502259ad0.png

设置调试接口

设置工程并生成工程

baf613ae-ab47-11ed-bfe3-dac502259ad0.png

生成工程

52. 移植SFUD串行 Flash 通用驱动库

SFUD 是什么

SFUD(https://github.com/armink/SFUD) 是一款开源的串行 SPI Flash 通用驱动库。由于现有市面的串行 Flash 种类居多,各个 Flash 的规格及命令存在差异, SFUD 就是为了解决这些 Flash 的差异现状而设计,让我们的产品能够支持不同品牌及规格的 Flash,提高了涉及到 Flash 功能的软件的可重用性及可扩展性,同时也可以规避 Flash 缺货或停产给产品所带来的风险。

主要特点:支持 SPI/QSPI 接口、面向对象(同时支持多个 Flash 对象)、可灵活裁剪、扩展性强、支持 4 字节地址

资源占用

标准占用:RAM:0.2KB ROM:5.5KB

最小占用:RAM:0.1KB ROM:3.6KB

设计思路:

什么是 SFDP :它是 JEDEC (固态威廉希尔官方网站 协会)制定的串行 Flash 功能的参数表标准,最新版 V1.6B (点击这里查看)。该标准规定了,每个 Flash 中会存在一个参数表,该表中会存放 Flash 容量、写粒度、擦除命令、地址模式等 Flash 规格参数。目前,除了部分厂家旧款 Flash 型号会不支持该标准,其他绝大多数新出厂的 Flash 均已支持 SFDP 标准。所以该库在初始化时会优先读取 SFDP 表参数。

不支持 SFDP 怎么办 :如果该 Flash 不支持 SFDP 标准,SFUD 会查询配置文件 ( /sfud/inc/sfud_flash_def.h ) 中提供的 Flash 参数信息表 中是否支持该款 Flash。如果不支持,则可以在配置文件中添加该款 Flash 的参数信息。获取到了 Flash 的规格参数后,就可以实现对 Flash 的全部操作。

移植SFUD

将下载到sfud源代码放置在工程目录中

bb0bb33a-ab47-11ed-bfe3-dac502259ad0.png

将sfud添加到工程目录:

bb22a432-ab47-11ed-bfe3-dac502259ad0.png

修改sfud_port.c文件:

#include
#include
#include
#include"gpio.h"
#include"spi.h"

typedefstruct{
SPI_HandleTypeDef*spix;
GPIO_TypeDef*cs_gpiox;
uint16_tcs_gpio_pin;
}spi_user_data,*spi_user_data_t;

staticspi_user_dataspi1;
staticcharlog_buf[256];
voidsfud_log_debug(constchar*file,constlongline,constchar*format,...);
externintrt_vsnprintf(char*buf,intsize,constchar*fmt,va_listargs);
externintrt_kprintf(constchar*fmt,...);
staticvoidspi_lock(constsfud_spi*spi)
{

}

staticvoidspi_unlock(constsfud_spi*spi)
{

}
/*about100microseconddelay*/
staticvoiddelay_100us(void){
uint32_tdelay=2000;
while(delay--);
}
/**
*SPIwritedatathenreaddata
*/
staticsfud_errspi_write_read(constsfud_spi*spi,constuint8_t*write_buf,size_twrite_size,uint8_t*read_buf,
size_tread_size)
{
sfud_errresult=SFUD_SUCCESS;
/**
*addyourspiwriteandreadcode
*/
spi_user_data_tspi_dev=(spi_user_data_t)spi->user_data;

HAL_GPIO_WritePin(spi_dev->cs_gpiox,spi_dev->cs_gpio_pin,GPIO_PIN_RESET);
if(write_size){
HAL_SPI_Transmit(spi_dev->spix,(uint8_t*)write_buf,write_size,1);
}
if(read_size){
HAL_SPI_Receive(spi_dev->spix,read_buf,read_size,1);
}
exit:
HAL_GPIO_WritePin(spi_dev->cs_gpiox,spi_dev->cs_gpio_pin,GPIO_PIN_SET);
returnresult;
}

sfud_errsfud_spi_port_init(sfud_flash*flash)
{
sfud_errresult=SFUD_SUCCESS;

switch(flash->index){
caseSFUD_W25Q128_DEVICE_INDEX:{
spi1.spix=&hspi1;
spi1.cs_gpiox=GPIOA;
spi1.cs_gpio_pin=GPIO_PIN_4;
/*同步Flash移植所需的接口及数据*/
flash->spi.wr=spi_write_read;
flash->spi.lock=spi_lock;
flash->spi.unlock=spi_unlock;
flash->spi.user_data=&spi1;
/*about100microseconddelay*/
flash->retry.delay=delay_100us;
/*adout60secondstimeout*/
flash->retry.times=60*10000;

break;
}
}

returnresult;
}

voidsfud_log_debug(constchar*file,constlongline,constchar*format,...){
va_listargs;

/*argspointtothefirstvariableparameter*/
va_start(args,format);
rt_kprintf("[SFUD](%s:%ld)",file,line);
/*mustusevprintftoprint*/
rt_vsnprintf(log_buf,sizeof(log_buf),format,args);
rt_kprintf("%s
",log_buf);
va_end(args);
}

voidsfud_log_info(constchar*format,...){
va_listargs;

/*argspointtothefirstvariableparameter*/
va_start(args,format);
rt_kprintf("[SFUD]");
/*mustusevprintftoprint*/
rt_vsnprintf(log_buf,sizeof(log_buf),format,args);
rt_kprintf("%s
",log_buf);
va_end(args);
}

测试SFUD

在main.c中添加测试代码:

/*USERCODEENDHeader*/
/*Includes------------------------------------------------------------------*/
#include"main.h"
#include"spi.h"
#include"usart.h"
#include"gpio.h"

/*Privatefunctionprototypes-----------------------------------------------*/
voidSystemClock_Config(void);
staticvoidMPU_Config(void);
/*USERCODEBEGINPFP*/
externintrt_kprintf(constchar*fmt,...);
#include"sfud.h"
/*USERCODEENDPFP*/

/*Privateusercode---------------------------------------------------------*/
/*USERCODEBEGIN0*/
#defineSFUD_DEMO_TEST_BUFFER_SIZE1024

staticuint8_tsfud_demo_test_buf[SFUD_DEMO_TEST_BUFFER_SIZE];
/**
*SFUDdemoforthefirstflashdevicetest.
*
*@paramaddrflashstartaddress
*@paramsizetestflashsize
*@paramsizetestflashdatabuffer
*/
staticvoidsfud_demo(uint32_taddr,size_tsize,uint8_t*data){
sfud_errresult=SFUD_SUCCESS;
constsfud_flash*flash=sfud_get_device_table()+0;
size_ti;
/*preparewritedata*/
for(i=0;i< size; i++) {
        data[i] = i;
    }
    /* erase test */
    result = sfud_erase(flash, addr, size);
    if (result == SFUD_SUCCESS) {
        rt_kprintf("Erase the %s flash data finish. Start from 0x%08X, size is %d.
", flash->name,addr,
size);
}else{
rt_kprintf("Erasethe%sflashdatafailed.
",flash->name);
return;
}
/*writetest*/
result=sfud_write(flash,addr,size,data);
if(result==SFUD_SUCCESS){
rt_kprintf("Writethe%sflashdatafinish.Startfrom0x%08X,sizeis%d.
",flash->name,addr,
size);
}else{
rt_kprintf("Writethe%sflashdatafailed.
",flash->name);
return;
}
/*readtest*/
result=sfud_read(flash,addr,size,data);
if(result==SFUD_SUCCESS){
rt_kprintf("Readthe%sflashdatasuccess.Startfrom0x%08X,sizeis%d.Thedatais:
",flash->name,addr,
size);
rt_kprintf("Offset(h)000102030405060708090A0B0C0D0E0F
");
for(i=0;i< size; i++) {
            if (i % 16 == 0) {
                rt_kprintf("[%08X] ", addr + i);
            }
            rt_kprintf("%02X ", data[i]);
            if (((i + 1) % 16 == 0) || i == size - 1) {
                rt_kprintf("
");
            }
        }
        rt_kprintf("
");
    } else {
        rt_kprintf("Read the %s flash data failed.
", flash->name);
}
/*datacheck*/
for(i=0;i< size; i++) {
        if (data[i] != i % 256) {
            rt_kprintf("Read and check write data has an error. Write the %s flash data failed.
", flash->name);
break;
}
}
if(i==size){
rt_kprintf("The%sflashtestissuccess.
",flash->name);
}
}

/*USERCODEEND0*/

intmain(void)
{

/*MPUConfiguration--------------------------------------------------------*/
MPU_Config();

/*MCUConfiguration--------------------------------------------------------*/

/*Resetofallperipherals,InitializestheFlashinterfaceandtheSystick.*/
HAL_Init();

SystemClock_Config();

MX_GPIO_Init();
MX_SPI1_Init();
MX_UART4_Init();
/*USERCODEBEGIN2*/
if(sfud_init()==SFUD_SUCCESS){
sfud_demo(0,sizeof(sfud_demo_test_buf),sfud_demo_test_buf);
}

while(1)
{

}

}

#endif/*USE_FULL_ASSERT*/

运行如下:

bb3c7448-ab47-11ed-bfe3-dac502259ad0.png

63.制作下载算法

重新生成不带main函数的工程

bb518982-ab47-11ed-bfe3-dac502259ad0.png

添加修改编程算法文件FlashPrg.c

模板工程里面提供了FlashOS.h和FlashPrg.c ,复制到此工程中,然后对FlashPrg.c 代码进行填充。

#include"FlashOS.H"
#include"sfud.h"
#include"gpio.h"
#include"usart.h"
#include"spi.h"

staticuint32_tbase_adr;

/*
*InitializeFlashProgrammingFunctions
*Parameter:adr:DeviceBaseAddress
*clk:ClockFrequency(Hz)
*fnc:FunctionCode(1-Erase,2-Program,3-Verify)
*ReturnValue:0-OK,1-Failed
*/

#ifdefinedFLASH_MEM||definedFLASH_OTP
intInit(unsignedlongadr,unsignedlongclk,unsignedlongfnc)
{
MX_GPIO_Init();
MX_UART4_Init();
MX_SPI1_Init();
base_adr=adr;
if(sfud_init()==SFUD_SUCCESS){
return0;
}else{
return1;
}
}
#endif


/*
*De-InitializeFlashProgrammingFunctions
*Parameter:fnc:FunctionCode(1-Erase,2-Program,3-Verify)
*ReturnValue:0-OK,1-Failed
*/

#ifdefinedFLASH_MEM||definedFLASH_OTP
intUnInit(unsignedlongfnc)
{

return(0);
}
#endif

/*
*ErasecompleteFlashMemory
*ReturnValue:0-OK,1-Failed
*/

intEraseChip(void)
{
intresult=0;
constsfud_flash*flash=sfud_get_device_table();
/*AddyourCode*/
result=sfud_erase(flash,0,flash->chip.capacity);

if(result==SFUD_SUCCESS)
return0;
else
returnresult;//FinishedwithoutErrors
}

/*
*EraseSectorinFlashMemory
*Parameter:adr:SectorAddress
*ReturnValue:0-OK,1-Failed
*/

#ifdefFLASH_MEM
intEraseSector(unsignedlongadr)
{
intresult=0;
uint32_tblock_start;
constsfud_flash*flash;
flash=sfud_get_device_table();
block_start=adr-base_adr;
result=sfud_erase(flash,block_start,4096);

if(result==SFUD_SUCCESS)
return0;
else
returnresult;
}
#endif


/*
*ProgramPageinFlashMemory
*Parameter:adr:PageStartAddress
*sz:PageSize
*buf:PageData
*ReturnValue:0-OK,1-Failed
*/

#ifdefinedFLASH_MEM||definedFLASH_OTP
intProgramPage(unsignedlongblock_start,unsignedlongsize,unsignedchar*buffer)
{
constsfud_flash*flash=sfud_get_device_table()+0;
uint32_tstart_addr=block_start-base_adr;

if(sfud_write(flash,start_addr,size,buffer)==SFUD_SUCCESS)
return0;
else
return1;
}


#definePAGE_SIZE4096
uint8_taux_buf[PAGE_SIZE];
unsignedlongVerify(unsignedlongadr,unsignedlongsz,unsignedchar*buf)
{
inti;
constsfud_flash*flash=sfud_get_device_table();
sfud_read(flash,adr-base_adr,sz,aux_buf);

for(i=0;i< PAGE_SIZE; i++) {
        if (aux_buf[i] != buf[i])
            return (adr + i);                 // Verification Failed (return address)
    }

    return (adr + sz);                    // Done successfully
}

#endif

在工程中定义FLASH_MEM宏

bb607762-ab47-11ed-bfe3-dac502259ad0.png

添加修改配置文件FlashDev.c

模板工程里面提供了FlashDev.c ,复制到此工程中,然后对代码进行修改。

#include"FlashOS.H"

#ifdefFLASH_MEM
structFlashDeviceconstFlashDevice={
FLASH_DRV_VERS,//DriverVersion,donotmodify!
"STM32H750-ARTPI",//DeviceName
EXTSPI,//DeviceType
0x90000000,//DeviceStartAddress
0x08000000,//DeviceSizeinBytes(128MB)
0x00001000,//ProgrammingPageSize4096Bytes
0x00,//Reserved,mustbe0
0xFF,//InitialContentofErasedMemory
10000,//ProgramPageTimeout100mSec
6000,//EraseSectorTimeout6000mSec

//SpecifySizeandAddressofSectors
0x1000,0x000000,//SectorSize4kB
SECTOR_END
};
#endif//FLASH_MEM

特别注意:"STM32H750-ARTPI"就是MDK的Option选项里面会识别出这个名字。0x90000000是MDK分散加载文件中定义的外部flash起始地址。

地址无关代码实现

C和汇编的配置勾选上:


bb747ece-ab47-11ed-bfe3-dac502259ad0.pngbb90c69c-ab47-11ed-bfe3-dac502259ad0.png

ROPI地址无关实现

如果程序的所有只读段都与位置无关,则该程序为只读位置无关(ROPI, Read-only position independence)。ROPI段通常是位置无关代码(PIC,position-independent code),但可以是只读数据,也可以是PIC和只读数据的组合。选择“ ROPI”选项,可以避免用户不得不将代码加载到内存中的特定位置。这对于以下例程特别有用:

(1)加载以响应运行事件。

(2)在不同情况下使用其他例程的不同组合加载到内存中。

(3)在执行期间映射到不同的地址。

RWPI数据无关实现使用Read-Write position independence同理,表示的可读可写数据段。使用RWPI编译代码,解决RW段即全局变量的加载。首先编译的时候会为每一个全局变量生成一个相对于r9寄存器的偏移量,这个偏移量会在.text段中。

在加载elf阶段,将RW段加载到RAM当中之后,需要将r9寄存器指向此片内存的基地址,然后接下来就可以跳转到加载的elf的代码中去执行,就可以实现全局变量的加载了。这也就是利用MDK的FLM文件生成通用flash驱动中提到的需要在编译选项中添加-ffixed-r9的原因。

综上所述,勾选ROPI和RWPI选项,可以实现elf文件的动态加载,还遗留的一个小问题是elf模块如何调用系统函数,这与此文无关,留在以后再讲。

特别注意:

由于模块中不含中断向量表,所以程序中不要开启任何中断。

startup_stm32h750xx.s不再需要参与编译

bba03280-ab47-11ed-bfe3-dac502259ad0.png

修改分散加载文件

复制一份新的分散加载文件到工程目录中,然后修改成如下代码

bbaff440-ab47-11ed-bfe3-dac502259ad0.png


--diag_suppress L6305用于屏蔽没有入口地址的警告信息。

;LinkerControlFile(scatter-loading)
;

PRG0PI;ProgrammingFunctions
{
PrgCode+0;Code
{
*(+RO)
}
PrgData+0;Data
{
*(+RW,+ZI)
}
}

DSCR+0;DeviceDescription
{
DevDscr+0
{
FlashDev.o
}
}

将程序可执行文件axf修改为flm格式

通过这个cmd.exe /C copy "!L" "..@L.FLM"命令可以将生成的axf可执行文件修改为flm。


bbcda490-ab47-11ed-bfe3-dac502259ad0.pngbbe256b0-ab47-11ed-bfe3-dac502259ad0.png


将生成的flm文件拷贝到...Keil_v5ARMFlash目录,即可被MDK识别到。

DEMO下载地址:https://gitee.com/Aladdin-Wang/STM32H7_W25QXXX

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FlaSh
    +关注

    关注

    10

    文章

    1633

    浏览量

    147952
  • 算法
    +关注

    关注

    23

    文章

    4608

    浏览量

    92844
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1706

    浏览量

    91516
  • MDK
    MDK
    +关注

    关注

    4

    文章

    209

    浏览量

    32063
  • 编写
    +关注

    关注

    0

    文章

    29

    浏览量

    8443

原文标题:从零编写STM32H7的MDK SPI FLASH下载算法

文章出处:【微信号:嵌入式应用研究院,微信公众号:嵌入式应用研究院】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    MDK下载算法制作方法

    第36章 STM32F407的SPI 总线应用之SPI FlashMDK下载
    发表于 08-10 06:18

    讲解STM32CubeProg下载算法制作方法

    第85章 STM32H7SPI 总线应用之SPI FlashSTM32CubeProg下载
    发表于 08-10 06:23

    STM32H7的内部Flash和QSPI Flash混合执行程序的优势

    第83章 STM32H7的内部Flash和QSPI Flash都运行程序的混合方式(强烈推荐)本章节为大家讲解内部Flash和外部QSPI Flas
    发表于 08-18 06:57

    STM32H7教程】第19章 STM32H7的GPIO应用之按键FIFO

    STM32H7教程】第19章 STM32H7的GPIO应用之按键FIFO
    发表于 11-23 18:21 9次下载
    【<b class='flag-5'>STM32H7</b>教程】第19章 <b class='flag-5'>STM32H7</b>的GPIO应用之按键FIFO

    STM32H7学习之路继续(stm32H7系列3) GPIO

    STM32H7学习之路继续(stm32H7系列3) GPIO
    发表于 11-30 12:36 20次下载
    <b class='flag-5'>STM32H7</b>学习之路继续(<b class='flag-5'>stm32H7</b>系列3)  GPIO

    STM32H7】第20章 ThreadX GUIX汉字显示(QSPI Flash全字库)

    STM32H7】第20章 ThreadX GUIX汉字显示(QSPI Flash全字库)
    发表于 12-02 09:36 14次下载
    【<b class='flag-5'>STM32H7</b>】第20章 ThreadX GUIX汉字显示(QSPI <b class='flag-5'>Flash</b>全字库)

    STM32H7教程】第21章 STM32H7的NVIC中断分组和配置(重要)

    STM32H7教程】第21章 STM32H7的NVIC中断分组和配置(重要)
    发表于 12-04 14:36 13次下载
    【<b class='flag-5'>STM32H7</b>教程】第21章 <b class='flag-5'>STM32H7</b>的NVIC中断分组和配置(重要)

    "STM32H7学习继续(STM32H7系列5)第十七章比较实用,以后写程序的时候会用到"

    "STM32H7学习继续(STM32H7系列5)第十七章比较实用,以后写程序的时候会用到"
    发表于 12-05 11:21 9次下载
    "<b class='flag-5'>STM32H7</b>学习继续(<b class='flag-5'>STM32H7</b>系列5)第十七章比较实用,以后写程序的时候会用到"

    STM32H7教程】第8章 STM32H7的终极调试组件Event Recorder

    STM32H7教程】第8章 STM32H7的终极调试组件Event Recorder
    发表于 12-05 20:06 7次下载
    【<b class='flag-5'>STM32H7</b>教程】第8章 <b class='flag-5'>STM32H7</b>的终极调试组件Event Recorder

    STM32H7教程】第14章 STM32H7的电源,复位和时钟系统

    STM32H7教程】第14章 STM32H7的电源,复位和时钟系统
    发表于 12-09 11:21 36次下载
    【<b class='flag-5'>STM32H7</b>教程】第14章 <b class='flag-5'>STM32H7</b>的电源,复位和时钟系统

    AN5293 STM32F7系列移植到STM32H7系列

    AN5293 STM32F7系列移植到STM32H7系列
    发表于 11-21 12:57 1次下载
    AN5293 <b class='flag-5'>STM32F7</b>系列移植到<b class='flag-5'>STM32H7</b>系列

    AN4936_STM32F7STM32H7的软件移植

    AN4936_STM32F7STM32H7的软件移植
    发表于 11-21 17:06 5次下载
    AN4936_<b class='flag-5'>从</b><b class='flag-5'>STM32F7</b>到<b class='flag-5'>STM32H7</b>的软件移植

    STM32H7威廉希尔官方网站 详解

    电子发烧友网站提供《STM32H7威廉希尔官方网站 详解.pdf》资料免费下载
    发表于 08-01 14:49 5次下载
    <b class='flag-5'>STM32H7</b>威廉希尔官方网站
详解

    不能连接上STM32H7芯片

    不能连接上STM32H7芯片
    的头像 发表于 09-18 10:58 1311次阅读
    不能连接上<b class='flag-5'>STM32H7</b>芯片

    STM32H7以太网的MMC中断

    电子发烧友网站提供《STM32H7以太网的MMC中断.pdf》资料免费下载
    发表于 09-20 09:11 0次下载
    <b class='flag-5'>STM32H7</b>以太网的MMC中断