diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst
index 46e6d08cf144eb2469f7791090bced69f098fcc2..e5d2b9acb1bb8c61a705cf1fc1501fc459d36a58 100644
--- a/docs/library/pyb.CAN.rst
+++ b/docs/library/pyb.CAN.rst
@@ -82,7 +82,7 @@ Methods
 
    Turn off the CAN bus.
 
-.. method:: can.setfilter(bank, mode, fifo, params)
+.. method:: can.setfilter(bank, mode, fifo, params, \*, rtr)
 
    Configure a filter bank:
 
@@ -107,6 +107,23 @@ Methods
    |CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.|
    +-----------+---------------------------------------------------------+
 
+   - ``rtr`` is an array of booleans that states if a filter should accept a
+     remote transmission request message.  If this argument is not given
+     then it defaults to False for all entries.  The length of the array
+     depends on the ``mode`` argument.
+
+   +-----------+----------------------+
+   |``mode``   |length of rtr array   |
+   +===========+======================+
+   |CAN.LIST16 |4                     |
+   +-----------+----------------------+
+   |CAN.LIST32 |2                     |
+   +-----------+----------------------+
+   |CAN.MASK16 |2                     |
+   +-----------+----------------------+
+   |CAN.MASK32 |1                     |
+   +-----------+----------------------+
+
 .. method:: can.clearfilter(bank)
 
    Clear and disables a filter bank:
@@ -124,15 +141,24 @@ Methods
      - ``fifo`` is an integer, which is the FIFO to receive on
      - ``timeout`` is the timeout in milliseconds to wait for the receive.
 
-   Return value: buffer of data bytes.
+   Return value: A tuple containing four values.
+
+     - The id of the message.
+     - A boolean that indicates if the message is an RTR message.
+     - The FMI (Filter Match Index) value.
+     - An array containing the data.
 
-.. method:: can.send(send, addr, \*, timeout=0)
+.. method:: can.send(data, id, \*, timeout=0, rtr=False)
 
    Send a message on the bus:
 
-     - ``send`` is the data to send (an integer to send, or a buffer object).
-     - ``addr`` is the address to send to
+     - ``data`` is the data to send (an integer to send, or a buffer object).
+     - ``id`` is the id of the message to be sent.
      - ``timeout`` is the timeout in milliseconds to wait for the send.
+     - ``rtr`` is a boolean that specifies if the message shall be sent as
+       a remote transmission request.  If ``rtr`` is True then only the length
+       of ``data`` is used to fill in the DLC slot of the frame; the actual
+       bytes in ``data`` are unused.
 
      If timeout is 0 the message is placed in a buffer in one of three hardware
      buffers and the method returns immediately. If all three buffers are in use
diff --git a/stmhal/can.c b/stmhal/can.c
index f60f79532da01fee0a20f055e3781df77bbe8eb7..f4758399cec6010343ea6e72e8cc23b4b653e87b 100644
--- a/stmhal/can.c
+++ b/stmhal/can.c
@@ -436,9 +436,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_can_any_obj, pyb_can_any);
 /// Return value: `None`.
 STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     static const mp_arg_t allowed_args[] = {
-        { MP_QSTR_send,    MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
-        { MP_QSTR_addr,    MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
+        { MP_QSTR_data,    MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_id,      MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
         { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
+        { MP_QSTR_rtr,     MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
     };
 
     // parse args
@@ -464,11 +465,16 @@ STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
         tx_msg.StdId = args[1].u_int & 0x7FF;
         tx_msg.IDE = CAN_ID_STD;
     }
-    tx_msg.RTR = CAN_RTR_DATA;
+    if (args[3].u_bool == false) {
+        tx_msg.RTR = CAN_RTR_DATA;
+    } else  {
+        tx_msg.RTR = CAN_RTR_REMOTE;
+    }
     tx_msg.DLC = bufinfo.len;
     for (mp_uint_t i = 0; i < bufinfo.len; i++) {
         tx_msg.Data[i] = ((byte*)bufinfo.buf)[i]; // Data is uint32_t but holds only 1 byte
     }
+
     self->can.pTxMsg = &tx_msg;
     HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[2].u_int);
 
@@ -543,7 +549,7 @@ STATIC mp_obj_t pyb_can_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
     } else {
         tuple->items[0] = MP_OBJ_NEW_SMALL_INT(rx_msg.ExtId);
     }
-    tuple->items[1] = MP_OBJ_NEW_SMALL_INT(rx_msg.RTR);
+    tuple->items[1] = rx_msg.RTR == CAN_RTR_REMOTE ? mp_const_true : mp_const_false;
     tuple->items[2] = MP_OBJ_NEW_SMALL_INT(rx_msg.FMI);
     vstr_t vstr;
     vstr_init_len(&vstr, rx_msg.DLC);
@@ -597,6 +603,7 @@ STATIC mp_obj_t pyb_can_setfilter(mp_uint_t n_args, const mp_obj_t *pos_args, mp
         { MP_QSTR_mode,     MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
         { MP_QSTR_fifo,     MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_FILTER_FIFO0} },
         { MP_QSTR_params,   MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+        { MP_QSTR_rtr,      MP_ARG_KW_ONLY  | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
     };
 
     // parse args
@@ -605,8 +612,14 @@ STATIC mp_obj_t pyb_can_setfilter(mp_uint_t n_args, const mp_obj_t *pos_args, mp
     mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
 
     mp_uint_t len;
+    mp_uint_t rtr_len;
+    mp_uint_t rtr_masks[4] = {0, 0, 0, 0};
+    mp_obj_t *rtr_flags;
     mp_obj_t *params;
     mp_obj_get_array(args[3].u_obj, &len, &params);
+    if (args[4].u_obj != MP_OBJ_NULL){
+        mp_obj_get_array(args[4].u_obj, &rtr_len, &rtr_flags);
+    }
 
     CAN_FilterConfTypeDef filter;
     if (args[1].u_int == MASK16 || args[1].u_int == LIST16) {
@@ -615,15 +628,41 @@ STATIC mp_obj_t pyb_can_setfilter(mp_uint_t n_args, const mp_obj_t *pos_args, mp
         }
         filter.FilterScale = CAN_FILTERSCALE_16BIT;
         if (self->extframe) {
-            filter.FilterIdLow      = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[0])); // id1
-            filter.FilterMaskIdLow  = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[1])); // mask1
-            filter.FilterIdHigh     = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])); // id2
-            filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])); // mask2
-        } else {
-            filter.FilterIdLow      = mp_obj_get_int(params[0]) << 5; // id1
-            filter.FilterMaskIdLow  = mp_obj_get_int(params[1]) << 5; // mask1
-            filter.FilterIdHigh     = mp_obj_get_int(params[2]) << 5; // id2
-            filter.FilterMaskIdHigh = mp_obj_get_int(params[3]) << 5; // mask2
+            if (args[4].u_obj != MP_OBJ_NULL) {
+                if (args[1].u_int == MASK16) {
+                    rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
+                    rtr_masks[1] = 0x02;
+                    rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
+                    rtr_masks[3] = 0x02;
+                } else {  // LIST16
+                    rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
+                    rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
+                    rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x02 : 0;
+                    rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x02 : 0;
+                }
+            }
+            filter.FilterIdLow      = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[0])) | rtr_masks[0]; // id1
+            filter.FilterMaskIdLow  = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[1])) | rtr_masks[1]; // mask1
+            filter.FilterIdHigh     = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[2])) | rtr_masks[2]; // id2
+            filter.FilterMaskIdHigh = EXTENDED_ID_TO_16BIT_FILTER(mp_obj_get_int(params[3])) | rtr_masks[3]; // mask2
+        } else { // Basic frames
+            if (args[4].u_obj != MP_OBJ_NULL) {
+                if (args[1].u_int == MASK16) {
+                    rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0;
+                    rtr_masks[1] = 0x10;
+                    rtr_masks[2] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0;
+                    rtr_masks[3] = 0x10;
+                } else {  // LIST16
+                    rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x10 : 0;
+                    rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x10 : 0;
+                    rtr_masks[2] = mp_obj_get_int(rtr_flags[2]) ? 0x10 : 0;
+                    rtr_masks[3] = mp_obj_get_int(rtr_flags[3]) ? 0x10 : 0;
+                }
+            }
+            filter.FilterIdLow      = (mp_obj_get_int(params[0]) << 5) | rtr_masks[0]; // id1
+            filter.FilterMaskIdLow  = (mp_obj_get_int(params[1]) << 5) | rtr_masks[1]; // mask1
+            filter.FilterIdHigh     = (mp_obj_get_int(params[2]) << 5) | rtr_masks[2]; // id2
+            filter.FilterMaskIdHigh = (mp_obj_get_int(params[3]) << 5) | rtr_masks[3]; // mask2
         }
         if (args[1].u_int == MASK16) {
             filter.FilterMode  = CAN_FILTERMODE_IDMASK;
@@ -636,12 +675,20 @@ STATIC mp_obj_t pyb_can_setfilter(mp_uint_t n_args, const mp_obj_t *pos_args, mp
         if (len != 2) {
             goto error;
         }
-        filter.FilterScale      = CAN_FILTERSCALE_32BIT;
-
+        filter.FilterScale = CAN_FILTERSCALE_32BIT;
+        if (args[4].u_obj != MP_OBJ_NULL) {
+            if (args[1].u_int == MASK32) {
+                rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
+                rtr_masks[1] = 0x02;
+            } else {  // LIST32
+                rtr_masks[0] = mp_obj_get_int(rtr_flags[0]) ? 0x02 : 0;
+                rtr_masks[1] = mp_obj_get_int(rtr_flags[1]) ? 0x02 : 0;
+            }
+        }
         filter.FilterIdHigh     = (mp_obj_get_int(params[0]) & 0xFF00)  >> 13;
-        filter.FilterIdLow      = ((mp_obj_get_int(params[0]) & 0x00FF) << 3) | 4;
+        filter.FilterIdLow      = (((mp_obj_get_int(params[0]) & 0x00FF) << 3) | 4) | rtr_masks[0];
         filter.FilterMaskIdHigh = (mp_obj_get_int(params[1]) & 0xFF00 ) >> 13;
-        filter.FilterMaskIdLow  = ((mp_obj_get_int(params[1]) & 0x00FF) << 3) | 4;
+        filter.FilterMaskIdLow  = (((mp_obj_get_int(params[1]) & 0x00FF) << 3) | 4) | rtr_masks[1];
         if (args[1].u_int == MASK32) {
             filter.FilterMode  = CAN_FILTERMODE_IDMASK;
         }
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
index e992f545ba62fcf453e8741dddc66940d0b5e786..3c265b616dab720d704e412321bb279a5405f6e0 100644
--- a/stmhal/qstrdefsport.h
+++ b/stmhal/qstrdefsport.h
@@ -213,6 +213,7 @@ Q(initfilterbanks)
 Q(clearfilter)
 Q(setfilter)
 Q(rxcallback)
+Q(rtr)
 Q(NORMAL)
 Q(LOOPBACK)
 Q(SILENT)
diff --git a/tests/pyb/can.py b/tests/pyb/can.py
index 5fd4d39d05d328fceb6bd9ae473e1f139ee96e8e..63a3be4e925fd8b372b7a579ba1c0d155863bf37 100644
--- a/tests/pyb/can.py
+++ b/tests/pyb/can.py
@@ -151,3 +151,40 @@ except OSError as e:
 pyb.delay(500)
 while can.any(0):
     print(can.recv(0))
+
+# Testing rtr messages
+bus1 = CAN(1, CAN.LOOPBACK)
+bus2 = CAN(2, CAN.LOOPBACK, extframe = True)
+while bus1.any(0):
+    bus1.recv(0)
+while bus2.any(0):
+    bus2.recv(0)
+bus1.setfilter(0, CAN.LIST16, 0, (1, 2, 3, 4))
+bus1.setfilter(1, CAN.LIST16, 0, (5, 6, 7, 8), rtr=(True, True, True, True))
+bus1.setfilter(2, CAN.MASK16, 0, (64, 64, 32, 32), rtr=(False, True))
+bus2.setfilter(0, CAN.LIST32, 0, (1, 2), rtr=(True, True))
+bus2.setfilter(1, CAN.LIST32, 0, (3, 4), rtr=(True, False))
+bus2.setfilter(2, CAN.MASK32, 0, (16, 16), rtr=(False,))
+bus2.setfilter(2, CAN.MASK32, 0, (32, 32), rtr=(True,))
+
+bus1.send('',1,rtr=True)
+print(bus1.any(0))
+bus1.send('',5,rtr=True)
+print(bus1.recv(0))
+bus1.send('',6,rtr=True)
+print(bus1.recv(0))
+bus1.send('',7,rtr=True)
+print(bus1.recv(0))
+bus1.send('',16,rtr=True)
+print(bus1.any(0))
+bus1.send('',32,rtr=True)
+print(bus1.recv(0))
+
+bus2.send('',1,rtr=True)
+print(bus2.recv(0))
+bus2.send('',2,rtr=True)
+print(bus2.recv(0))
+bus2.send('',3,rtr=True)
+print(bus2.recv(0))
+bus2.send('',4,rtr=True)
+print(bus2.any(0))
diff --git a/tests/pyb/can.py.exp b/tests/pyb/can.py.exp
index 845f6d5ba16e83794829d2942cb0fbde395ea2a3..ec6f97ea02b5525ebc359bfc509b51ea1c149aa7 100644
--- a/tests/pyb/can.py.exp
+++ b/tests/pyb/can.py.exp
@@ -2,9 +2,9 @@ CAN(1)
 CAN(1, CAN.LOOPBACK, extframe=False)
 False
 True
-(123, 0, 0, b'abcd')
-(2047, 0, 0, b'abcd')
-(0, 0, 0, b'abcd')
+(123, False, 0, b'abcd')
+(2047, False, 0, b'abcd')
+(0, False, 0, b'abcd')
 passed
 CAN(1, CAN.LOOPBACK, extframe=True)
 passed
@@ -20,21 +20,31 @@ cb1
 full
 cb1a
 overflow
-(1, 0, 0, b'11111111')
-(2, 0, 1, b'22222222')
-(4, 0, 3, b'44444444')
-(5, 0, 0, b'55555555')
-(6, 0, 1, b'66666666')
-(8, 0, 3, b'88888888')
+(1, False, 0, b'11111111')
+(2, False, 1, b'22222222')
+(4, False, 3, b'44444444')
+(5, False, 0, b'55555555')
+(6, False, 1, b'66666666')
+(8, False, 3, b'88888888')
 cb0a
 pending
 cb1a
 pending
-(1, 0, 0, b'11111111')
-(5, 0, 0, b'55555555')
+(1, False, 0, b'11111111')
+(5, False, 0, b'55555555')
 False
-(1, 0, 0, b'abcde')
+(1, False, 0, b'abcde')
 passed
-(2, 0, 0, b'abcde')
-(3, 0, 0, b'abcde')
-(4, 0, 0, b'abcde')
+(2, False, 0, b'abcde')
+(3, False, 0, b'abcde')
+(4, False, 0, b'abcde')
+False
+(5, True, 4, b'')
+(6, True, 5, b'')
+(7, True, 6, b'')
+False
+(32, True, 9, b'')
+(1, True, 0, b'')
+(2, True, 1, b'')
+(3, True, 2, b'')
+False