Hi,
I'm trying to run an STM32F103 on as little power as possible. Most of the time, the processor is in Standby, waking up occasionally on a RTC alarm interrupt.
When the processor wakes, from the current consumption, it appears that it takes approximately 2ms before I get to the start of my c main() function - which seems like a long time to me.
The processor is fitted with an 8MHz external xtal, but I'm hoping to start up on the HSI clock (which appears to be the case if I check with the debugger).
I'm using the Keil microlib; I know it will take some time to initialise memory etc. - but 2ms seems rather long. According to the hardware manual, the HCI startup time is 2us.
Can anyone give me an idea about what I'm missing? What is the processor doing for 2ms before it gets to main()?
Thanks in advance,
Jon.
There are a couple of implementations, including some which compress the statics.
It should enumerate through a Load Region list that the Linker creates, describing areas of memory to copy, decompress, or zero.
At 8 MHz, and 2 ms, you are looking at about 16000 cycles.
Thanks.
I'm surprised it takes so long to initialise my statics etc. - it hadn't occurred to me that it would take anywhere near 2ms. I'm hoping (in most cases) to wake up, check a few things, and then get back to sleep as quickly as possible (to reduce power consumption). My checks take approximately 2ms, so initialisation code is essentially doubling the time that the processor is powered up (and therefore doubling my power consumption).
It seems that Keil doesn't give me many options for optimising the library initialisation routines for my application, so it looks like I'm going to have to re-write all of my checking code in assembler - and have it run before __main (which is a big piece of work).
I was hoping to get a copy of the source code for the __main library function (including the copying/initialising/decompressing), so that I could modify it to start up faster - just initialising the variables that are important for my checks etc. - but it seems that only the binary libraries are provided.
Regards, Jon.
You don't need to use assembler, if you 1) Don't rely on the initial state of your global variables. 2) Are careful to not use any CRTL function that relies on the state of global variables. 3) You make sure you call your function with a proper stack frame.
So you could jump to a C function and then depending on the return value in a register decide if you should continue to __main or not. Or even have the function you called turn off the power without returning.
Per,
That sounds like the kind of solution I need - it hadn't occurred to me. Your description makes sense - apart from the piece about the stack frame. Can you point me towards an explanation or so example code ensure that I've got a stack frame? Does that just mean that I need to ensure that the SP is set to a sensible stack address before calling my function (as long as my function prototype is void func(void))?
You need an initialized stack, so your initial C function can be allowed to call secondary C functions.
And you should call your C function the same way the compiler would implement a call. You can look at disassembly to see what is required.
The stack size is usually defined in startup_stm32f10x.s, usually pretty small by default, 512 bytes?
The initialization code is pretty efficient, a tight assembler loop, but I'd still expect it to take 3-4 cycles per 32-bit word to zero, and a few more to copy.
Try not to have 8.5 KB of space to zero