uptime
command.
$ man -k uptime uptime (1) - Tell how long the system has been running.I am going to make a quick prototype first to validate the concept.
volatile unsigned uptime ; /* seconds elapsed since boot */ #ifdef LED_ON static void userLEDtoggle( void) { GPIO( LED_IOP)[ ODR] ^= 1 << LED_PIN ; /* Toggle User LED */ } #endif void SysTick_Handler( void) { uptime += 1 ; #ifdef LED_ON userLEDtoggle() ; #endif }The global variable
uptime
is marked volatile
, the
compiler needs this information to avoid optimization as the value changes
concurrently when an interrupt is triggered.
I move the user LED toggling code to a dedicated local function
userLEDtoggle()
as this is not the only task of
SysTick_Handler()
anymore and a call to toggle the LED is needed
during initialization. I adjust the initialization code accordingly.
I write a first uptime.1.c to print the count of seconds every time
the uptime
counter value changes.
/* uptime.1.c -- tells how long the system has been running */ #include <stdio.h> extern volatile unsigned uptime ; extern void kputc( unsigned char c) ; void kputu( unsigned u) { unsigned r = u % 10 ; u /= 10 ; if( u) kputu( u) ; kputc( '0' + r) ; } int main( void) { static unsigned last ; for( ;;) if( last != uptime) { last = uptime ; kputu( last) ; puts( " sec") ; } else __asm( "WFI") ; /* Wait for System Tick Interrupt */ }As before for
kputc()
, the implementation of kputu()
to print an unsigned integer in decimal format is not optimal but still
functional.
SRCS = startup.c uplow.1.c uptime.1.cUnfortunately, when I try to build an executable, the link phase fails.
$ make f030f4.elf D:\Program Files (x86)\GNU Arm Embedded Toolchain\arm-gnu-toolchain-13.3.rel1-mi ngw-w64-i686-arm-none-eabi\bin\arm-none-eabi-ld.exe: uptime.1.o: in function `kp utu': D:\Projects\stm32bringup\docs/uptime.1.c:13:(.text+0x6): undefined reference to `__aeabi_uidivmod' D:\Program Files (x86)\GNU Arm Embedded Toolchain\arm-gnu-toolchain-13.3.rel1-mi ngw-w64-i686-arm-none-eabi\bin\arm-none-eabi-ld.exe: D:\Projects\stm32bringup\do cs/uptime.1.c:14:(.text+0x14): undefined reference to `__aeabi_uidiv' make: *** [Makefile:45: f030f4.elf] Error 1The compiler has generated code that references two functions
__aeabi_uidivmod
and __aeabi_uidiv
when compiling
the lines 13 and 14 of uptime.1.c.
unsigned r = u % 10 ; u /= 10 ;This happens because the compiler generates code for Cortex-M0 which has no integer division support. So integer division needs to be implemented by code as it is not supported by hardware. I need to pass the linker a reference to GNU Arm Embedded Toolchain library for Cortex-M0. The library file is libggc.a, the option -l and -L of the linker tell what the library name is (-lgcc => libgcc.a) and where to look for it.
LIBDIR = $(GCCDIR)/lib/gcc/arm-none-eabi/13.3.1/thumb/v6-m/nofp LIB_PATHS = -L$(LIBDIR) LIBS = -lgcc $(PROJECT).elf: $(OBJS) @echo $@ $(LD) -T$(LD_SCRIPT) $(LIB_PATHS) -Map=$(PROJECT).map -cref -o $@ $^ $(LIBS) $(SIZE) $@ $(OBJDUMP) -hS $@ > $(PROJECT).lstOnce the Makefile has been updated, the build finish successfully.
$ make f030f4.elf text data bss dec hex filename 769 0 8 777 309 f030f4.elf f030f4.hex f030f4.binChecking the linker produced map file, f030f4.map, I can see which library (libgcc.a) but also which modules in the library ( _udivsi3.o and _dvmd_tls.o) have been used to resolve the symbols (
__aeabi_uidiv
and __aeabi_idiv0
).
Archive member included to satisfy reference by file (symbol) D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mi ngw-w64-i686-arm-none-eabi/lib/gcc/arm-none-eabi/13.3.1/thumb/v6-m/nofp\libgcc.a (_udivsi3.o) uptime.1.o (__aeabi_uidiv) D:/Program Files (x86)/GNU Arm Embedded Toolchain/arm-gnu-toolchain-13.3.rel1-mi ngw-w64-i686-arm-none-eabi/lib/gcc/arm-none-eabi/13.3.1/thumb/v6-m/nofp\libgcc.a (_dvmd_tls.o) D:/Program Files (x86)/GNU Arm Embedded Toolchain/ arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi/lib/gcc/arm-none-eabi/1 3.3.1/thumb/v6-m/nofp\libgcc.a(_udivsi3.o) (__aeabi_idiv0)
ar
command distributed by the GNU Arm embedded toolchain is
the same GNU ar as the Linux or Cygwin and MSYS2 distributions on
Windows. So I use my native environment implementation for convenience.
This is true for the utility commands (ar
, objcopy
,
objdump
and size
) but not for gcc
and
ld
.
uptime
and found an extra
dependency to Gnu Arm Embedded Toolchain: some modules included in
libgcc.a have to be included at link time as the chipset I am using has
no support for integer division. At this stage I will reuse the library as it
is, but I know where to look in the map file generated by the linker to find
which modules are included. If I ever need a better control of the link phase,
I can use ar
to extract locally those modules from the library.
Next, I will write uptime
with a
better structure.