2009-10-18 11:08 PM
FLASH Copy / Vector Table Update / Core Reboot
2011-05-17 04:26 AM
All,
I’m trying to copy blocks of flash around, including the vector table, and then reboot the MCU. I’ve had no success so far. Does anyone have any pointers? The VERBOSE version of the code I have just now, is below. 1) g_strOTAUpdateBuffer is the source buffer ( downlaoded via HTTP over GPRS ) 2) All functions that are called are located “above� strOTAUpdateBuffer in FLASH. So they never get erased. // This is from part of the map file. ******************************************************************************* *** PLACEMENT SUMMARY *** ''A1'': place at mem:0x8000000 { ro section .intvec }; ''A2'': place at mem:0x8000800 { ro section .text }; ''A3'': place at mem:0x807fbff { ro section UPDATES }; ''A4'': place at mem:0x804dbff { rw section IMAGE }; g_strOTAUpdateBuffer 0x0804dc00 0x1 Data Gb ARMA_OTA_Updates.o [1] // So the Buffer goes to 0x0804dc00 and the routines needed to copy go to 0x0807fc00 ''A4'': 0x1 IMAGE zero 0x0804dc00 0x1 ARMA_OTA_Updates.o [1] - 0x0804dc01 0x1 ''A3'': 0x27c UPDATES ro code 0x0807fc00 0xbc ARMA_OTA_Updates.o [1] UPDATES ro code 0x0807fcbc 0x1ac stm32f10x_flash.o [1] UPDATES ro code 0x0807fe68 0x14 stm32f10x_nvic.o [1] - 0x0807fe7c 0x27c #define G_INT_FLASH_MEMORY_BLOCK_SIZE 2048 #define INT_LIVE_READ_ADDRESS 0x8000000 I know I need // Grant us access to writing flash memory FLASH_Unlock(); To Write to the FLASH, before anyone says. And I’ve thought that to take the Interrupt table out of the loop I’d stop the interrupts // Turn off interrupts. OS_DI(); But then I had a feeing that I could “de-init� some hardware too. RCC_DeInit(); NVIC_DeInit(); // Clear Down TIM4 Configuration TIM_DeInit(TIM4); USART_DeInit(USART1); USART_DeInit(USART2); None of this seems to work. Anyone got any procedural suggestions? Oh, and the code. Anything really silly here? // Now, Erase enough space in the FLASH system to store our downloaded data intPages = intLen / G_INT_FLASH_MEMORY_BLOCK_SIZE; intPages++; intLastAddress = ( intPages * G_INT_FLASH_MEMORY_BLOCK_SIZE ) + INT_LIVE_READ_ADDRESS; if ( intLastAddress < (int)&g_strOTAUpdateBuffer[0] ) { // Here we have space. So get to clearing the space pintSource = (int*)INT_LIVE_READ_ADDRESS; for ( intCurPage = 0 ; intCurPage < intPages ; intCurPage ++ ) { FLASH_ErasePage ( (u32)pintSource ); pintSource += G_INT_FLASH_MEMORY_BLOCK_SIZE; } // Now, we have to copy our new code over the old code! Page // at a time. Take it easy :) This section is critical. pintSource = (int*)&g_strOTAUpdateBuffer[0]; pintStorage = (int*)INT_LIVE_READ_ADDRESS; for ( intCurPage = 0; intCurPage < intPages ; intCurPage ++ ) { for ( intCounter = 1; intCounter < (G_INT_FLASH_MEMORY_BLOCK_SIZE/4) ; intCounter ++ ) { intTemp = *pintSource; FLASH_ProgramWord ( (u32)pintStorage, intTemp ); pintStorage ++; pintSource ++; } } // NVIC_GenerateSystemReset(); NVIC_GenerateCoreReset(); }2011-05-17 04:26 AM
Not sure if ''NVIC_GenerateCoreReset()'' works, at least I never got it working. Now I'm using the IWDG with a short timeout followed by a while(1).
2011-05-17 04:26 AM
On a 64KB RAM part I use the following sequence to restart the system and get it into the system loader. I use different keys to perform other critical functions prior to enabling other features, or dropping into the main application. ie Instead of disabling features on a running system, I reboot and do the work in a very controlled set of conditions with no interrupts or anything else. I would do this in assembler, and avoid using library code, again to control the conditions, and limit the code called outside my control.
*((unsigned long *)0x2000FFF0) = 0xDEADBEEF; NVIC_GenerateSystemReset(); Then very early in the restart in STM32F10x.s Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main LDR R0, =0x2000FFF0 LDR R1, =0xDEADBEEF LDR R2, [R0, #0] STR R0, [R0, #0] ; Invalidate CMP R2, R1 BEQ Reboot_Loader ; ldr r1, =0xDEADxxxx ; cmp r2, r1 ; beq Function_xxxx LDR R0, =__initial_sp LDR R1, =0x20010000 LDR R2, =0xE5E5E5E5 Clear_Heap STR R2, [R0, #0] ADD R0, #4 CMP R0, R1 BNE Clear_Heap LDR R0, =__main BX R0 ENDP ALIGN Reboot_Loader PROC EXPORT Reboot_Loader LDR R0, =0x1FFFF000 ; System Loader ROM LDR SP,[R0, #0] ; Initial Stack LDR R0,[R0, #4] ; Initial Program Counter BX R0 ENDP I also have other code, not shown, which copies some efficient self-contained assembler code to do the flashing from RAM. I'll note that is possible to program the entire flash page without toggling the PG bit for every word/half-word. I also blank check pages before erasing them, and skip writing pages which are full of 0xFF. I have a GSM modem pulling new firmware using HTTP (scary huh?), which it sticks into a free region of flash, once it has a valid image it starts a reboot/flash/run sequence. The reboot checks for a startup signature, and validates the image before erasing/flashing a page at a time. Once it has that completed it executes the new code. I also export the vector address so the linker does the work and I don't have any #define's to screw up. extern void * __Vectors; // exported, must be suitably aligned NVIC_SetVectorTable((u32)(&__Vectors), 0x0); // Smart Base Location The app code can be anywhere in FLASH/RAM provided the vector table is suitably aligned. -Clive2011-05-17 04:26 AM
This code incorrectly determines the number of pages when the size is an exact multiple of the page size. It will be one too big when this occurs, erasing the page beyond the range you expect.
// Now, Erase enough space in the FLASH system to store our downloaded data intPages = intLen / G_INT_FLASH_MEMORY_BLOCK_SIZE; intPages++; The code should be intPages = (intLen + G_INT_FLASH_MEMORY_BLOCK_SIZE - 1) / G_INT_FLASH_MEMORY_BLOCK_SIZE; This will round up correctly. ie 0x8000 would be 16 pages on a 512KB part. -Clive2011-05-17 04:26 AM
Clive1,
Thanks for your input in both your messages. That’s a good way of thinking of things that you have, vis-à -vis the boot process. The Atari-ST used to use a “magic� number to validate the reset vector and I was reminded of that approach by your comments. As I know that my image is located at g_strOTAUpdateBuffer then I can use the said magic number business to do something with it at reset. That’s the approach I’ll use I feel. Nice one. I hope I can get NVIC_GenerateSystemReset(); to actually do something. I’m using an RTOS too, so I have to quiet that down as well. And as for the intPages business; one more is okay:) Thanks for the ''solution'' in any case though. Most helpful all in. I’ll write back when I can’t get NVIC_GenerateSystemReset(); to anything :) As hbliek said, NVIC_GenerateCoreReset() seems to do very little:) Cheers man, and thanks hbliek. Dunk