You are here: Foswiki>Frontend Web>LM32Developments (29 May 2024, UlrichBecker)Edit Attach

LM32 and Linux Developments

This topic describes the software development for the SCU which lies under the FESA- layer and the SAFT-lib.

Table of Contents

Obtaining the LM32 Frontend SDK

For LM32 developments is this GIT repository necessary.

This repository includes some sub-repositories, therefore don't forget the option "--recursive" if you'll clone this repository.

git clone --recursive https://github.com/UlrichBecker/gsi_scu.git

If you works on the ASL-cluster then add following to the environment variable LD_LIBRARY_PATH if not already done:

export LD_LIBRARY_PATH=/common/usr/cscofe/lib:/common/usr/fesa/lib:$LD_LIBRARY_PATH

Obtaining the LM32 Toolchain respectively a GNU- Cross-Compiler for LM32

Furher is a LM32 cross-toolchain necessary. This toolchain is on the ASL cluster installed and can be found in this folder:

/common/usr/cscofe/opt/compiler/lm32

Add follows to your environment variable PATH if you works on ASL:
export PATH=/common/usr/cscofe/opt/compiler/lm32/bin:$PATH

Build your own LM32-Toolchain

If on your PC a Linux operating system installed, so it's recommanded to build and install the the LM32- cross-toolchain on your local PC. This can be easily accomplished by help of this GIT- repository.
Note the building of a toolchain can take a while, up to one hour and more.

Using the tool cppcheck as option

If you work on a local linux machine so it's meaningful to verify the C/C++ code by the additional tool cppcheck to make the sourcecode as clean as possible.
The cppcheck code analysis can still find errors and warnings that the compiler misses.
Unfortunately this tool isn't installed on the ASL- clusters at the moment, because its not a part of "rhel9". frown, sad smile

Note: For a release variant of a software project, only one number of warnings are permitted: zero!

By the way, there is an online portal for cppcheck that you can play around with.

Pre-built Makefiles

The main work in creating an executable file becomes accomplished by using pre-built makefiles. This pre-built makefiles shall be included at the bottom of each project- makefile.

For LM32 applications are following both lines in the concerning makefile necessary:
REPOSITORY_DIR := $(shell git rev-parse --show-toplevel)
include $(REPOSITORY_DIR)/makefiles/makefile.scu

And for linux applications:
REPOSITORY_DIR := $(shell git rev-parse --show-toplevel)
include $(REPOSITORY_DIR)/makefiles/makefile.scun

The pre-build makefiles can be found here.

Some Makefile targets

The following listed targets are implemented in the pre-built makefiles.

Common targets

Prerequisite is that you has changed in a directory which includes a "Makefile".

  • make Builds the corresponding binary file.
  • make clean Deletes the binary file and all build artifacts.
  • make rebuild Compiles the entire project new doesn't matter a source-file has changed or not.
  • make ldep Prints the dependencies, that means all source and headder files which are involved at the corresponding project.
  • make lsrc Prints all source code files belonging to the current project.
  • make incdirs Prints all include directories belonging to the current project.
  • make devargs Prints all definitions of the preprocessor which had been made in the makefile.
  • make doc Generates a doxygen documentation in HTML of the corresponding project. Don't care about the doxygen configuration file "Doxyfile" this becomes generated automatically by the makefile.
  • make showdoc Generates a doxygen documentation in HTML of the corresponding project and invokes the firefox-browser.
  • make deldoc Cleans the complete documentation.
  • make asm Translates all source code modules in assembler.
  • make objdump Builds the corresponding .elf - file and disassemble it.
  • make check Makes C/C++ code analysis of the current project by the tool cppcheck which is more accuracy as the compilers code analysis.
  • make V=1 Builds the project in the verbosity mode.

Tip: If your preferred editor is capable to open multiple files via the command line, then you can do this for a single project with the following command line:

<your preferred editor> $(make ldep)

Makefile targets especially for LM32 projects

Prerequisite is that the environment variable SCU_URL exist which includes the name of the target-SCU. E.g.: export SCU_URL=scuxl4711

  • make load Builds the LM32 binary file and loads it up to the corresponding SCU specified in SCU_URL.
  • make reset Makes a CPU-reset of the LM32.
  • make info Prints the build-ID.

Makefile targets especially for linux projects

For test and debug purposes the variable CALL_ARGS can set with commandline parameters.

  • make run Builds the binary-file and invoke it.
  • make dbg Builds a debugable binary-file and invokes the KDE-debugger frontend kdbg if the makefile-variable DEBUG=1. Yes KDE! That isn't exotic!
  • make public Builds the binary-file and copy it in the directory /common/usr/cscofe/bin/

Makefile variables

Some of the most important common makefile variables

  • REPOSITORY_DIR This variable is the most important which shall contain the path who this GIT-repository is installed.
    The following both codelines shall be include at the bottom of each mekefile:
    For LM32-applications:
    REPOSITORY_DIR := $(shell git rev-parse --show-toplevel)
    include $(REPOSITORY_DIR)/makefiles/makefile.scu
    For Linux-applications:
    REPOSITORY_DIR := $(shell git rev-parse --show-toplevel)
    include $(REPOSITORY_DIR)/makefiles/makefile.scun
  • MIAN_MODULE By default the name of the sourcefile which contains the function main() this is also the name of the binary file. E.g.:
    MIAN_MODULE = scu_control_os.c
  • SOURCE List of additional source files, which can be C-, cplusplus- or assembler- files. E.g.:
    SOURCE += mprintf.c
    SOURCE + scu_task_daq.c
  • DEFINES List of predefined macros. E.g.:
    DEFINES += CONFIG_USE_TEMPERATURE_WATCHER
    DEFINES + MAX_LM32_INTERRUPTS=2
  • INCLUDE_DIRS List of additional directories of header files. E.g.:
    INCLUDE_DIRS + $(RTOS_SRC_DIR)/include
  • CFLAGS Compiler flags. E.g.:
    CFLAGS += -Wall
    CFLAGS + -Wfatal-errors
  • LD_FLAGS Linker flags. E.g.:
    LD_FLAGS + -Wl,--gc-sections
  • CODE_OPTIMIZATION Code optimization level. E.g.:
    CODE_OPTIMIZATION = s
  • NO_LTO By default the link time optimizer is active. If this is not desired then this variable has to be initialized by one. E.g.:
    NO_LTO = 1
  • SCU_URL Name of the developer-SCU. E.g.:
    SCU_URL = scuxl4711.acc.gsi.de

Makefile variables which concerns the the building of LM32 applications only

  • USRCPUCLK CPU-clock in kHz. by default its 125000.
  • RAM_SIZE Size of LM32-RAM in bytes. By default on SCU3: 147456 bytes.
  • USE_RTOS The base source files of FreeRTOS will added to the project.
  • RTOS_USING_HEAP Number of heap-model for FreeRTOS, this can be 1, 2, 3, 4 or 5. By default the heap-model 1 will used.

Makefile variables which concerns the building of Linux applications only

  • LIBS List of additional libraries. E.g.:
    LIBS + stdc++
  • LIB_DIRS Path to additional libraries.
  • IS_LIBRARY Binary will build as library if its value is 1.
  • STATIC_LIBRARY Binary will build as static-library if its value is 1.
  • FOR_SCU Binary shall run on SCU only.
  • FOR_SCU_AND_ACC Binary can run on SCU and ASL-cluster.
  • DEBUG Binary will build with debug-infos. In this case the code optimization is 0, doesn't matter how the value of CODE_OPTIMIZATION is. And the target make dbg becomes active.
  • CALL_ARGS List of command line parameters for binary to test. This variable will used by the target make run and make dbg.

Compiling a LM32 application

Building the classical "Hello world" example application for LM32

In this example you can see how the makefile has to look for a simple LM32 application.

Makefile:

MIAN_MODULE := hello_lm32_world.c
SOURCE += $(SCU_LIB_SRC_LM32_DIR)/scu_std_init.c # Initializes the most important wishbone devices, this will be done by the startup code before the function main() is called. 
# NO_LTO := 1
CODE_OPTIMIZATION = s
REPOSITORY_DIR := $(shell git rev-parse --show-toplevel)
include $(REPOSITORY_DIR)/makefiles/makefile.scu

Sourcecode "hello_lm32_world.c" will print the text Hello world!" on the eb-console:

#include <mprintf.h>
#include <stdbool.h>

void main( void )
{
  mprintf( "Hello world!\n" );
  while( true );
}
  1. Change in directory gsi_scu/demo-and-test/lm32/non-os/Hello_World
  2. Build the binary file by typing: make.
  3. If the binary was successful built it will be in this directory: gsi_scu/demo-and-test/lm32/non-os/Hello_World/deploy_lm32/result/Hello_World.bin
  4. If the variable SCU_URL specified so you can upload the binary-file by typing make load. Of course it is possible to define the variable SCU_URL in the makefile as well, this will overwrite a possible environment variable. In the directory gsi_scu/demo-and-test/lm32/ you can find further examples for LM32 with and without using FreeRTOS. Note: For LM32-applications using FreeRTOS the variable USE_RTOS has to be defined in the makefile. In this manner the source files of FreeRTOS will added automatically to the project and the startup code crt0ScuLm32.S becomes correct customized: USE_RTOS = 1. Further the heap-model using by FreeRTOS has to be choose by the makefile variable RTOS_USING_HEAP. E.g.: RTOS_USING_HEAP = 4. For more information about FreeRTOS read the topic "FreeRTOS especially for the LM32 of the GSI-SCU".

The LM32 Build Identification (Build-ID). Respectively which application runs currently on the LM32?

Each LM32- application which was built by the LM32-build- system described above has in the LM32 working memory a information field a so called "build-ID".
This build-ID becomes created automatically during the build process and becomes linked to the LM32 memory at address 0x100 with a length of 1024 bytes.
By the help of this build-ID we obtain information which firmware is currently running on the concerning LM32.
There are two tools available to read this build ID:
  1. eb-info with option -w
  2. lm32-logd with option -B
For more information read also the wiki of the timing group.

For example the input of:

lm32-logd -B scuxl4711

(Note: The SCU-name can be omitted when the log-daemon becomes invoked on the concerning SCU, e.g. login via sss, and not on the ASL-cluster.)

leads to following output:

UserLM32 
Project     : scu3_control_os 
Version     : 4.6.3 * +MIL-DDR3 +LOG +DAQ +DIOB-DAQ +AFGT +MMU 
Git-revision: e176c65 (2023-12-14 15:39:16 +0100) 
Platform    : SCU 3 
Build Date  : Mo Dez 18 16:05:48 CET 2023 
Prepared by : ulrich  <> 
Prepared on : sadpc029 
OS Version  :  Linux 5.14.21-150500.55.39-default x86_64 
Embedded OS : FreeRTOS Kernel: V10.4.6 
Tick-frequ. : 10000 Hz 
GCC Version : lm32-elf-gcc (GSI) 13.1.0 
Opt. level  : s, LTO: Yes 
Log param   : 8 
IntAdrOffs  : 0x10000000 
SharedOffs  : 0x500 
SharedSize  : 24832 
StackSize   : 512
Name (Key) Meaning (Value) Comment
Project Name of the LM32 firmware binary file which has been uploaded. (firmware name)  
Version Version number of the firmware  
Git-revision Git commit ID and commit date  
Platform Device name where the LM32 is implemented e.g. SCU 3 or SCU 4  
Build Date Build date of this firmware  
Prepared by Username which has built this firmware  
Prepsred on PC name on which has build this firmware  
OS Version Version of the OS-kernel in the build PC.  
Embedded OS Version of the FreeRTOS kernel Only if FreeRTOS implemented.
Tick-frequ. Task change frequency in Hz. Only if FreeRTOS implemented.
GCC Version Version of the LM32 cross compiler  
Opt. level Optimization level in which has the crosscompiler built the firmware.  
Log param Number of optional log parameters, e.g.: "%d, %s" and so on...  
IntAdrOffs Offset of the LM32 working memory.  
SharedOffs Relative offset of the shared memory in the working memory.  
SharedSize Length of the shared memory section.  
StackSize Length of te stack section.  
Tip: If you'll obtain for example only the version number of the firmware which runs currently in the SCU, then type this:
lm32-logd -B scuxl4711 | grep "Version     :" | awk '{print $3}'

Or its also possible to read the version number of the firmware directly from the binary file by typing that:

strings <filename of LM32-firmware>.bin | grep "Version     :" | awk '{print $3}'

Automatic source code documentation with Doxygen

The pre-build makefiles are capable to build a source code documentation by using of the netherlands tool Doxygen.

In this case you don't need to worry about the complicated creation of the doxygen configuration file "Doxyfile", this will accomplished by the pre build makefiles.
Makefile command (target) Meaning
make doc Creates the whole source code documentation of the concerned project.
make showdoc Creates the whole source code documentation of the concerned project and invokes the Firefox browser.
make deldoc Deletes all by doxygen created files.
The targed folder for all files created by Doxygen, is determined by the makefile variable DOX_OUTPUT_DIRECTORY. By default this variable has the value:

DOX_OUTPUT_DIRECTORY ?= $(HOME)/Documents/scr_doc/$(TARGET)

Whereby the makefile variable TARGET includes the project name. As shown it's possible to overwrite this makefile variable with your desired target folder.

Each Doxygen configuration variable which are defined in the Doxyfile has its equivalent in the Makefile with the prefix "DOX_" and can be overwritten. By default they are predefined with a meningful value.

An additional older documentation about using of Doxygen written in german by Ludwig Hechler can be found here.

Handling of diagnostic and logging messages created by a LM32-Application via the linux- application "lm32-logd"

A LM32 application can be able to send messages to the linux host.
This can be for example status messages, debug messages, error messages or warning messages and so on.
Typical log messages can look like this:



The latency-time of the LM32-application sending a log-message is very short and non-blocking in contrast to a message via the UART (serial port via mprintf), so that it will not disturbed the timing, because there is no polling routine implemented.

The C-prototypes for the LM32-applikation are defined in the headder lm32_syslog.h

void lm32Log( const unsigned int filter, const char* format, ... );
void vLm32log( const unsigned int filter, const char* format, va_list ap );

The source file lm32_syslog.c has to be added to the LM32 project.

The syntax of the function "lm32Log()" is similar like the known C-function "printf()" with the different that the first parameter is a filter-value defined in lm32_syslog_common.h which identifies the type of log-message. In contrast to printf() is the number of the optional paraneters (e.g.: %d) limited by 8, further parameters will ignored.

Following filter values are already reserved:
Name Value Meaning
LM32_LOG_ERROR 0 Error message
LM32_LOG_WARNING 1 Warning message
LM32_LOG_INFO 2 General information message
LM32_LOG_CMD 3 Command from linux host received
LM32_LOG_DEBUG 4 Debug message respectively trace information
The following code snippet shows a minimum LM32 application using log-messages:
#include <stdbool.h>
#include <lm32_syslog.h>
#include <scu_wr_time.h>

void main( void )
{
   /*
    * Allocates memory in the DDR3 or SRAM for a maximum of
    * 20 messages.
    */
   lm32LogInit( 20 );
   
   uint64_t triggerTime = 0;
   unsigned int c = 0;
   while( true )
   {
      const uint64_t time = getWrSysTime();
      if( time < triggerTime )
         continue;
      triggerTime = time + 100000000000;

      /*
       * Every second appears a new log-message.
       */
      lm32Log( LM32_LOG_INFO, "Count = %u -> %s", c, (c%2 == 0)? "even": "odd" );
      c++;
   }
}

A bit more complex example can be found here.

The LM32- application allocates memory in the DDR3-RAM on SCU3 or in future in SRAM on SCU4 by the memory-tag TAG_LM32_LOG, definned in scu_mmu_tag.h of the SCU- memory management unit (MMU). The function ln32Log() copies the WR-timestamp (64-bit), the first parameter (32-bit filter value), the second parameter (32-bit pointer to the control string) and a maximum of 8 additional 32-bit parameters (depending on the control string) into the SCU-RAM, which is organized as fifo. So a single message item, residing in the SCU-RAM, has a fixed size of twelve 32-bit values respectively a size of six 64-bit values. The following figure shows how a single log-message is organized in the DDR3-RAM of SCU 3 respectively in the future in SRAM of SCU 4:

The LM32 log daemon "lm32-logd"

The final evaluation of the control string will made by the Linux- application "lm32-logd", which reads the characters of the control string from the LM32- working memory and - if necessary - further text strings depending on the control string ("%s"), like the example above.
The Linux- application for LM32- log-messages "lm32-logd" can run as normal linux-applikation or in the background as disk and execution monitor (daemon), depending on the commandline option "-d" or "--daemonize".
Depending of the commandline parameters the lm32-logd can write the LM32-massages normal in "stdout" or in a file or in the syslog-system of the linux host respectively for example in graylog.

For more information read the build-in help of lm32-logd by typing:
lm32-logd -h

The sourcefiles of lm32-logd can be found here.

Proposal how the LM32-log daemon can be used to write messages in a log-file:
/opt/nfsinit/global/tools/lm32-logd -Habd=/var/log/lm32.log
  • The option "H" means that the timestamp shall be readable for humans, otherwise a 64 bit decimal number will printed.
  • The option "a" means that terminal control commands respectively escape sequences will not suppressed. That means for example the messages can be colored.
  • The option "b" means that at the start of the logging the build identification string of the LM32 application will printed in the log-file.
  • The option "d" means that the application lm32-logd shall run as background process as daemon. The optional parameter is the name of the log-file. If this optional parameter not given then the messages becomes written in the linux sys-log system.
The command:
tail -n100 -f /var/log/lm32.log 

makes the log-messages visible in "realtime" similar like the development of linux- kernel drivers.
Topic revision: r20 - 29 May 2024, UlrichBecker
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback