2022-04-22 04:40 AM
Hello,
At work we have developed firmware on a stm32l0 based on different time base with systick and counters of elapsed time (10ms, 100ms and 1s). Therefore, some function are executed periodically.
The board is powered with 3.3V.
In order to measure cpu load, we use a gpio and a voltmeter as below :
main()
{
/* Init phases */
...
...
while(1)
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
if(u8_FlagTime10ms == 1u)
{
u8_FlagTime10ms = 0u;
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
/*
* Do some stuff
*/
}
if(u8_FlagTime100ms == 1u)
{
u8_FlagTime100ms = 0u;
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
/*
* Do some stuff
*/
}
if(u8_FlagTime1000ms == 1u)
{
u8_FlagTime1000ms = 0u;
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
/*
* Do some stuff
*/
}
}
}
In this way, by using the min, max and average value shown by the voltmeter, we can compute the cpu load with the formula :
Cpu load % min = ( (3.3V - V_min_voltmeter) / 3.3V ) * 100
Cpu load % moy = ( (3.3V - V_moy_voltmeter) / 3.3V ) * 100
Cpu load % max = ( (3.3V - V_max_voltmeter) / 3.3V ) * 100
My question is the following:
Is this method suitable to compute cpu load for an stm32L0 ?
Thank you in advance :smiling_face_with_smiling_eyes:
Sebastian
2022-04-22 05:50 AM
Careful:
I do something similar, but from a magazine article from ages back, and two variants of it (DAC and no DAC).
Paul
2022-04-22 08:09 AM
No, that won't work as an interrupt could happen at any time. You could do the following:
while (1) {
__disable_irq();
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
__disable_irq();
// other stuff
}
You would need to take a reading of the voltage at idle first. Then, cpu usage would be a scale between 0V (100%) and the idle reading (0%). Idle reading value will vary based on compiler settings and code.
There are better ways.
2022-04-22 08:12 AM
Or simpler What is your LOAD ? Current to MCU or reply to question CPU do nothing or something.
Your idea is ok for nothing vs something, but dont count ISR code. Current load is big and relative constant, for example 3mA . L0 is low power designed then if you properly use for example STOP mode you jump to 3uA and in lower mode 300nA . 10000:1
2022-04-22 08:33 AM
How would you even know which task you were looking at? Should perhaps be using different GPIO or an else-if
Perhaps be better looking at elapsed time across a WFI
2022-04-23 03:26 AM
Implement a proper task scheduling and sleeping at a single location of code with WFI at idle. Then, as said by Tesla, measure the time spend sleeping with a hardware timer. Typically DWT_CYCCNT is used.
To get the idea:
uint32_t t1, t2;
for (;;) {
__disable_irq();
if (/* Test if there are no tasks to execute */) {
t1 = DWT->CYCCNT;
__DSB();
__WFI();
t2 = DWT->CYCCNT;
__enable_irq();
// Accumulate the idle time for some period and then calculate the CPU load for that period
} else {
// Select the task to execute
// Remove the active flag for the selected task
__enable_irq();
// Execute the selected task
}
}
2022-04-23 03:56 AM
If you have implemented the idle loop as suggested by @Piranha and still want to use your voltmeter (L0 doesn't have CYCCNT), issue a __SEV() instruction in the idle for loop and configure the pin as EVENTOUT. That loop will consume all remaining CPU cycles and the pin will be high whenever __SEV() is executed and low else.
By using a logic analyzer (starting at $10) you can gain much more insight like execution patterns and interrupt latencies.
There is also instrumentation software which will collect such info for you, but this is, of course, an intrusive method.
hth
KnarfB
2022-04-23 04:06 AM
Also setting/resetting any pin around the WFI instead of reading t1/t2 should also do the job.