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”.

A 53 year old Sangamo Weston uA meter


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.


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.


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.


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:
  1. How additional “pause” Words can have zero effect
  2. 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


  • 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 and ms-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

#require memstat.fs		    \ Optional development word

#require dict.fs		    \ Optional development word

#require f0-legends.fs

#require ms-loadmeter.memmap.fs

#require multitask.fs


\ 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
    nop						    \ some small delays to extend the meter pulse as this mcu is so fast

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
    id				    \ Optional development word
    mem				    \ Optional development word

Loadmeter Pics

Load task running


Load and blinky tasks running


Load, blinky and delay1 tasks running


Load, blinky, delay1, and delay2 tasks running


Load, blinky, delay1, delay2 and user-pb tasks running