diff --git a/Documentation/pycardium/utime.rst b/Documentation/pycardium/utime.rst
index ebcff6ccbc518d593431797fb5d66c580e8201e3..a2900145d06d197b9492c57d3269fd7b152cb5b1 100644
--- a/Documentation/pycardium/utime.rst
+++ b/Documentation/pycardium/utime.rst
@@ -28,6 +28,11 @@ alarm.
    Return the current timestamp in seconds since 2000-01-01 00:00 in
    the local timezone.
 
+.. py:function:: time_ms()
+
+   Return the current timestamp in milliseconds since 2000-01-01 00:00 in
+   the local timezone.
+
 .. py:function:: set_time(secs)
 
    Sets the time to ``secs`` seconds since 2000-01-01 00:00 in the local
diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 60f008a33f8ba4271384af19a7ae0844a856ce23..043b0e4bac8745a02dc0ae97ff29a61e135f9810 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -79,6 +79,7 @@ typedef _Bool bool;
 #define API_RTC_GET_SECONDS        0x50
 #define API_RTC_SCHEDULE_ALARM     0x51
 #define API_RTC_SET_MILLISECONDS   0x52
+#define API_RTC_GET_MILLISECONDS   0x53
 
 #define API_LEDS_SET               0x60
 #define API_LEDS_SET_HSV           0x61
@@ -1577,6 +1578,13 @@ API(API_FILE_MKDIR, int epic_file_mkdir(const char *dirname));
  */
 API(API_RTC_GET_SECONDS, uint32_t epic_rtc_get_seconds(void));
 
+/**
+ * Read the current RTC value in ms.
+ *
+ * :return: Unix time in milliseconds
+ */
+API(API_RTC_GET_MILLISECONDS, uint64_t epic_rtc_get_milliseconds(void));
+
 /**
  * Sets the current RTC time in milliseconds
  */
diff --git a/epicardium/modules/rtc.c b/epicardium/modules/rtc.c
index 8aa2e3f650cb236f8cae4de106bbcfaeca004333..de1ef70d26653a8b1f2441b8bf6a62a3d0124ef7 100644
--- a/epicardium/modules/rtc.c
+++ b/epicardium/modules/rtc.c
@@ -25,6 +25,16 @@ uint32_t epic_rtc_get_seconds(void)
 	return sec;
 }
 
+uint64_t epic_rtc_get_milliseconds(void)
+{
+	uint32_t sec, subsec;
+
+	while (RTC_GetTime(&sec, &subsec) == E_BUSY) {
+		vTaskDelay(pdMS_TO_TICKS(4));
+	}
+	return subsec * 1000ULL / 4096 + sec * 1000ULL;
+}
+
 void epic_rtc_set_milliseconds(uint64_t milliseconds)
 {
 	uint32_t sec, subsec;
diff --git a/pycardium/modules/qstrdefs.h b/pycardium/modules/qstrdefs.h
index 5c9c63a17f50dcf976d2001f641feb3ce274b86d..d789c8730c42f68925b4d058fe35e93449b2e4bb 100644
--- a/pycardium/modules/qstrdefs.h
+++ b/pycardium/modules/qstrdefs.h
@@ -47,6 +47,7 @@ Q(ticks_diff)
 Q(localtime)
 Q(mktime)
 Q(time)
+Q(time_ms)
 Q(set_time)
 Q(set_unix_time)
 
diff --git a/pycardium/modules/utime.c b/pycardium/modules/utime.c
index 4578d9971902cfd1d2a9e7edc0e5d939ad8a5a75..88fe86b9ad2933d1f5e109e0113cf24453be69d3 100644
--- a/pycardium/modules/utime.c
+++ b/pycardium/modules/utime.c
@@ -42,6 +42,15 @@ static mp_obj_t time_time(void)
 }
 MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time);
 
+static mp_obj_t time_time_ms(void)
+{
+	uint64_t milliseconds;
+	milliseconds = epic_rtc_get_milliseconds() -
+		       (EPOCH_OFFSET + TZONE_OFFSET) * 1000ULL;
+	return mp_obj_new_int_from_ull(milliseconds);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(time_time_ms_obj, time_time_ms);
+
 static mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args)
 {
 	mp_int_t seconds;
@@ -120,6 +129,7 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(time_alarm_obj, 1, 2, time_alarm);
 static const mp_rom_map_elem_t time_module_globals_table[] = {
 	{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
 	{ MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&time_time_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_time_ms), MP_ROM_PTR(&time_time_ms_obj) },
 	{ MP_ROM_QSTR(MP_QSTR_set_time), MP_ROM_PTR(&time_set_time_obj) },
 	{ MP_ROM_QSTR(MP_QSTR_set_unix_time),
 	  MP_ROM_PTR(&time_set_unix_time_obj) },