Welcome to the new Parasoft forums! We hope you will enjoy the site and try out some of the new features, like sharing an idea you may have for one of our products or following a category.

Keil uVision Unit Testing ITM Simulator Starter Guide

MichaelC
MichaelC Posts: 28 admin
edited August 2019 in C/C++test

In this tutorial, we'll be going over how to get C++test to run Unit Tests on Keil uVision projects.

  • In this example, I will be using the following:

    • Keil uVision MDK-ARM 5.26
    • C++test 10.4.2
    • Windows 7 64-bit
  • If you are familiar on how to import your Keil project and/or create a bdf file for Keil skip to step 7.

  • I will put a list of common errors that appears when using C++test with Keil at the bottom of this tutorial and way on how to resolve them.

Known Limitation:
MDK-ARM 4.6x and Later
Due to the changes in debugger and compiler libraries (especially Sys I/O lib module - sys_io.o) semihosting must be disabled when building the test executable. Standard symbols (such as ttywrch and _sys_exit) and all I/O _sys... and __std..._name symbols must be retargeted. In addition, MicroLib must be disabled when disabling the test executable.

  • Semihosting is not supported by µVision by extension C++test is not supported with semihosting. More information can be found here and discussed in Step 10:

Keil Compiler Retarget Overview:
https://www.keil.com/pack/doc/compiler/RetargetIO/html/_retarget__overview.html

Runtime Testing with Keil MDK-ARM:
https://docs.parasoft.com/display/CPPDESKE1042/Runtime+Testing+with+Keil+MDK-ARM+Support

  • We'll be focusing on using the C++test Sensor Project. Other projects may need additional configuration to get C++test to collect coverage but this will be a great reference point if you have any issue.

  • The sensor was originally built with Keil uVision 4 but this project will still work if it's converted into a Keil uVision 5 project.

1. Import the Sensor.uvproj file into your Keil uVision IDE.

*This can be done by going to File -> Open and change the file type to Project Files (*.uvproj, *.uvprojx)

2. Switch to the Proper Target Configuration

  • Switch your target configuration to C++test - Simulator if C++test doesn't switch to this by default. You should see a dialog box at towards the top-left of the page and click down to see the other target configuration.

  • This project contains 4 configuration:

    • Simulator
    • MCBSTM32E Flash
    • C++test - MCBSTM32E
    • C++test - Simulator
  • Below is a screenshot on how you can switch between these configurations

  • It's good practice to create a separate target configuration for configuring C++test with Runtime analysis.

  • This can be done by right-clicking on the Target configuration and select Manage Project Items.

  • Next click on the next Project Target icon to create a new Target Configuration this will copy over the settings from your active Target configuration.

3. Configure the Keil Project to output a Batch File

  • C++test needs the Batch output file from Keil uVision can collect the necessary information to build this project and import this project into the Eclipse IDE.

    • This can be done by right-clicking on the Target Configuration Folder and select Options for Target 'C++test - Simulator'

  • Then go to the Output tab and select the box next to Create Batch File this will create a batch file every time you build your project.

4. Ensure that your project meets the minimum stack and heap memory to perform Dynamic Analysis on your project.

  • Minimum Stack Requirement: 0x00002000 (4KB of memory)
  • Minimum Heap Requirement: 0x00002000 (4KB of memory)

5. Build your project.

  • This can be done by right-clicking on your project and select Build Target

6. Launch C++test.

  • We recommend open a command terminal and run the newly generated batch file so that your environment will be configured for C++test and Keil integration.

  • Once the batch file is run open up C++test from the command line using the cpptest.exe found in the C++test Home Directory.

7. Importing the Keil Project into C++test.

  • Parasoft offers two ways to import Keil projects into the Eclipse IDE.

  • Import with a bdf

  • Import via Keil Project

7a. Importing via BDF

*We need to go to the directory we the batch file was generated and run the following command

cpptesttrace --cpptesttraceProjectName=Sensor --cpptesttraceOutputFile=Sensor.bdf --cpptesttraceResponseFileOption="--Via" "C++test - Simulator.BAT"

  • Once the Sensor.bdf has been generated go to your Eclipse IDE and go to File -> New -> Other -> C/C++test -> Create project from a build data file

  • Double-check to make sure that your compiler, linker, Project location, and bdf location are correct then select finish

7b. Importing via Keil Project

  • For importing project with the .uvproj or .uvprojx file is a simpler process.

  • Go to File -> New -> Other -> C/C++test -> Import Keil uVision project

  • Point to the location of your .uvproj or .uvprojx then select next

  • Select the location for the imported project (we recommend using the workspace location if possible)

  • Enabling Use Path Variable to define linker folder locations (if applicable) and re-define the Path Variable Name so that it's easily recognizable and could be shared with other team members.

  • Ensure that Path Variable Value to the hard-coded path of your Keil Project on your machine.

  • In the Project target Settings select Use other build target (if applicable) and select C++test - Simulator

8. Disable instrumentation on all "execution-sensitive" code.

  • This can be done by right-clicking on your source file(s) and go to Parasoft -> C/C++test -> Execution Settings

  • Unselect the Instrument select source file(s) this will prevent C/C++test from replacing hardware set up code during analysis. This can lead to some unexpected behavior if the necessary files are instrumented by C++test.

  • Generally, we would to disable instrumentation for the device library like the STM32-Lib directory. Other examples of code that shouldn't be instrumented are startup code, interrupt handler sources, unsafe code, time-critical code, and order-critical code.

9. Generate a Unit Test for the Sensor.c file.

  • Select the Sensor.c file then go to Parasoft -> Test Configurations -> Builtin -> Unit Testing
    and select the generate Unit Test Test Configuration.

  • If you go to Test Case Explorer you should now a few Unit Tests for each of the methods within the Sensor.c file.

10. Generate Stubs for Sensor.c

  • We are planning on running on Unit Test on this file only so that we can collect coverage. In order to accomplish this will need to isolate the file by replacing the symbols

  • Run the Generate Stubs (File Scope) Test Configuration on Sensor.c. This can be found within Builtin -> Unit Testing -> File Scope

  • A stub directory should appear within your project

  • This will create stubs to replace the symbols that would be used from other files so that we can run Unit Tests on Sensor.c in isolation.

  • Open the Stubs view by going to Parasoft -> Show View -> Stubs

  • Run the Collect Stub Information (File Scope) to check what stub will be used during file scope analysis. This can be found within Builtin -> Unit Testing -> File Scope

11. Retarget your low-level functions and I/O functions.

  • In the Sensor example project, there is an example retarget.c but we will be creating a retarget file to expose you on how you can quickly retarget your project.

  • To create a retarget go to File -> New -> C/C++test -> Runtime - Custom ARM Compilation Tools C Library retargeting

  • If necessary change the Source file Location to the /Sensor/factory location and select Finish.

  • The newly generated retarget file will need to include the fputc(){} function as the retarget file doesn't have this by default.

  • It may be possible that other low-level functions may need to be added to the retargeting file but this should be enough for a vast majority of the time.

12. Creating a User-Defined Test Configuration

  • Go to Parasoft -> Test Configurations -> Builtin -> Keil uVision -> Run Keil uVision Tests - ULINKPro or Simulator (ITM)

  • Right Click on the Test Configuration and select Duplicate

13. Configuring the Test Configuration

  • Select your User-Defined Test Configuration and go to the Execution Tab the following will be checked

  • General Tab: General Configuration Page for Unit Testing/Application Monitoring

    • Instrumentation mode is set up to collect the specific type of coverage
    • Test Execution Flow to make sure that the correct flow is set
      • The Execution Flow requires the following to be correct:
        • uVision Project Executable Location
        • uVision Project file
        • uVision IDE executable file (location to UV4.exe)
        • uVision Project Directory
        • The Executable exit point (function name or address)

  • Symbol Tab: Configuration for the Symbols that C++test will use during analysis

  • For this tutorial we will disable the option Use symbols from additional project files to test our files in isolation

  • C++test will automatically pull from the auto-generated stubs symbols that we created to run our test in isolation

  • Runtime Tab:
  • Most information about this tab can be found within our documentation but there are three sections that are important.

    • Test Cases Debugging options:
    • Select Run Tests in Debugger(*) and select Use External Debugger to create
      breakpoint in the Test Suites to debug any potential issues during runtime. This is
      assuming that you are using cpptest.ini for your uVision target configuration

    • Enable Generate detailed coverage report for: then select Line Coverage

      • Other Coverage types can be enabled if the Instrumentation Mode is configured in
        such a way

        • Archive Test and coverage Results (Experimental) can archive the Quality Tasks and
          Coverage from a prior run.
  • Please refer to our documentation if you would like to go into further detail Execution Tab

Defining How Tests are Executed:
https://docs.parasoft.com/display/CPPDESKE1042/Execution+Tab+Settings+-+Defining+How+Tests+are+Executed

14. Running Unit Tests

  • Go to the Test Case Explorer View and click on the first test case, test_CalcAverage_1

    • Most of these test cases are valid but running Unit Tests on the main function will result in
      an endless loop since it's running in a while loop.
  • Right-click on the desired test case and go to Parasoft -> Test Using -> User-Defined -> Keil uVision -> Run Keil uVision Test - ULINKPro or Simulator (ITM)

15.Verify Results

  • After we accomplish this we should be able to collect coverage from our Unit Tests.

  • We can also take a look into our source code and see which lines are tested.

16. Generate Detailed Coverage Report

  • Click on either the Proceed or the Report Icon at the top-right to generate a report.

  • Click on the option LC Detailed Report to see the Detailed Report.

This concludes the tutorial. Happy testing!

Tip for Embedded Unit Testing

Usually, avoid testing 'main' - it frequently contains initializations, which shouldn't happen multiple times and perhaps some endless loop, common for embedded apps

Common Errors and How to Resolve them

Error: L6236E: No section matches selector - no section to be FIRST/LAST

  • This is normally caused because C/C++test is unable to find the startup_{$TARGET_DEVICE}.o file manually adding this to the C++test Build Settings will resolve this issue.

Error: L6915E: Library reports error: __use_no_semihosting was requested, but _sys_exit was referenced
Error: L6915E: Library reports error: __use_no_semihosting was requested, but _sys_open was referenced
Error: L6915E: Library reports error: __use_no_semihosting was requested, but _ttywrch was referenced

  • This error will occur if step 11 is not done properly.

Error: L6915E: Library reports error: __use_no_semihosting was requested, but fputc was referenced
DISCLAIMER: There are a few C++test symbols that need to be used. The best way to make sure that there are included is to use the correct ARM compiler family settings:

Error: L6200E: Symbol __stdin_name multiply defined (by sys_io.o and harness_cpptest_retgt.o).
Error: L6218E: Undefined symbol exit (referred from CppTestMemory.o).
Error: L6218E: Undefined symbol time (referred from CppTestTime.o).

  • These errors are normally caused when the project is using ARM Compiler 5.0 rather than ARM Compiler 5.0 for uVision. Right-click on your project and go to Properties -> Parasoft -> C/C++test -> Build Settings and verify that your compiler settings is correct.

https://docs.parasoft.com/pages/viewpage.action?pageId=50501985#WorkingwiththeC++testRuntimeLibrary-SymbolsUsedBytheC++testRuntimeLibrarySymbolsUsedBytheC++testRuntimeLibrary

Error 65: Access violation at 0x00000004 : No 'write' permission
(Optional) Modify the uvision_ulinkPro_itm.tja

  • This is usually caused by including the incorrect startup_${device}.o into the linker. Ensure that you're using the correct startup file before doing the following.

  • C++test offers tja which can be used to generate a debugger initialization file used in the analysis. By default, it will generate a cpptest.ini file.

  • The tja file that we are focused on is uvision_ulinkPro_itm.tja as this is the tja file that is used in our test configuration.

  • uvision_ulinkPro_itm.tja can be found within ${CPPTEST_HOME}/engine/etc/templates/for_recipes

  • Below is an example of the changes that I made to the file to Run Unit Tests on my Sensor project.

$if INITIALIZATION_SCRIPT != "":\$
include "$INITIALIZATION_SCRIPT$"
$end\$

LOAD "$TEST_EXECUTABLE$"

MAP 0x01000000, 0x0100FFFF READ // Manually Setting Read Privileges for Memory Range

$if DEBUG == "true":
if len(BRKPTS) > 0:
for b in BRKPTS:
\$
BS \$print b["DIR_MIX"],b["FILE_NAME"],$\$b["LINE"]$
$
end
end
end
\$

ITMLOG 8 > "$RESULTS_LOG$"
G,$TEST_EXEC_EXIT$

$if DEBUG != "true":\$
ITMLOG 8 OFF
EXIT
$end\$

UVISION DEBUGGER: ERROR 65 (ACCESS VIOLATION)
http://www.keil.com/support/docs/814.htm

Comments

  • sketkar
    sketkar Posts: 16
    edited September 2019

    This is great, thanks!

    If you are looking a different approach (uses Keil uVision retargeting compiler feature for Simulator ITM and Keil project import in Parasoft), there is a whitepaper on Static Analysis and Unit Testing which includes integrating Parasoft and Keil uVision Simulator ITM for MDK-ARM Cortex M4. It includes a how-to document and a complete example.

    I put this together as we have many clients/projects that use MDK-ARM Cortex M3 and M4 with Keil uVision and Parasoft. Give it a shot.

    https://www.velentium.com/blog/configuring-parasoft-for-secure-development-of-medical-devices

    Regards,

    Satyajit Ketkar

  • HI
    im having the linking error Error:
    L6200E: Symbol __stdin_name multiply defined (by retarget_io.o and harness_cpptest_retgt.o).
    and I have ARM Compiler 5.0 for uVision selected as compiler do you know what can be the issue?

  • @francciscoespain, please select 'ARM Compiler 5.0 for uVision' for compiler option. Follow all steps mentioned in this article and check if anything missed. I had few issue but resolved after following all steps from this article.