diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp
index 40fadaa2f004632771d523c61e670e18b93fd61d..33c7b7e86a586d2bc89af6f75ce4b47a78a453e8 100644
--- a/cores/arduino/USB/CDC.cpp
+++ b/cores/arduino/USB/CDC.cpp
@@ -160,25 +160,26 @@ void Serial_::end(void)
 
 void Serial_::accept(void)
 {
-	ring_buffer *buffer = &cdc_rx_buffer;
-	uint32_t i = (uint32_t)(buffer->head+1) % CDC_SERIAL_BUFFER_SIZE;
+	uint8_t buffer[CDC_SERIAL_BUFFER_SIZE];
+	uint32_t len = USBD_Recv(CDC_ENDPOINT_OUT, (void*)&buffer, CDC_SERIAL_BUFFER_SIZE);
+
+	noInterrupts();
+	ring_buffer *ringBuffer = &cdc_rx_buffer;
+	uint32_t i = ringBuffer->head;
 
 	// if we should be storing the received character into the location
 	// just before the tail (meaning that the head would advance to the
 	// current location of the tail), we're about to overflow the buffer
 	// and so we don't write the character or advance the head.
-	while (i != buffer->tail) {
-		uint32_t c;
-		if (!USBD_Available(CDC_ENDPOINT_OUT)) {
-            UDD_ReleaseRX(CDC_ENDPOINT_OUT);
-			break;
-		}
-		c = USBD_Recv(CDC_ENDPOINT_OUT);
-		buffer->buffer[buffer->head] = c;
-		buffer->head = i;
-
+	uint32_t k = 0;
+	i = (i + 1) % CDC_SERIAL_BUFFER_SIZE;
+	while (i != ringBuffer->tail && len>0) {
+		len--;
+		ringBuffer->buffer[ringBuffer->head] = buffer[k++];
+		ringBuffer->head = i;
 		i = (i + 1) % CDC_SERIAL_BUFFER_SIZE;
 	}
+	interrupts();
 }
 
 int Serial_::available(void)
diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp
index 41285d4f056afc97a551a414a9402cd906dbdf5a..8164f25236fd5e19e85b0a5203b33e006f1e83d9 100644
--- a/cores/arduino/USB/USBCore.cpp
+++ b/cores/arduino/USB/USBCore.cpp
@@ -108,12 +108,17 @@ uint32_t USBD_Recv(uint32_t ep, void* d, uint32_t len)
 	if (!_usbConfiguration)
 		return -1;
 
-	uint32_t n = UDD_FifoByteCount(ep);
-	len = min(n,len);
-	n = len;
-	uint8_t* dst = (uint8_t*)d;
-	while (n--)
-		*dst++ = UDD_Recv_data(ep, 8);
+	uint8_t *buffer;
+	uint8_t *data = (uint8_t *)d;
+
+	len = min(UDD_FifoByteCount(ep), len);
+
+	UDD_Recv_data(ep, len);
+	UDD_Recv(ep, &buffer);
+	for (uint32_t i=0; i<len; i++) {
+		data[i] = buffer[i];
+	}
+
 	if (len && !UDD_FifoByteCount(ep)) // release empty buffer
 		UDD_ReleaseRX(ep);
 
diff --git a/cores/arduino/USB/samd21_device.c b/cores/arduino/USB/samd21_device.c
index 82342405f2a17b08e4c55b27d72b50ea441d786c..271243a3da774aa466e7c29740eda252ba6df705 100644
--- a/cores/arduino/USB/samd21_device.c
+++ b/cores/arduino/USB/samd21_device.c
@@ -266,22 +266,23 @@ uint32_t UDD_Send(uint32_t ep, const void* data, uint32_t len)
 	return len;
 }
 
-uint8_t UDD_Recv_data(uint32_t ep, uint32_t len)
-{
-	TRACE_DEVICE(printf("=> UDD_Recvdata : ep=%d\r\n", (char)ep);)
-
-	usb_endpoint_table[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[ep];
-	usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = len;
-	usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0;
+uint8_t UDD_Recv_data(uint32_t ep, uint32_t len)
+{
+	TRACE_DEVICE(printf("=> UDD_Recvdata : ep=%d\r\n", (char)ep);)
+
+	if (len>64) len=64;
+	usb_endpoint_table[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[ep];
+	usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = len;
+	usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0;
 	udd_OUT_transfer_allowed(ep);
-	TRACE_DEVICE(printf("=> UDD_Recv_data : data=%lu\r\n", (unsigned long)data);)
-
-	/* Wait for transfer to complete */
-	while (!udd_is_OUT_transf_cplt(ep));
-	/* Clear Transfer complete 0 flag */
-	udd_clear_OUT_transf_cplt(ep);
-
-	return udd_ep_out_cache_buffer[ep][0];
+	TRACE_DEVICE(printf("=> UDD_Recv_data : data=%lu\r\n", (unsigned long)data);)
+
+	/* Wait for transfer to complete */
+	while (!udd_is_OUT_transf_cplt(ep));
+	/* Clear Transfer complete 0 flag */
+	udd_clear_OUT_transf_cplt(ep);
+
+	return udd_ep_out_cache_buffer[ep][0];
 }
 
 void UDD_Recv(uint32_t ep, uint8_t** ppData)