2015-12-03 02:07 AM
Lately, I've been trying IAP over UART using Ymodem protocol for STM32F072C8 SOC based custom board. The goal is to try IAP with this mode with different upgrade scenarios and later transform these into my actual requirement. I was able to successfully perform IAP using ST provided libraries, IAP driver and template (More information can be found
/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a//my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Query%20on%20IAP%20over%20UART%20for%20STM32F072C8&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=27
) After this, I tried to put two different application firmware along with IAP driver in the main flash memory and was also able to jump from IAP driver to application f/w1 or f/w2. The memory layout that I'm using currently is as below: Table1: memory map of main flash memory (Total 64 kB)Table2: memory map of SRAM (Total 16 kB)
</colgroup>Component
main flash memory
Block number
Size
Bootloader
0x08000000 – 0x08003FFF
0
16 kB
fw 1
0x08004000 – 0x08009FFF
0
24 kB
fw 2
0x0800A000 – 0x0800FFFF
0
24 kB
Note#if (defined ( __CC_ARM ))
__IO uint32_t VectorTable[48] __attribute__((at(0x20000000)));
#elif (defined (__ICCARM__))
#pragma location = 0x20000000
__no_init __IO uint32_t VectorTable[48];
#elif defined ( __GNUC__ )
__IO uint32_t VectorTable[48] __attribute__((section(''.RAMVectorTable'')));
#elif defined ( __TASKING__ )
__IO uint32_t VectorTable[48] __at(0x20000000);
#endif
void
FLASH_If_Init(
void
)
{
/* Unlock the Program memory */
FLASH_Unlock();
/* Clear all FLASH flags */
FLASH_ClearFlag(FLASH_FLAG_EOP|FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR | FLASH_FLAG_BSY);
}
int
main(
void
)
{
uint32_t i = 0;
FLASH_Status status;
for
(i = 0; i < 48; i++)
{
VectorTable[i] = *(__IO uint32_t*)(APPLICATION_ADDRESS + (i<<2));
}
/* Enable the SYSCFG peripheral clock*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* Remap SRAM at 0x00000000 */
SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM);
/***************** Add your application code here ***************************/
FLASH_If_Init();
/* set flag to trigger IAP after a reset. this flag will be cleared by IAP driver after a successful update */
status = FLASH_ProgramWord(0x0800E000, 0x1);
while
(status != FLASH_COMPLETE);
while
(1)
{
// do something
}
}
Please advise on what could be going wrong here and also any pointers on this overall design. Basically I would like to have
status = FLASH_ErasePage(0x0800E000);
while
(status != FLASH_COMPLETE){}
status = FLASH_ProgramWord(0x0800E000, 0xDEADBEEF);
while
(status != FLASH_COMPLETE){}
0x08004000, instead of the default location (0x08000000)?
</colgroup>Component
Physical
Block number
Size
Purpose
Bootloader
NA
NA
NA
NA
fw {1|2}
0x20000000
1
0x4000
Vector table relocation to SRAM
that I'm using the same SRAM location for both application firmware (fw1, fw2)I'm able to put the three(IAP driver, fw1, fw2) images in the main flash memory and was also able to jump from IAP driver to fw1 or fw2. Now I would like to implement the following logic (See the flow below)To achieve this, I should be able to store a variable in main flash memory at an address accessible from each of the three images (IAP driver, fw1, fw2). However, when I tried to set a flag at some address, which I think is not being utilized at the moment,in flash memory from application firmware 1 (fw1), the system hung (I think I'm getting a hard fault here, but I need to check). Code snip for storing 0x1 at some random address (note that this main flash memory address is within the overall range i.e.0x0800 0000 - 0x0800 FFFF)SOC: STM32F072C8 64kB Flash memory (ARM cortex M0 based SOC)Main flash memory requirement: IAP driver + fw1 + fw2Application f/w size: ~20 kB (Theoratically, I should be able to fit in IAP driver and two differnt application firmware in 64kB flash memory)IDE: KEIL uVision5 for windowsIAP Mode: UARTUtilities: fromelf.exe (For converting .hex files into .bin file), ST Programmer (for In-circuit programming using SWD interface) and Hyperterminal [1]Reference document: AN4065 [2]Update #1:I'm able to program the main flash memory from the IAP driver, i.e. the following works when I invoke these in the IAP driver, but not when I try to do the same in application firmware.Also, now I'm not able to debug the application fimrware using the KEIL uVision5 debugger window. None of the single stepping, step over, etc tabs are getting activated. Do I need to configure some changes for debugger, since my application now is loaded at #iap #iap #iap #solved2015-12-03 03:43 AM
Well you also need to ensure the FLASH is erased for a write to succeed.
Personally, I'd have the images with an integral CRC so the loader could determine if the image was valid/complete without any separate flagging as such. And I'd use RAM to pass status between the app and loader. I don't think you're going to get source level debugging across transition easily. There are probably some methods to do so, but this is beyond the scope of the forum. The easy way is to a) use the disassembly view, stepping instructions, to extract enough insight into the failure, or b) instrument your own code sufficiently to get data from a serial or SWV connection, starting with a proper Hard Fault handler.2015-12-03 03:49 AM
In Keil, if you debug the app, not the loader, the ''run to main'' should get to the app's main() provided the loader doesn't get in the way to prevent this occurring normally. If your issue is before main() then you'll need break point the Reset Handler in the app and walk from there. If your issue is with the hand-off, then you need to be debugging the loader, and walk across the transition code to grasp what's wrong there.
2015-12-03 05:17 AM
Thanks Clive. As you suggested, I'll later implement CRC check, however for the time being, I moved from setting this flag in main flash memory to SRAM and in the application code, If I do :
*(uint32_t *)0x20000040 = 0x1;
It has no effect at all !!!, However, the same works fine in IAP driver/loader.
Unfortunately, I don't have much experience with debuggers but I'm trying to figure out the problem.
2015-12-03 07:53 AM
Well you want to be using a RAM address that's outside the scope of the linker, or C runtime code.
When you call __main in the Reset Handler code, it clears and copies the statics used by the application, and then calls your main() function. If you want a ''command line'' space, or a place to pass parameters or structures between loader/app(s) you might want to look at the end of RAM, and shrink the space passed to the linker so it's less apt to tread on it.2015-12-07 08:36 AM
For the time being, I came back to setting and resetting a flag in the main flash memory and found that previously I had address related issue in my application f/w. It's resolved and I now set a flag once I get a trigger (say from outside world) and issue a system reboot. IAP driver kicks in, it finds the flag set, starts IAP procedure. So far okay. I'd like to have firmware upgrade path such as application f/w A -> B-> C->D (At the moment, let's leave out, upgrading the IAP driver itself). Main flash memory should contain IAP driver and two application f/w (say C and B, Where C being the newest). To have minimum impact on application f/w development and to avoid bricking of f/w, I'm thinking of Copying the existing f/w first to a separate area of flash memory, then program the new firmware in the same area as the existing f/w. In case programming of new firmware fails, try to recover the old firmware from the separate flash memory area and reprogram the area, which it was occupying before. To achieve this, my first step was to just copy the original firmware in a separate flash memory. Sample code to do so is below:
#define APPLICATION_ADDRESS (uint32_t)0x08004000 /* all application will run from here */
#define APPLICATION_COPY_ADDRESS (uint32_t)0x0800A000 /* backup area for rollback purposes */
#define IAP_FLAG_ADDRESS (uint32_t)0x0800FC00 /* Last page for IAP flag and some other purposes */
uint32_t *p;
uint32_t *pFLASH = (uint32_t *)APPLICATION_ADDRESS;
for
(p = (uint32_t *)(APPLICATION_COPY_ADDRESS); p < (uint32_t *)IAP_FLAG_ADDRESS; ++p, ++pFLASH) {
if
(FLASH_ProgramWord(*p, *pFLASH) == FLASH_COMPLETE) {
/* verify the data */
if
(*(p) != *pFLASH) {
SerialPutString(
''
flash memory content do not match
''
);
return
ERROR;
}
}
else
{
SerialPutString(
''
Firmware program error
''
);
return
ERROR;
}
}
However, this results in HardFault. Is it because, I'm trying to access two different flash memory region at the same time, or is it due to something else ?
Thank you.
2015-12-07 08:55 AM
However, this results in HardFault. Is it because, I'm trying to access two different flash memory region at the same time, or is it due to something else ?
Most probably because you are confusing what's a pointer/address, and the content at an address.FLASH_ProgramWord(*p, *pFLASH)
// This is clearly wrong
FLASH_ProgramWord((uint32_t)p, *pFLASH) // The ADDRESS, not the CONTENT at the address
2015-12-07 09:49 AM
Damn me and also damn those suggestions by the IDE. Did a quick fix to make the IDE happy and got into trouble. Thank you Clive, however, doing a careful single step in debugger, shows me that just before programming the flash, I invoke the erase function and it's rather the erase function that causes this hardfault.
#define APPLICATION_COPY_ADDRESS (uint32_t)0x0800A000
#define FLASH_PAGE_SIZE 0x400 /* 1 Kbytes */
FLASH_Status FLASH_ErasePage(uint32_t Page_Address)
{
FLASH_Status status = FLASH_COMPLETE;
/* Check the parameters */
assert_param(IS_FLASH_PROGRAM_ADDRESS(Page_Address));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
if
(status == FLASH_COMPLETE)
{
/* If the previous operation is completed, proceed to erase the page */
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = Page_Address;
FLASH->CR |= FLASH_CR_STRT;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_ER_PRG_TIMEOUT);
/* Disable the PER Bit */
FLASH->CR &= ~FLASH_CR_PER;
}
/* Return the Erase Status */
return
status;
}
uint32_t FLASH_If_Erase(uint32_t StartSector)
{
uint32_t flashaddress;
flashaddress = StartSector;
while
(flashaddress <= (uint32_t) USER_FLASH_LAST_PAGE_ADDRESS)
{
if
(FLASH_ErasePage(flashaddress) == FLASH_COMPLETE)
{
flashaddress += FLASH_PAGE_SIZE;
}
else
{
/* Error occurred while page erase */
return
(1);
}
}
return
(0);
}
if
(FLASH_If_Erase(APPLICATION_COPY_ADDRESS)) {
SerialPutString(
'' Flash erase error
''
);
return
ERROR;
}
2015-12-08 02:23 AM
> I invoke the erase function and it's rather the erase function that causes this hardfault.
Are you sure you are unlocking the flash memory before trying to erase? Also, I would consider using the backup registers (or backup SRAM, if available) for passing small amounts of temporary data between resets.2015-12-09 03:23 AM
With backup register, do you mean, ''RTC backup registers (RTC_BKPxR)'' register on STM32F072C8?
In the meantime, I switched back to setting the flag in SRAM and now it works (I'm able to set the flag in application and reset it IAP driver). As Clive1 had suggested before, I opted a higher address in SRAM region and it worked. Note that this SOC has 16kB of SRAM memory. The IRAM1 value in Keil uVision5 are set to following values for each of the three component: </colgroup>
Component
Start
Size
IAP driver
0x20000000
0x4000
Firmware 1
0x200000C0
0x4000
Firmware 2
0x200000C0
0x4000
#define IAP_FLAG_ADDRESS 0x20003000 /* 0x200000C0 didn't worked */ #define IAP_FLAG 0x1CEB00DA