diff --git a/.gitignore b/.gitignore
index 052dcddd65ceeba004894d6d72d2bd4f4d4cc0b2..b803f4ae7009ac3a0d5f56f64a2c953d059eae4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,3 +77,7 @@ vectorcontrol/
 
 # CLion ignores
 .idea
+
+# gcov code coverage
+coverage-html/
+coverage.info
diff --git a/Makefile b/Makefile
index 518c1725d85a656ece67caeffff34afba9076e14..c37610e65acd680e7f47705242611657b18f3a1b 100644
--- a/Makefile
+++ b/Makefile
@@ -257,6 +257,13 @@ run_tests_posix: posix_sitl_default
 
 tests: check_unittest run_tests_posix
 
+tests_coverage:
+	@(PX4_CODE_COVERAGE=1 CCACHE_DISABLE=1 ${MAKE} tests)
+	@(lcov --directory . --capture --quiet --output-file coverage.info)
+	@(lcov --remove coverage.info '/usr/*' --quiet --output-file coverage.info)
+	#@(lcov --list coverage.info)
+	@(genhtml coverage.info --quiet --output-directory coverage-html)
+
 # QGroundControl flashable firmware (currently built by travis-ci)
 qgc_firmware: \
 	check_px4fmu-v1_default \
diff --git a/cmake/common/px4_base.cmake b/cmake/common/px4_base.cmake
index 52922ad8758aff116cc487763e7ffd7cb8827a2e..7ad8254d8a823c94575e21295f1ba63ae6a809b2 100644
--- a/cmake/common/px4_base.cmake
+++ b/cmake/common/px4_base.cmake
@@ -827,6 +827,7 @@ function(px4_add_common_flags)
 		)
 
 	set(added_link_dirs) # none used currently
+	set(added_exe_linker_flags)
 
 	string(TOUPPER ${BOARD} board_upper)
 	string(REPLACE "-" "_" board_config ${board_upper})
@@ -848,6 +849,20 @@ function(px4_add_common_flags)
 			)
 	endif()
 
+	# code coverage
+	if ($ENV{PX4_CODE_COVERAGE} MATCHES "1")
+		message(STATUS "Code coverage build flags enabled")
+		list(APPEND added_cxx_flags
+			-fprofile-arcs -ftest-coverage --coverage -g3 -O0 -fno-elide-constructors -Wno-invalid-offsetof -fno-default-inline -fno-inline
+		)
+		list(APPEND added_c_flags
+			-fprofile-arcs -ftest-coverage --coverage -g3 -O0 -fno-default-inline -fno-inline
+		)
+		list(APPEND added_exe_linker_flags
+			-ftest-coverage --coverage -lgcov
+		)
+	endif()
+
 	# output
 	foreach(var ${inout_vars})
 		string(TOLOWER ${var} lower_var)
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 795902bf18bdb9ccd5969cae23433211d634dc58..0ed8ec9781dd0369d9a8ae93b9631d15173deaae 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -13,11 +13,17 @@ enable_testing()
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -std=gnu99 -g")
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -std=gnu++0x -g -fno-exceptions -fno-rtti -fno-threadsafe-statics -DCONFIG_WCHAR_BUILTIN -D__CUSTOM_FILE_IO__")
 
+# code coverage
+if ($ENV{PX4_CODE_COVERAGE} MATCHES "1")
+	message(STATUS "Code coverage build flags enabled")
+	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage --coverage")
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage")
+endif()
+
 if (NOT PX4_SOURCE_DIR)
 	set(PX4_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
 endif()
 
-
 set(GTEST_DIR ${PX4_SOURCE_DIR}/unittests/googletest)
 add_subdirectory(${GTEST_DIR})
 include_directories(${GTEST_DIR}/include)