Loadmeter¶
During embedded development, an accurate idea of the MCU load is important, and it’s nice to have it confirmed by a second source … enter the “Loadmeter”.
The meter is a 53 year old Sangamo Weston uA meter
See also
This project was featured on Hackaday: https://hackaday.com/2017/05/13/microcontroller-load-meter-tells-you-how-hard-its-currently-working/
Cooperative Multitasking¶
A cooperatively multitasked system relies on each process regularly giving up time to other processes on the system. One poorly designed task or process can consume all of the CPU time for itself, either by performing extensive calculations or by busy waiting; both would cause the whole system to hang.
Whilst a cooperative scheduler starts each task, they must voluntarily give back control when they are finished or even during stages of their operation by using the pause Word.
Note
busy-waiting, busy-looping or spinning is a technique in which a process repeatedly checks to see if a condition is true
How Does It Work ?¶
A loadmeter-task sends a short pulse to a Microamp Meter. Any other tasks delay the rate at which loadmeter-task can send pulses, therby reducing the duty cycle of the square wave pulse train to the meter, giving a lower reading and indicating more load.
A moving coil meter is ideal because the mechanical inertia will average the duty cycle of the pulse train.
Calibration¶
The Loadmeter is calibrated with a trimpot for a point near the high reading of the meter, (in this case the “0” on the DB meter scale) to indicate the minimum load of the default system. This is done while only the loadmeter-task is running.
Usage¶
Once the loadmeter-task is running, subsequent tasks will cause the Loadmeter pointer to move to the left, indicating they are using MCU time, which is a increase in load.
While indicating MCU load, a steady pointer shows ideal rapid cycling between tasks, but a pulsing Loadmeter pointer indicates a task may be hogging the MCU or perhaps the “pause” Word is in the wrong place, such as at the end of a 1 second delay, when it should be in the loop counter instead ?
- The Loadmeter also indicates:
How additional “pause” Words can have zero effect
Whether a task can be made more efficient with better code or perhaps by using a timer for a delay instead of spinning ?
Schematic Diagram¶
A STM32F0 Discovery board was used.
Loadmeter Schematic Diagram¶
Source Code and Notes¶
Notes:
The F0 Discovery board lacks RAM for more tasks, having only 8KB of RAM. Mecrisp-Stellaris will raise a ‘Not Enough Ram’ error if one more task is added.
This is all running from Flash so I can fit in the 5 tasks, if ms-loadmeter.fs is run from ram, then a task must be removed.
The USER push button lights the GREEN LED when depressed.
The Blinky flashes the BLUE LED on and off about once a second
Delays 1 and 2 just delay for a second each, they are there to waste time.
All ancillary files are available from the library
ms-loadmeter.fs
andms-loadmeter.memmap.fs
are available here.
\ Program Name: ms-loadmeter.fs
\ Edit template.xml, commenting out unwanted register lines ( <!- commented out -> F9 ), then run 'make'
\ Date: Tue 9 May 2017 05:29:17 AEST
\ Copyright 2017 t.porter <terry@tjporter.com.au> Released under the GPL
\ For Mecrisp-Stellaris by Matthias Koch
\ Chip: STM32F051
\ Board: STM32F0 Discovery Board
\ Terminal: e4thcom Copyright (C) 2013-2017 Manfred Mahlow; https://wiki.forth-ev.de/doku.php/en:projects:e4thcom
\ Clock: 8 Mhz using the internal STM32F051 RC clock, unless otherwise stated
\ All register names must be CMSIS-SVD compliant
\
\ This Program Does: Indicates MCU load using a external uA moving coil meter.
\
\ Inputs: none
\ Outputs: PF-1
\
\ ------------------ USER CODE HERE ------------------ \
compiletoflash \ seems that compiletoflash is reset to compiletoram after each upload ?
#require f0-id.fs \ Optional development word
compiletoflash
#require memstat.fs \ Optional development word
compiletoflash
#require dict.fs \ Optional development word
compiletoflash
#require f0-legends.fs
compiletoflash
#require ms-loadmeter.memmap.fs
compiletoflash
#require multitask.fs
compiletoflash
\ Initialisations
%01 2 lshift GPIOF_MODER bis! \ use PF-1 as meter driver o/p
%01 18 lshift GPIOC_MODER bis! \ PC-9 as output
%01 16 lshift GPIOC_MODER bis! \ PC-8 as outpu
: .5s-delay 25000 0 do pause loop ; \ Used by Blinky
: delay-1 50000 0 do pause loop ; \ 1 second delay
: delay-2 50000 0 do pause loop ;
: green-on %1 9 lshift GPIOC_BSRR bis! ; \ Activated by User pushbutton
: green-off %1 9 lshift GPIOC_BRR bis! ;
: blue-on %1 8 lshift GPIOC_BSRR bis! ; \ Activated by Blinky
: blue-off %1 8 lshift GPIOC_BRR bis! ;
: meter-high %1 1 lshift GPIOF_BSRR bis! ; \ PF-1 high
: meter-low %1 17 lshift GPIOF_BSRR bis! ; \ PF-1 low
: blink blue-on .5s-delay blue-off .5s-delay ;
: pb? ( -- ? ) 1 0 lshift GPIOA_IDR bit@ \ test User pushbutton, lights green led if pressed
if green-on else green-off then pause
;
: loadmeter
meter-high
nop
nop \ some small delays to extend the meter pulse as this mcu is so fast
meter-low
pause
;
task: loadmeter-task
: load& ( -- )
loadmeter-task activate
begin loadmeter again
;
task: blinktask
: blinky& ( -- )
blinktask activate
begin blink again
;
task: delay1
: delay1& ( -- )
delay1 activate
begin delay-1 again
;
task: delay2
: delay2& ( -- )
delay2 activate
begin delay-2 again
;
task: user-pb-task
: user-pb& ( -- )
user-pb-task activate
begin pb? again
;
\ multitask
load&
blinky&
delay1&
delay2&
user-pb&
id \ Optional development word
mem \ Optional development word
multitask