Passage d’un firmware à un autre dans le FLASH interne du MCU

Je travaille actuellement sur une application de micrologiciel de chargeur de démarrage ciblée sur STM32F030C8. J’ai spécifié dans mon fichier scatter que l’application du chargeur de démarrage occupera l’emplacement de mémoire principale 0x08000000 à 0x08002FFF (secteur 0 à secteur 2). J’ai également écrit une application de firmware principale stockée de 0x08003000 à 0x0800C800. Après avoir téléchargé les deux microprogrammes sur le FLASH interne du MCU, j’ai lancé l’application principale à partir du chargeur de démarrage à l’aide du code ci-dessous:

/************************************************************//** * \brief Start the main application if available and correct *****************************************************************/ void INTFLASH_execute_main_app(const char mode) { MyFunc_ptr AppEntry; uint32_t temp[1]; IRQn_Type index; memcpy(temp, (void*)&NVIC->ISER, sizeof(NVIC->ISER)); //Save enabled interrupts for( index = (IRQn_Type)0; indexISER, temp, sizeof(NVIC->ISER) ); //Restore interrupts } 

Pour une raison quelconque, lorsqu’il exécute AppEntry (), il passe au code ci-dessous et n’exécute pas l’application principale à l’emplacement 0x08003000:

 HardFault_Handler\ PROC EXPORT HardFault_Handler [WEAK] B . ENDP 

J’ai déjà utilisé ce type de logique sur MCM ARM7 et cela fonctionne bien. Je ne comprends pas très bien pourquoi cela ne fonctionne pas sur ce MCU à base de cortex M0. Toute aide serait grandement appréciée.

Voir les fichiers Scatter pour le chargeur de démarrage et l’application principale ci-dessous:

 LR_IROM1 0x08000000 0x00003000 { ; load region size_region ER_IROM1 0x08000000 0x00003000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00002000 { ; RW data .ANY (+RW +ZI) } } LR_IROM1 0x08003000 0x0000C800 { ; load region size_region ER_IROM1 0x08003000 0x0000C800 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000000 0x00002000 { ; RW data .ANY (+RW +ZI) } } 

Vous devez accéder à “l’adresse de l’application + 4” car l’adresse de base de l’application contient la position initiale du pointeur de stack. Donc, sauter à cette adresse signifie sauter à l’adresse de la base de la stack. Sous l’adresse de l’application + 4 (+ 4B en raison de l’architecture 32 bits), vous trouverez l’adresse de la procédure de réinitialisation du gestionnaire.

Dans le fichier ‘startup_stm32f03xx.s’, assurez-vous de disposer du code suivant:

 EXTERN HardFault_Handler_C ; this declaration is probably missing __tx_vectors ; this declaration is probably there DCD HardFault_Handler 

Ensuite, dans le même fichier, ajoutez le gestionnaire d’interruption suivant (où se trouvent tous les autres gestionnaires):

  PUBWEAK HardFault_Handler SECTION .text:CODE:REORDER(1) HardFault_Handler TST LR, #4 ITE EQ MRSEQ R0, MSP MRSNE R0, PSP B HardFault_Handler_C 

Ensuite, dans le fichier ‘stm32f03xx.c’, ajoutez l’ISR suivant:

 void HardFault_Handler_C(unsigned int* hardfault_args) { printf("R0 = 0x%.8X\r\n",hardfault_args[0]); printf("R1 = 0x%.8X\r\n",hardfault_args[1]); printf("R2 = 0x%.8X\r\n",hardfault_args[2]); printf("R3 = 0x%.8X\r\n",hardfault_args[3]); printf("R12 = 0x%.8X\r\n",hardfault_args[4]); printf("LR = 0x%.8X\r\n",hardfault_args[5]); printf("PC = 0x%.8X\r\n",hardfault_args[6]); printf("PSR = 0x%.8X\r\n",hardfault_args[7]); printf("BFAR = 0x%.8X\r\n",*(unsigned int*)0xE000ED38); printf("CFSR = 0x%.8X\r\n",*(unsigned int*)0xE000ED28); printf("HFSR = 0x%.8X\r\n",*(unsigned int*)0xE000ED2C); printf("DFSR = 0x%.8X\r\n",*(unsigned int*)0xE000ED30); printf("AFSR = 0x%.8X\r\n",*(unsigned int*)0xE000ED3C); printf("SHCSR = 0x%.8X\r\n",SCB->SHCSR); while (1); } 

Si vous ne pouvez pas utiliser printf au moment de l’exécution lorsque cette interruption de défaillance grave survient, sauvegardez toutes les données ci-dessus dans un tampon global afin de pouvoir les visualiser après avoir atteint la fin de la période while (1) .

Reportez-vous ensuite à la section “Exceptions et registres d’erreurs Cortex-M” à l’ adresse http://www.keil.com/appnotes/files/apnt209.pdf pour comprendre le problème ou publiez le résultat ici si vous souhaitez obtenir de l’aide. .

Le défaut fort ISR m’a indiqué où la faute était. R0 avait __initial_sp qui est le sumt de la stack. Cela m’a fait comprendre que je devais initialiser le pointeur Stack de mon application dans le chargeur de démarrage avant de passer à l’application. Cela fait, je peux maintenant accéder à l’application à partir du chargeur de démarrage. L’adresse de saut doit également être (pour une raison quelconque, je ne comprends pas bien) l’adresse de l’application + 4.

Notez également que vous devez modifier l’allocation de mémoire vive de l’application principale pour qu’elle démarre à partir de 0x200000C0 de taille 0x00001FD0. Ceci est fait pour que vous puissiez déplacer la table de vecteurs dans la SRAM interne à l’adresse 0x20000000 dans la fonction “principale” de l’application principale, comme suit:

 /* Private macro -------------------------------------------------------------*/ __IO uint32_t VectorTable[48] __atsortingbute__((at(0x20000000))); /************************************************************//** * \brief Main application application entry point * * At this stage the microcontroller clock setting is already configured, * this is done through SystemInit() function which is called from startup * file (startup_stm32f030x8.s) before to branch to application main. * To reconfigure the default setting of SystemInit() function, refer to * startup_stm32f030x8.c file *****************************************************************/ int main( void ) { uint32_t i = 0; uint8_t status; /* Relocate by software the vector table to the internal SRAM at 0x20000000 ***/ /* Copy the vector table from the Flash (mapped at the base of the application load address 0x08003000) to the base address of the SRAM at 0x20000000. */ for(i = 0; i < 48; i++) { VectorTable[i] = *(__IO uint32_t*)(IAP_BTLUPG_ADDRESS + (i<<2)); } RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; /* Enable the SYSCFG peripheral clock*/ SYSCFG->CFGR1 = SYSCFG_CFGR1_MEM_MODE; /* Remap SRAM at 0x00000000 */ /***************** Application code starts below ***************************/ } 

Voir ma nouvelle fonction de chargeur de démarrage INTFLASH_execute_main_app ci-dessous:

 void INTFLASH_execute_main_app(const char mode) { MyFunc_ptr Jump_To_Application; uint32_t JumpAddress; // __disable_irq(); JumpAddress = *(__IO uint32_t*) (IAP_APP_ADDRESS + 4); Jump_To_Application = (MyFunc_ptr) JumpAddress; if( mode || intflash_check_main_app() ) { App_ptr = (uint8_t*)Jump_To_Application; if( (*App_ptr != 0xFF) && (App_ptr) ) { __set_MSP( *(__IO uint32_t*)IAP_APP_ADDRESS ); // Initialise app's Stack Pointer Jump_To_Application(); } } // __enable_irq(); } 

Merci beaucoup