Modo DFU do carregador de inicialização STM32 usando CubeMX. Instruções passo a passo

Portanto, o trabalho desse mandril foi motivado pela quase completa ausência de instruções passo a passo, usando as ferramentas usuais oferecidas pela STMicroelectronics.

Infelizmente, o grande número de gerenciadores de inicialização encontrados na rede, às vezes muito ocupado, é "aguçado" para qualquer cristal em particular.

O material proposto contém o procedimento para usar o pacote CubeMX, o “carregador de inicialização” DfuSeDemo e o utilitário de preparação de firmware do gerenciador de arquivos Dfu, ou seja, abstraímos nossa lista de desejos do hardware, perdoamos o montador de macro e o guru da folha de dados.

Cozinhando o ambiente ...

Precisamos do próprio CubeMX, o download do gerenciador de arquivos DfuSeDemo + Dfu, estão todos no mesmo pacote, STM32 ST-LINK Utility, encontramos tudo no site da STMicroelectronics gratuitamente.

Nosso bastão experimental com o chip STM32F103C8T6 do tio Liao

imagem

e o programador ST-Link de lá.

imagem

Bem, seu IDE favorito, nesta apresentação específica, usamos KEIL, as configurações de compilação em outros IDEs não são muito diferentes.

Então vamos lá ...

Inicie o CubeMX e selecione o seu cristal ...

imagem

Celebre a sua lista de desejos ...

imagem

Nesta tarefa específica, ativamos o dispositivo USB → Device FS e, consequentemente, a classe Device USB → DownLoad Update Firmware, e o inesquecível RCC → Relógio de alta velocidade → Ressonador Cristal / Cerâmico é aquele a bordo.

Em seguida, selecione o comutador de modo bootloader-a; neste exemplo, basta usar o jumper boot1 existente.

imagem

Observamos o pequeno esquema e, de acordo com ele, o boot1 é anexado à parte do PB2 e, portanto, o usamos no modo GPIO_Input.

Feito, ative a guia Configuração do relógio e inicie a máquina de seleção de configuração.

imagem
Vá para a guia Cofiguração ...

imagem

Selecione o botão GPIO ...

imagem

E no campo ...

imagem
escreva um rótulo personalizado, seja boot1.

Em seguida, configure o projeto ...

imagem

Escolha Projeto → Configuração ...

imagem

Selecione e preencha ....

imagem

Assim, escolhemos para qual IDE Cub iremos gerar o projeto, no nosso caso, o MDK-ARM V5.

A guia Gerador de código nesta modalidade permanecerá inalterada ...

imagem

Bem, isso é tudo, começamos a geração do projeto Projeto → Gerar código

imagem

No final, o Cub solicitará que você inicie imediatamente seu IDE ... o que você deve fazer.

imagem

imagem

Começamos a compilação, montagem e carregamento no cristal ... F7, F8 ...

imagem

O resultado final ...

Mudamos os pinos da nossa placa para o modo operacional e conectamos o cabo USB ...

imagem

imagem

Abra o painel de controle no Windows → sistema → gerenciador de dispositivos → controlador USB. E observe a lista de dispositivos, o Windows fará um farfalhar e instalará o dispositivo STM no driver do modo DFU (se ainda não o estava).

Então, o motorista se levantou e decidiu, iniciar o "boot" DfuSeDemo ...

imagem

Analisamos o que capturamos no DFU Device e clicamos duas vezes no campo Selecionar destino ...

imagem

Olhamos e ficamos maravilhados com o fato de o flash até o endereço 0x0800C000 estar fechado para gravação e escrevermos esse endereço, precisamos dele ...

A propósito, eu tentei no STM32F407VE, onde a memória está aberta para gravação de 0x08000000, ou seja, desde o início ... por que, em nossa versão, não está claro, não está cavando, está enterrado em algum lugar, mas claramente não está escrito, não há nenhum comentário, porque um pedaço grande desaparece sem dono ... talvez alguém lhe diga onde cavar ...

Então, "o corte de cabelo está apenas começando" ...

Precisamos apenas de dois arquivos de origem ...

imagem

Nós os abrimos no IDE e corrigimos, adicionamos ...

Levamos em conta que o CubeMX NÃO JUNTO ao regenerar a inserção entre USER CODE BEGIN e USER COD END ... lá inseriremos nossas adições ...

Vamos começar com 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 */ . . . 

isso é tudo com main.c ...

vá para usbd_conf.he

 #define USBD_DFU_APP_DEFAULT_ADD 0x0800000 

trazer à mente ...

 #define USBD_DFU_APP_DEFAULT_ADD 0x080C000 //     … 

passamos para usbd_dfu_it.c, aqui mais ....

 . . . /* 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 */ } 

Na verdade isso é tudo ...

Conectamos o programador, jogamos os jumpers no modo de programação, F7, F8 e botloader são gravados ...

Posso usar ...

Agora vamos preparar nosso aplicativo para carregamento via bootloder ...
Aplicação favorita piscará LED ...

Preparamos e depuramos o aplicativo e alteramos os locais individuais no compilador e no corpo do programa para alterar o endereço dos vetores de inicialização e interrupção do programa ...

Ou seja, em KEIL → Configurar → Ferramentas Flash

imagem

Mude o endereço do início do programa ...

imagem

Dizemos para gerar um arquivo HEX

imagem

e altere o endereço da tabela vetorial ...

coletando o programa F7 ...

converter o HEX recebido em um arquivo dfo usando o utilitário gerenciador de arquivos Dfu ...

imagem

selecione nosso arquivo HEX com o botão S19 ou HEX ... e clique em Gerar ...

imagem

nós obtemos o arquivo dfu.

Na verdade, está tudo pronto.

Carregando no controlador ...

Conectamos nossa placa experimental com o botloader já carregado ao USB, depois de definir os jumpers no modo DFU.

imagem

Você pode controlar a aparência do dispositivo STM no modo DFU na lista de dispositivos.
execute o "carregador de inicialização".

imagem
diga a ela nosso arquivo dfu ...

imagem

Pressionamos Upgrade e observamos o resultado do carregamento ... por confiança, pressionamos check.

imagem

tudo é bem sucedido ... você pode correr ...

se o erro sair, isso significa que em algum lugar um batente ...

imagem

por exemplo ...

Então, vamos assumir que tudo foi bem-sucedido ... alterne o jumper para o modo de aplicação

imagem

e aproveite o diodo piscando ...
...
Uhhhh Tantos bukoffff. Cansado de copiar fotos :-)

Obrigado a todos pela atenção ...

Source: https://habr.com/ru/post/pt432398/


All Articles