使用CubeMX的STM32引导加载程序DFU模式。 分步说明

因此,使用STMicroelectronics提供的常用工具几乎完全没有逐步说明,这促使了这种手法的工作。

不幸的是,对于网络上发现的大量引导加载程序,有时非常繁忙,它们对于任何特定的晶体都是“锐化的”。

提议的材料包含使用CubeMX软件包,DfuSeDemo“引导程序”和Dfu文件管理器固件准备实用程序的过程,也就是说,我们从硬件中提取了我们的愿望清单,请原谅宏汇编器和数据表大师。

烹饪环境...

我们需要CubeMX本身,DfuSeDemo + Dfu文件管理器下载文件,并且都在同一软件包STM32 ST-LINK Utility中,我们可以在STMicroelectronics网站上免费找到所有内容。

我们的实验棒配备了廖叔叔的STM32F103C8T6芯片

图片

以及那里的ST-Link程序员。

图片

好吧,您最喜欢的IDE,在此特定演示中,我们使用KEIL,其他IDE中的编译设置也没有太大不同。

所以走吧...

启动CubeMX并选择您的水晶...

图片

庆祝您的愿望清单...

图片

在此特定任务中,我们将激活USB设备→设备FS,并因此激活USB设备→下载更新固件类,而令人难忘的RCC→高速时钟→晶体/陶瓷谐振器就是其中一个。

接下来,选择bootloader-a模式开关,在此示例中,仅使用现有的boot1跳线。

图片

我们看一下这个小方案,根据它,boot1连接到PB2的分支,因此我们在GPIO_Input模式下使用它。

完成后,激活“时钟配置”选项卡并启动配置选择器。

图片
跳转到Cofiguration选项卡...

图片

选择GPIO按钮...

图片

在野外...

图片
编写一个自定义标签,将其设为boot1。

接下来,设置项目...

图片

选择项目→设置...

图片

选择并填充....

图片

因此,我们选择为哪个IDE Cub生成项目,在本例中为MDK-ARM V5。

在此实施例中,“代码生成器”选项卡将保持不变...

图片

好了,就是这样,我们开始生成项目Project→Generate Code

图片

最后,Cub将提示您立即启动您的IDE ...您应该做什么。

图片

图片

我们开始编译和组装,并将其加载到晶体... F7,F8 ...

图片

最终结果...

我们将板上的引脚切换到工作模式,然后连接USB电缆...

图片

图片

在Windows→系统→设备管理器→USB控制器中打开控制面板。 再看一下设备列表,Windows会沙沙作响,并在DFU模式驱动程序中安装STM设备(如果尚未安装)。

因此,驱动程序起来并决定启动“ boot” DfuSeDemo ...

图片

我们查看捕获了DFU设备的内容,然后双击“选择目标”字段...

图片

我们仔细观察并惊奇地发现,关闭了写入地址0x0800C000的闪存以进行写入,然后写入该地址,我们需要它...

顺便说一下,我在STM32F407VE上进行了尝试,该存储器从一开始就是从0x08000000开始记录的。。。为什么,在我们的版本中,不清楚,没有挖掘,它被埋在某个地方,但是显然没有写,没有通俗的说法,因为一大块东西消失了,没有主人了……也许有人会告诉你在哪里挖……

因此,“理发才刚刚开始” ...

我们只需要两个源文件...

图片

我们在IDE中打开它们,然后更正,我们添加了...

我们考虑到在重新生成USER CODE BEGIN和USER CODE END之间的插入时CubeMX不会在一起...在这里我们将输入附加内容...

让我们从main.c开始

/* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ typedef void (*pFunction)(void); pFunction JumpToApplication; uint32_t JumpAddress; /* USER CODE END PV */ . . . /* USER CODE BEGIN 0 */ uint32_t AddressMyApplicationBegin = 0x0800C000; uint32_t AddressMyApplicationEnd = 0x0800FBFC; /* USER CODE END 0 */ . . . /* USER CODE BEGIN 2 */ /* Check if the KEY Button is pressed */ if(HAL_GPIO_ReadPin(boot1_GPIO_Port, boot1_Pin ) == GPIO_PIN_SET) { /* Test if user code is programmed starting from address 0x0800C000 */ if (((*(__IO uint32_t *) USBD_DFU_APP_DEFAULT_ADD) & 0x2FFE0000) == 0x20000000) { /* Jump to user application */ JumpAddress = *(__IO uint32_t *) (USBD_DFU_APP_DEFAULT_ADD + 4); JumpToApplication = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t *) USBD_DFU_APP_DEFAULT_ADD); JumpToApplication(); } } MX_USB_DEVICE_Init(); /*      */ /* USER CODE END 2 */ . . . 

这就是main.c ...

转到usbd_conf.h并转到

 #define USBD_DFU_APP_DEFAULT_ADD 0x0800000 

想到...

 #define USBD_DFU_APP_DEFAULT_ADD 0x080C000 //     … 

我们传递给usbd_dfu_it.c,这里还有更多...。

 . . . /* USER CODE BEGIN PRIVATE_TYPES */ extern uint32_t AddressMyApplicationBegin; extern uint32_t AddressMyApplicationEnd; /* USER CODE END PRIVATE_TYPES */ . . . /* USER CODE BEGIN PRIVATE_DEFINES */ #define FLASH_ERASE_TIME (uint16_t)50 #define FLASH_PROGRAM_TIME (uint16_t)50 /* USER CODE END PRIVATE_DEFINES */ . . .   ,    «»  … uint16_t MEM_If_Init_FS(void) { /* USER CODE BEGIN 0 */ HAL_StatusTypeDef flash_ok = HAL_ERROR; //   while(flash_ok != HAL_OK){ flash_ok = HAL_FLASH_Unlock(); } return (USBD_OK); /* USER CODE END 0 */ } . . . uint16_t MEM_If_DeInit_FS(void) { /* USER CODE BEGIN 1 */ HAL_StatusTypeDef flash_ok = HAL_ERROR; //  flash_ok = HAL_ERROR; while(flash_ok != HAL_OK){ flash_ok = HAL_FLASH_Lock(); } return (USBD_OK); /* USER CODE END 1 */ } . . . uint16_t MEM_If_Erase_FS(uint32_t Add) { /* USER CODE BEGIN 2 */ uint32_t NbOfPages = 0; uint32_t PageError = 0; /* Variable contains Flash operation status */ HAL_StatusTypeDef status; FLASH_EraseInitTypeDef eraseinitstruct; /* Get the number of sector to erase from 1st sector*/ NbOfPages = ((AddressMyApplicationEnd - AddressMyApplicationBegin) / FLASH_PAGE_SIZE) + 1; eraseinitstruct.TypeErase = FLASH_TYPEERASE_PAGES; eraseinitstruct.PageAddress = AddressMyApplicationBegin; eraseinitstruct.NbPages = NbOfPages; status = HAL_FLASHEx_Erase(&eraseinitstruct, &PageError); if (status != HAL_OK) { return (!USBD_OK); } return (USBD_OK); /* USER CODE END 2 */ } . . . uint16_t MEM_If_Write_FS(uint8_t *src, uint8_t *dest, uint32_t Len) { /* USER CODE BEGIN 3 */ uint32_t i = 0; for(i = 0; i < Len; i+=4) { /* Device voltage range supposed to be [2.7V to 3.6V], the operation will be done by byte */ if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (uint32_t)(dest+i), *(uint32_t*)(src+i)) == HAL_OK) { // Usart1_Send_String("MEM_If_Write_FS OK!"); /* Check the written value */ if(*(uint32_t *)(src + i) != *(uint32_t*)(dest+i)) { /* Flash content doesn't match SRAM content */ return 2; } } else { /* Error occurred while writing data in Flash memory */ return (!USBD_OK); } } return (USBD_OK); /* USER CODE END 3 */ } . . . uint8_t *MEM_If_Read_FS (uint8_t *src, uint8_t *dest, uint32_t Len) { /* Return a valid address to avoid HardFault */ /* USER CODE BEGIN 4 */ uint32_t i = 0; uint8_t *psrc = src; for (i = 0; i < Len; i++) { dest[i] = *psrc++; } return (uint8_t*)(dest); /* ,     */ /* USER CODE END 4 */ } . . . uint16_t MEM_If_GetStatus_FS (uint32_t Add, uint8_t Cmd, uint8_t *buffer) { /* USER CODE BEGIN 5 */ switch (Cmd) { case DFU_MEDIA_PROGRAM: buffer[1] = (uint8_t)FLASH_PROGRAM_TIME; buffer[2] = (uint8_t)(FLASH_PROGRAM_TIME << 8); buffer[3] = 0; break; case DFU_MEDIA_ERASE: default: buffer[1] = (uint8_t)FLASH_ERASE_TIME; buffer[2] = (uint8_t)(FLASH_ERASE_TIME << 8); buffer[3] = 0; break; } return (USBD_OK); /* USER CODE END 5 */ } 

其实就这些...

我们连接编程器,将跳线置于编程模式,并记录F7,F8和botloader ...

我可以使用...

现在,我们将准备我们的应用程序以通过引导程序加载...
最喜欢的应用程序将闪烁LED ...

我们准备和调试应用程序,并更改编译器和程序主体中的各个位置,以更改程序启动和中断向量的地址...

即在KEIL中→配置→Flash工具

图片

更改程序开头的地址...

图片

我们说要生成一个十六进制文件

图片

并更改向量表的地址...

收集F7程序...

使用Dfu文件管理器实用程序将接收到的HEX转换为dfo文件...

图片

使用按钮S19或HEX ...选择我们的HEX文件,然后单击Generate ...

图片

我们得到了dfu文件。

实际上,一切都准备就绪。

正在载入控制器...

将跳线设置为DFU模式后,我们将实验板与已经加载的botloader连接到USB。

图片

您可以在设备列表中以DFU模式控制STM设备的外观。
运行“ bootloader”。

图片
告诉她我们的DFU文件...

图片

我们按升级,然后观察加载的结果...为了放心,我们按。

图片

一切都成功了...您可以运行...

如果错误出了错,那意味着某个地方出现了...

图片

例如...

因此,我们将假设一切成功...将跳线切换到应用程序模式

图片

并享受闪烁的二极管...
...
h 这么多布科夫。 厌倦了复制图片:-)

谢谢大家的关注...

Source: https://habr.com/ru/post/zh-CN432398/


All Articles