From 729a9f55fc815fbe2bcb64ca9f447755c2645779 Mon Sep 17 00:00:00 2001
From: etagle <ejtagle@hotmail.com>
Date: Thu, 28 Dec 2017 03:32:46 -0300
Subject: [PATCH] Improved Sw SPI on DUE HAL a bit more.

Now the USB MSD can transfer at 750k/s. Previously, it was 500k/s. I think this is the maximum achievable speed using Sw SPI.
---
 Marlin/src/HAL/HAL_DUE/HAL_spi_Due.cpp | 327 ++++++++++++++++++------
 Marlin/src/HAL/HAL_DUE/usb/conf_usb.h  |  55 ++--
 Marlin/src/HAL/HAL_DUE/usb/usb_task.c  | 335 ++++++++++++++++---------
 Marlin/src/HAL/HAL_DUE/usb/usb_task.h  |  14 +-
 4 files changed, 510 insertions(+), 221 deletions(-)

diff --git a/Marlin/src/HAL/HAL_DUE/HAL_spi_Due.cpp b/Marlin/src/HAL/HAL_DUE/HAL_spi_Due.cpp
index 30386661b7..95123615c0 100644
--- a/Marlin/src/HAL/HAL_DUE/HAL_spi_Due.cpp
+++ b/Marlin/src/HAL/HAL_DUE/HAL_spi_Due.cpp
@@ -111,6 +111,9 @@
   #define DELAY_NS(x) DELAY_CYCLES( (x) * (F_CPU/1000000) / 1000)
 
   typedef uint8_t (*pfnSpiTransfer) (uint8_t b);
+  typedef void    (*pfnSpiRxBlock)(uint8_t* buf, uint32_t nbyte);
+  typedef void    (*pfnSpiTxBlock)(const uint8_t* buf, uint32_t nbyte);
+
 
   /* ---------------- Macros to be able to access definitions from asm */
 
@@ -183,26 +186,32 @@
       /* Bit 0 */
       " str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]" "\n\t"  /* Access the proper SODR or CODR registers based on that bit */
       " str %[sck_mask],[%[sck_port]]" "\n\t"                   /* SODR */
-      " nop"  "\n\t"
+      " nop" "\n\t"                                             /* Result will be 0 */
       " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"              /* CODR */
 
-      : [mosi_mask]"+r"( MOSI_MASK ),
-        [mosi_port]"+r"( MOSI_PORT_PLUS30 ),
-        [sck_mask]"+r"( SCK_MASK ),
-        [sck_port]"+r"( SCK_PORT_PLUS30 ),
-        [idx]"+r"( idx ),
-        [txval]"+r"( bout )
-      :
+      : [idx]"+r"( idx )
+      : [txval]"r"( bout ) ,
+        [mosi_mask]"r"( MOSI_MASK ),
+        [mosi_port]"r"( MOSI_PORT_PLUS30 ),
+        [sck_mask]"r"( SCK_MASK ),
+        [sck_port]"r"( SCK_PORT_PLUS30 )
       : "cc"
     );
 
     return 0;
   }
 
+ // Calculates the bit band alias address and returns a pointer address to word.
+ // addr: The byte address of bitbanding bit.
+ // bit:  The bit position of bitbanding bit.
+#define BITBAND_ADDRESS(addr, bit) \
+    (((uint32_t)(addr) & 0xF0000000) + 0x02000000 + ((uint32_t)(addr)&0xFFFFF)*32 + (bit)*4)
+
   // run at ~8 .. ~10Mhz - Rx version (Tx line not altered)
   static uint8_t spiTransferRx0(uint8_t bout) { // using Mode 0
-    int bin = 0, work = 0;
-    register uint32_t MISO_PORT_PLUS3C = ((uint32_t) PORT(MISO_PIN)) + 0x3C;  /* PDSR of port */
+    register uint32_t bin;
+    register uint32_t work;
+    register uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(MISO_PIN))+0x3C, PIN_SHIFT(MISO_PIN));  /* PDSR of port in bitband area */
     register uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30;    /* SODR of port */
     register uint32_t SCK_MASK = PIN_MASK(SCK_PIN);
     UNUSED(bout);
@@ -213,70 +222,61 @@
 
       /* bit 7 */
       " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
-      " ldr %[work],[%[miso_port]]" "\n\t"              /* PDSR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
       " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
-      " lsrs %[work],%[work],%[miso_shift]" "\n\t"      /* Isolate input into carry */
-      " adc %[bin],%[bin],%[bin]" "\n\t"                /* Shift left result and add the carry */
+      " bfi %[bin],%[work],#7,#1" "\n\t"                /* Store read bit as the bit 7 */
 
       /* bit 6 */
       " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
-      " ldr %[work],[%[miso_port]]" "\n\t"              /* PDSR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
       " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
-      " lsrs %[work],%[work],%[miso_shift]" "\n\t"      /* Isolate input into carry */
-      " adc %[bin],%[bin],%[bin]" "\n\t"                /* Shift left result and add the carry */
+      " bfi %[bin],%[work],#6,#1" "\n\t"                /* Store read bit as the bit 6 */
 
       /* bit 5 */
       " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
-      " ldr %[work],[%[miso_port]]" "\n\t"              /* PDSR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
       " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
-      " lsrs %[work],%[work],%[miso_shift]" "\n\t"      /* Isolate input into carry */
-      " adc %[bin],%[bin],%[bin]" "\n\t"                /* Shift left result and add the carry */
+      " bfi %[bin],%[work],#5,#1" "\n\t"                /* Store read bit as the bit 5 */
 
       /* bit 4 */
       " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
-      " ldr %[work],[%[miso_port]]" "\n\t"              /* PDSR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
       " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
-      " lsrs %[work],%[work],%[miso_shift]" "\n\t"      /* Isolate input into carry */
-      " adc %[bin],%[bin],%[bin]" "\n\t"                /* Shift left result and add the carry */
+      " bfi %[bin],%[work],#4,#1" "\n\t"                /* Store read bit as the bit 4 */
 
       /* bit 3 */
       " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
-      " ldr %[work],[%[miso_port]]" "\n\t"              /* PDSR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
       " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
-      " lsrs %[work],%[work],%[miso_shift]" "\n\t"      /* Isolate input into carry */
-      " adc %[bin],%[bin],%[bin]" "\n\t"                /* Shift left result and add the carry */
+      " bfi %[bin],%[work],#3,#1" "\n\t"                /* Store read bit as the bit 3 */
 
       /* bit 2 */
       " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
-      " ldr %[work],[%[miso_port]]" "\n\t"              /* PDSR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
       " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
-      " lsrs %[work],%[work],%[miso_shift]" "\n\t"      /* Isolate input into carry */
-      " adc %[bin],%[bin],%[bin]" "\n\t"                /* Shift left result and add the carry */
+      " bfi %[bin],%[work],#2,#1" "\n\t"                /* Store read bit as the bit 2 */
 
       /* bit 1 */
       " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
-      " ldr %[work],[%[miso_port]]" "\n\t"              /* PDSR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
       " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
-      " lsrs %[work],%[work],%[miso_shift]" "\n\t"      /* Isolate input into carry */
-      " adc %[bin],%[bin],%[bin]" "\n\t"                /* Shift left result and add the carry */
+      " bfi %[bin],%[work],#1,#1" "\n\t"                /* Store read bit as the bit 1 */
 
       /* bit 0 */
       " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
-      " ldr %[work],[%[miso_port]]" "\n\t"              /* PDSR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
       " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
-      " lsrs %[work],%[work],%[miso_shift]" "\n\t"      /* Isolate input into carry */
-      " adc %[bin],%[bin],%[bin]" "\n\t"                /* Shift left result and add the carry */
+      " bfi %[bin],%[work],#0,#1" "\n\t"                /* Store read bit as the bit 0 */
 
-      : [miso_port]"+r"( MISO_PORT_PLUS3C ),
-        [sck_mask]"+r"( SCK_MASK ),
-        [sck_port]"+r"( SCK_PORT_PLUS30 ),
-        [bin]"+r"(bin),
+      : [bin]"+r"(bin),
         [work]"+r"(work)
-      : [miso_shift]"M"( PIN_SHIFT(MISO_PIN) + 1 )      /* So we move to the carry */
+      : [bitband_miso_port]"r"( BITBAND_MISO_PORT ),
+        [sck_mask]"r"( SCK_MASK ),
+        [sck_port]"r"( SCK_PORT_PLUS30 )
       : "cc"
     );
 
-    return (uint8_t)bin;
+    return bin;
   }
 
   // run at ~4Mhz
@@ -317,10 +317,182 @@
     return b;
   }
 
-  // Pointers to generic functions
+  // Pointers to generic functions for byte transfers
   static pfnSpiTransfer spiTransferTx = spiTransferX;
   static pfnSpiTransfer spiTransferRx = spiTransferX;
 
+  // Block transfers run at ~8 .. ~10Mhz - Tx version (Rx data discarded)
+  static void spiTxBlock0(const uint8_t* ptr, uint32_t todo) {
+    register uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(MOSI_PIN)) + 0x30;  /* SODR of port */
+    register uint32_t MOSI_MASK = PIN_MASK(MOSI_PIN);
+    register uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30;    /* SODR of port */
+    register uint32_t SCK_MASK = PIN_MASK(SCK_PIN);
+    register uint32_t work;
+    register uint32_t txval;
+
+    /* The software SPI routine */
+    __asm__ __volatile__(
+      ".syntax unified" "\n\t" // is to prevent CM0,CM1 non-unified syntax
+
+      " loop%=:" "\n\t"
+      " ldrb.w %[txval], [%[ptr]], #1" "\n\t"                   /* Load value to send, increment buffer */
+      " mvn %[txval],%[txval]" "\n\t"                           /* Negate value */
+
+      /* Bit 7 */
+      " ubfx %[work],%[txval],#7,#1" "\n\t"                     /* Place bit 7 in bit 0 of work*/
+
+      " str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"                   /* SODR */
+      " ubfx %[work],%[txval],#6,#1" "\n\t"                     /* Place bit 6 in bit 0 of work*/
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"              /* CODR */
+
+      /* Bit 6 */
+      " str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"                   /* SODR */
+      " ubfx %[work],%[txval],#5,#1" "\n\t"                     /* Place bit 5 in bit 0 of work*/
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"              /* CODR */
+
+      /* Bit 5 */
+      " str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"                   /* SODR */
+      " ubfx %[work],%[txval],#4,#1" "\n\t"                     /* Place bit 4 in bit 0 of work*/
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"              /* CODR */
+
+      /* Bit 4 */
+      " str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"                   /* SODR */
+      " ubfx %[work],%[txval],#3,#1" "\n\t"                     /* Place bit 3 in bit 0 of work*/
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"              /* CODR */
+
+      /* Bit 3 */
+      " str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"                   /* SODR */
+      " ubfx %[work],%[txval],#2,#1" "\n\t"                     /* Place bit 2 in bit 0 of work*/
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"              /* CODR */
+
+      /* Bit 2 */
+      " str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"                   /* SODR */
+      " ubfx %[work],%[txval],#1,#1" "\n\t"                     /* Place bit 1 in bit 0 of work*/
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"              /* CODR */
+
+      /* Bit 1 */
+      " str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"                   /* SODR */
+      " ubfx %[work],%[txval],#0,#1" "\n\t"                     /* Place bit 0 in bit 0 of work*/
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"              /* CODR */
+
+      /* Bit 0 */
+      " str %[mosi_mask],[%[mosi_port], %[work],LSL #2]" "\n\t"  /* Access the proper SODR or CODR registers based on that bit */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"                   /* SODR */
+      " subs %[todo],#1" "\n\t"                                 /* Decrement count of pending words to send, update status */
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"              /* CODR */
+      " bne.n loop%=" "\n\t"                                    /* Repeat until done */
+
+      : [ptr]"+r" ( ptr ) ,
+        [todo]"+r" ( todo ) ,
+        [work]"+r"( work ) ,
+        [txval]"+r"( txval )
+      : [mosi_mask]"r"( MOSI_MASK ),
+        [mosi_port]"r"( MOSI_PORT_PLUS30 ),
+        [sck_mask]"r"( SCK_MASK ),
+        [sck_port]"r"( SCK_PORT_PLUS30 )
+      : "cc"
+    );
+  }
+
+  static void spiRxBlock0(uint8_t* ptr, uint32_t todo) {
+    register uint32_t bin;
+    register uint32_t work;
+    register uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(MISO_PIN))+0x3C, PIN_SHIFT(MISO_PIN));  /* PDSR of port in bitband area */
+    register uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30;    /* SODR of port */
+    register uint32_t SCK_MASK = PIN_MASK(SCK_PIN);
+
+    /* The software SPI routine */
+    __asm__ __volatile__(
+      ".syntax unified" "\n\t" // is to prevent CM0,CM1 non-unified syntax
+
+      " loop%=:" "\n\t"
+
+      /* bit 7 */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
+      " bfi %[bin],%[work],#7,#1" "\n\t"                /* Store read bit as the bit 7 */
+
+      /* bit 6 */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
+      " bfi %[bin],%[work],#6,#1" "\n\t"                /* Store read bit as the bit 6 */
+
+      /* bit 5 */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
+      " bfi %[bin],%[work],#5,#1" "\n\t"                /* Store read bit as the bit 5 */
+
+      /* bit 4 */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
+      " bfi %[bin],%[work],#4,#1" "\n\t"                /* Store read bit as the bit 4 */
+
+      /* bit 3 */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
+      " bfi %[bin],%[work],#3,#1" "\n\t"                /* Store read bit as the bit 3 */
+
+      /* bit 2 */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
+      " bfi %[bin],%[work],#2,#1" "\n\t"                /* Store read bit as the bit 2 */
+
+      /* bit 1 */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
+      " bfi %[bin],%[work],#1,#1" "\n\t"                /* Store read bit as the bit 1 */
+
+      /* bit 0 */
+      " str %[sck_mask],[%[sck_port]]" "\n\t"           /* SODR */
+      " ldr %[work],[%[bitband_miso_port]]" "\n\t"      /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
+      " str %[sck_mask],[%[sck_port],#0x4]" "\n\t"      /* CODR */
+      " bfi %[bin],%[work],#0,#1" "\n\t"                /* Store read bit as the bit 0 */
+
+      " subs %[todo],#1" "\n\t"                         /* Decrement count of pending words to send, update status */
+      " strb.w %[bin], [%[ptr]], #1" "\n\t"             /* Store read value into buffer, increment buffer pointer */
+      " bne.n loop%=" "\n\t"                            /* Repeat until done */
+
+      : [ptr]"+r"(ptr),
+        [todo]"+r"(todo),
+        [bin]"+r"(bin),
+        [work]"+r"(work)
+      : [bitband_miso_port]"r"( BITBAND_MISO_PORT ),
+        [sck_mask]"r"( SCK_MASK ),
+        [sck_port]"r"( SCK_PORT_PLUS30 )
+      : "cc"
+    );
+  }
+
+  static void spiTxBlockX(const uint8_t* buf, uint32_t todo) {
+    do {
+      (void) spiTransferTx(*buf++);
+    } while (--todo);
+  }
+
+  static void spiRxBlockX(uint8_t* buf, uint32_t todo) {
+    do {
+      *buf++ = spiTransferRx(0xff);
+    } while (--todo);
+  }
+
+  // Pointers to generic functions for block tranfers
+  static pfnSpiTxBlock spiTxBlock = spiTxBlockX;
+  static pfnSpiRxBlock spiRxBlock = spiRxBlockX;
+
   void spiBegin() {
     SET_OUTPUT(SS_PIN);
     WRITE(SS_PIN, HIGH);
@@ -329,6 +501,38 @@
     SET_OUTPUT(MOSI_PIN);
   }
 
+  uint8_t spiRec() {
+    WRITE(SS_PIN, LOW);
+    WRITE(MOSI_PIN, 1); /* Output 1s 1*/
+    uint8_t b = spiTransferRx(0xFF);
+    WRITE(SS_PIN, HIGH);
+    return b;
+  }
+
+  void spiRead(uint8_t* buf, uint16_t nbyte) {
+    uint32_t todo = nbyte;
+    if (todo == 0) return;
+
+    WRITE(SS_PIN, LOW);
+    WRITE(MOSI_PIN, 1); /* Output 1s 1*/
+    spiRxBlock(buf,nbyte);
+    WRITE(SS_PIN, HIGH);
+  }
+
+  void spiSend(uint8_t b) {
+    WRITE(SS_PIN, LOW);
+    (void) spiTransferTx(b);
+    WRITE(SS_PIN, HIGH);
+  }
+
+  void spiSendBlock(uint8_t token, const uint8_t* buf) {
+
+    WRITE(SS_PIN, LOW);
+    (void) spiTransferTx(token);
+    spiTxBlock(buf,512);
+    WRITE(SS_PIN, HIGH);
+  }
+
   /**
    * spiRate should be
    *  0 :  8 - 10 MHz
@@ -344,15 +548,21 @@
       case 0:
         spiTransferTx = spiTransferTx0;
         spiTransferRx = spiTransferRx0;
+        spiTxBlock = spiTxBlock0;
+        spiRxBlock = spiRxBlock0;
         break;
       case 1:
         spiTransferTx = spiTransfer1;
         spiTransferRx = spiTransfer1;
+        spiTxBlock = spiTxBlockX;
+        spiRxBlock = spiRxBlockX;
         break;
       default:
         spiDelayCyclesX4 = (F_CPU/1000000) >> (6 - spiRate);
         spiTransferTx = spiTransferX;
         spiTransferRx = spiTransferX;
+        spiTxBlock = spiTxBlockX;
+        spiRxBlock = spiRxBlockX;
         break;
     }
 
@@ -361,41 +571,6 @@
     WRITE(SCK_PIN, LOW);
   }
 
-  uint8_t spiRec() {
-    WRITE(SS_PIN, LOW);
-    WRITE(MOSI_PIN, 1); /* Output 1s 1*/
-    uint8_t b = spiTransferRx(0xFF);
-    WRITE(SS_PIN, HIGH);
-    return b;
-  }
-
-  void spiRead(uint8_t* buf, uint16_t nbyte) {
-    if (nbyte == 0) return;
-    WRITE(SS_PIN, LOW);
-    WRITE(MOSI_PIN, 1); /* Output 1s 1*/
-    for (int i = 0; i < nbyte; i++) {
-      buf[i] = spiTransferRx(0xff);
-    }
-    WRITE(SS_PIN, HIGH);
-  }
-
-  void spiSend(uint8_t b) {
-    WRITE(SS_PIN, LOW);
-    (void) spiTransferTx(b);
-    WRITE(SS_PIN, HIGH);
-  }
-
-  void spiSendBlock(uint8_t token, const uint8_t* buf) {
-
-    WRITE(SS_PIN, LOW);
-    (void) spiTransferTx(token);
-
-    for (uint16_t i = 0; i < 512; i++) {
-      (void) spiTransferTx(buf[i]);
-    }
-    WRITE(SS_PIN, HIGH);
-  }
-
   #pragma GCC reset_options
 
 #else
diff --git a/Marlin/src/HAL/HAL_DUE/usb/conf_usb.h b/Marlin/src/HAL/HAL_DUE/usb/conf_usb.h
index 8227fd6fc7..4f780e0093 100644
--- a/Marlin/src/HAL/HAL_DUE/usb/conf_usb.h
+++ b/Marlin/src/HAL/HAL_DUE/usb/conf_usb.h
@@ -47,8 +47,12 @@
 #ifndef _CONF_USB_H_
 #define _CONF_USB_H_
 
+#undef UNUSED                           /* To avoid a macro clash as macros.h already defines it */
+#include "../../../core/macros.h"       /* For ENABLED()/DISABLED() */
+#include "../../../../Configuration.h"  /* For CUSTOM_MACHINE_NAME definition - We just need the name, no C++ allowed! */
 #include "compiler.h"
 
+
 /**
  * USB Device Configuration
  * @{
@@ -61,15 +65,15 @@
 #define  USB_DEVICE_MINOR_VERSION         0
 #define  USB_DEVICE_POWER                 100 // Consumption on Vbus line (mA)
 #define  USB_DEVICE_ATTR                  \
-	(USB_CONFIG_ATTR_SELF_POWERED)
+  (USB_CONFIG_ATTR_SELF_POWERED)
 // (USB_CONFIG_ATTR_BUS_POWERED)
-//	(USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED)
-//	(USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED)
+//  (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED)
+//  (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED)
 
 //! USB Device string definitions (Optional)
-#define  USB_DEVICE_MANUFACTURE_NAME      "MARLIN 3D"
-#define  USB_DEVICE_PRODUCT_NAME          "CDC and MSC"
-#define  USB_DEVICE_SERIAL_NAME           "123985739853" // Disk SN for MSC
+#define  USB_DEVICE_MANUFACTURE_NAME      "marlinfw.org"
+#define  USB_DEVICE_PRODUCT_NAME          CUSTOM_MACHINE_NAME
+#define  USB_DEVICE_SERIAL_NAME           "123985739853"
 
 /**
  * Device speeds support
@@ -94,10 +98,11 @@
  * @{
  */
 #define  UDC_VBUS_EVENT(b_vbus_high)
-#define  UDC_SOF_EVENT()                  
-#define  UDC_SUSPEND_EVENT()              
-#define  UDC_RESUME_EVENT()               
-#define  UDC_GET_EXTRA_STRING()           usb_task_extra_string()
+#define  UDC_SOF_EVENT()
+#define  UDC_SUSPEND_EVENT()
+#define  UDC_RESUME_EVENT()
+#define  UDC_GET_EXTRA_STRING()         usb_task_extra_string()
+#define  USB_DEVICE_SPECIFIC_REQUEST()  usb_task_other_requests()
 //@}
 
 /**
@@ -246,30 +251,30 @@
  */
 //! USB Interfaces descriptor structure
 #define UDI_COMPOSITE_DESC_T \
-	usb_iad_desc_t       udi_cdc_iad; \
-	udi_cdc_comm_desc_t  udi_cdc_comm; \
-	udi_cdc_data_desc_t  udi_cdc_data; \
-	udi_msc_desc_t       udi_msc
+  usb_iad_desc_t       udi_cdc_iad; \
+  udi_cdc_comm_desc_t  udi_cdc_comm; \
+  udi_cdc_data_desc_t  udi_cdc_data; \
+  udi_msc_desc_t       udi_msc
 
 //! USB Interfaces descriptor value for Full Speed
 #define UDI_COMPOSITE_DESC_FS \
-	.udi_cdc_iad   = UDI_CDC_IAD_DESC_0, \
-	.udi_cdc_comm  = UDI_CDC_COMM_DESC_0, \
-	.udi_cdc_data  = UDI_CDC_DATA_DESC_0_FS, \
-	.udi_msc       = UDI_MSC_DESC_FS
+  .udi_cdc_iad   = UDI_CDC_IAD_DESC_0, \
+  .udi_cdc_comm  = UDI_CDC_COMM_DESC_0, \
+  .udi_cdc_data  = UDI_CDC_DATA_DESC_0_FS, \
+  .udi_msc       = UDI_MSC_DESC_FS
 
 //! USB Interfaces descriptor value for High Speed
 #define UDI_COMPOSITE_DESC_HS \
-	.udi_cdc_iad   = UDI_CDC_IAD_DESC_0, \
-	.udi_cdc_comm  = UDI_CDC_COMM_DESC_0, \
-	.udi_cdc_data  = UDI_CDC_DATA_DESC_0_HS, \
-	.udi_msc       = UDI_MSC_DESC_HS
+  .udi_cdc_iad   = UDI_CDC_IAD_DESC_0, \
+  .udi_cdc_comm  = UDI_CDC_COMM_DESC_0, \
+  .udi_cdc_data  = UDI_CDC_DATA_DESC_0_HS, \
+  .udi_msc       = UDI_MSC_DESC_HS
 
 //! USB Interface APIs
 #define UDI_COMPOSITE_API \
-	&udi_api_cdc_comm, \
-	&udi_api_cdc_data, \
-	&udi_api_msc
+  &udi_api_cdc_comm, \
+  &udi_api_cdc_data, \
+  &udi_api_msc
 //@}
 
 
diff --git a/Marlin/src/HAL/HAL_DUE/usb/usb_task.c b/Marlin/src/HAL/HAL_DUE/usb/usb_task.c
index af5a2e96f8..2931dbbc47 100644
--- a/Marlin/src/HAL/HAL_DUE/usb/usb_task.c
+++ b/Marlin/src/HAL/HAL_DUE/usb/usb_task.c
@@ -40,9 +40,8 @@
  * \asf_license_stop
  *
  */
-/*
- * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
- */
+
+// Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
 
 #ifdef ARDUINO_ARCH_SAM
 
@@ -52,135 +51,241 @@
 static volatile bool main_b_msc_enable = false;
 static volatile bool main_b_cdc_enable = false;
 
-void HAL_init(void) {
-	udd_disable();
-	UDD_SetStack(&USBD_ISR);
+void HAL_idletask(void) {
+  // Attend SD card access from the USB MSD -- Prioritize access to improve speed
+  int delay = 2;
+  while (main_b_msc_enable && --delay > 0) {
+    if (udi_msc_process_trans()) delay = 10000;
 
-	// Start USB stack to authorize VBus monitoring
-	udc_start();
+    // Reset the watchdog, just to be sure
+    REG_WDT_CR = WDT_CR_WDRSTT | WDT_CR_KEY(0xA5);
+  }
 }
 
-void HAL_idletask(void)
-{
-
-	// Attend SD card access from the USB MSD -- Priotize access to improve speed
-	int delay = 2;
-	while (main_b_msc_enable && --delay > 0 ) {
-		if (udi_msc_process_trans()) {
-			delay = 10000;
-		}
-		
-		/* Reset the watchdog, just to be sure */
-		REG_WDT_CR = WDT_CR_WDRSTT | WDT_CR_KEY(0xA5);
-	}
-}
+bool usb_task_msc_enable(void)                { return ((main_b_msc_enable = true)); }
+void usb_task_msc_disable(void)               { main_b_msc_enable = false; }
+bool usb_task_msc_isenabled(void)             { return main_b_msc_enable; }
+
+bool usb_task_cdc_enable(const uint8_t port)  { return ((main_b_cdc_enable = true)); }
+void usb_task_cdc_disable(const uint8_t port) { main_b_cdc_enable = false; }
+bool usb_task_cdc_isenabled(void)             { return main_b_cdc_enable; }
+
+/*! \brief Called by CDC interface
+ * Callback running when CDC device have received data
+ */
+void usb_task_cdc_rx_notify(const uint8_t port) { }
 
-/*! \brief Example of extra USB string management
- * This feature is available for single or composite device
- * which want implement additional USB string than
- * Manufacture, Product and serial number ID.
+/*! \brief Configures communication line
  *
- * return true, if the string ID requested is know and managed by this functions
+ * \param cfg      line configuration
  */
-bool usb_task_extra_string(void)
-{
-	static uint8_t udi_cdc_name[] = "CDC interface";
-	static uint8_t udi_msc_name[] = "MSC interface";
-
-	struct extra_strings_desc_t{
-		usb_str_desc_t header;
-		le16_t string[Max(sizeof(udi_cdc_name)-1, sizeof(udi_msc_name)-1)];
-	};
-	static UDC_DESC_STORAGE struct extra_strings_desc_t extra_strings_desc = {
-		.header.bDescriptorType = USB_DT_STRING
-	};
-
-	uint8_t i;
-	uint8_t *str;
-	uint8_t str_lgt=0;
-
-	// Link payload pointer to the string corresponding at request
-	switch (udd_g_ctrlreq.req.wValue & 0xff) {
-	case UDI_CDC_IAD_STRING_ID:
-		str_lgt = sizeof(udi_cdc_name)-1;
-		str = udi_cdc_name;
-		break;
-	case UDI_MSC_STRING_ID:
-		str_lgt = sizeof(udi_msc_name)-1;
-		str = udi_msc_name;
-		break;
-	default:
-		return false;
-	}
-
-	if (str_lgt!=0) {
-		for( i=0; i<str_lgt; i++) {
-			extra_strings_desc.string[i] = cpu_to_le16((le16_t)str[i]);
-		}
-		extra_strings_desc.header.bLength = 2+ (str_lgt)*2;
-		udd_g_ctrlreq.payload_size = extra_strings_desc.header.bLength;
-		udd_g_ctrlreq.payload = (uint8_t *) &extra_strings_desc;
-	}
-
-	// if the string is larger than request length, then cut it
-	if (udd_g_ctrlreq.payload_size > udd_g_ctrlreq.req.wLength) {
-		udd_g_ctrlreq.payload_size = udd_g_ctrlreq.req.wLength;
-	}
-	return true;
-}
+void usb_task_cdc_config(const uint8_t port, usb_cdc_line_coding_t *cfg) { }
 
-bool usb_task_msc_enable(void)
-{
-	main_b_msc_enable = true;
-	return true;
+void usb_task_cdc_set_dtr(const uint8_t port, const bool b_enable) {
+  if (b_enable) {
+  } else {
+  }
 }
 
-void usb_task_msc_disable(void)
-{
-	main_b_msc_enable = false;
-}
+/// Microsoft WCID descriptor
+typedef struct USB_MicrosoftCompatibleDescriptor_Interface {
+  uint8_t bFirstInterfaceNumber;
+  uint8_t reserved1;
+  uint8_t compatibleID[8];
+  uint8_t subCompatibleID[8];
+  uint8_t reserved2[6];
+} __attribute__((packed)) USB_MicrosoftCompatibleDescriptor_Interface;
 
-bool usb_task_msc_isenabled(void)
-{
-	return main_b_msc_enable;
-}
+typedef struct USB_MicrosoftCompatibleDescriptor {
+  uint32_t dwLength;
+  uint16_t bcdVersion;
+  uint16_t wIndex;
+  uint8_t bCount;
+  uint8_t reserved[7];
+  USB_MicrosoftCompatibleDescriptor_Interface interfaces[];
+} __attribute__((packed)) USB_MicrosoftCompatibleDescriptor;
 
-bool usb_task_cdc_enable(uint8_t port)
-{
-	main_b_cdc_enable = true;
-	return true;
-}
+// 3D Printer compatible descriptor
+static USB_MicrosoftCompatibleDescriptor microsoft_compatible_id_descriptor = {
+  .dwLength = sizeof(USB_MicrosoftCompatibleDescriptor) +
+              1*sizeof(USB_MicrosoftCompatibleDescriptor_Interface),
+  .bcdVersion = 0x0100,
+  .wIndex = 0x0004,
+  .bCount = 1,
+  .reserved = {0, 0, 0, 0, 0, 0, 0},
+  .interfaces = {
+    {
+      .bFirstInterfaceNumber = 0,
+      .reserved1 = 1,
+      .compatibleID = "3DPRINT",
+      .subCompatibleID = {0, 0, 0, 0, 0, 0, 0, 0},
+      .reserved2 = {0, 0, 0, 0, 0, 0},
+    }
+  }
+};
 
-void usb_task_cdc_disable(uint8_t port)
-{
-	main_b_cdc_enable = false;
-}
+#define xstr(s) str(s)
+#define str(s) #s
 
-bool usb_task_cdc_isenabled(void)
-{
-	return main_b_cdc_enable;
-}
+#define MS3DPRINT_CONFIG      u"MS3DPrintConfig"
+#define MS3DPRINT_CONFIG_DATA \
+  u"Base=SD\0"\
+  u"Job3DOutputAreaWidth=" xstr(X_BED_SIZE) "000\0"\
+  u"Job3DOutputAreaDepth=" xstr(Y_BED_SIZE) "000\0"\
+  u"Job3DOutputAreaHeight=" xstr(Z_MAX_POS) "000\0"\
+  u"filamentdiameter=1750\0"
 
-/*! \brief Called by CDC interface
- * Callback running when CDC device have received data
- */
-void usb_task_cdc_rx_notify(uint8_t port)
-{
+typedef struct USB_MicrosoftExtendedPropertiesDescriptor {
+  uint32_t  dwLength;
+  uint16_t  bcdVersion;
+  uint16_t  wIndex;
+  uint16_t  bCount;
+  uint32_t  dwPropertySize;
+  uint32_t  dwPropertyDataType;
+  uint16_t  wPropertyNameLength;
+  uint16_t  PropertyName[sizeof(MS3DPRINT_CONFIG)/sizeof(uint16_t)];
+  uint32_t  dwPropertyDataLength;
+  uint16_t  PropertyData[sizeof(MS3DPRINT_CONFIG_DATA)/sizeof(uint16_t)];
+} __attribute__((packed)) USB_MicrosoftExtendedPropertiesDescriptor;
+
+static USB_MicrosoftExtendedPropertiesDescriptor microsoft_extended_properties_descriptor = {
+  .dwLength = sizeof(USB_MicrosoftExtendedPropertiesDescriptor),
+  .bcdVersion = 0x0100,
+  .wIndex = 0x0005,
+  .bCount = 1,
+
+  .dwPropertySize = 4 + 4 + 2 + 4 + sizeof(MS3DPRINT_CONFIG) + sizeof(MS3DPRINT_CONFIG_DATA),
+  .dwPropertyDataType = 7, // (1=REG_SZ, 4=REG_DWORD, 7=REG_MULTI_SZ)
+  .wPropertyNameLength = sizeof(MS3DPRINT_CONFIG),
+  .PropertyName = MS3DPRINT_CONFIG,
+  .dwPropertyDataLength = sizeof(MS3DPRINT_CONFIG_DATA),
+  .PropertyData = MS3DPRINT_CONFIG_DATA
+};
+
+/**************************************************************************************************
+** WCID configuration information
+** Hooked into UDC via UDC_GET_EXTRA_STRING #define.
+*/
+bool usb_task_extra_string(void) {
+  static uint8_t udi_msft_magic[] = "MSFT100\xEE";
+  static uint8_t udi_cdc_name[] = "CDC interface";
+  static uint8_t udi_msc_name[] = "MSC interface";
+
+  struct extra_strings_desc_t {
+    usb_str_desc_t header;
+    le16_t string[Max(Max(sizeof(udi_cdc_name) - 1, sizeof(udi_msc_name) - 1), sizeof(udi_msft_magic) - 1)];
+  };
+  static UDC_DESC_STORAGE struct extra_strings_desc_t extra_strings_desc = {
+    .header.bDescriptorType = USB_DT_STRING
+  };
+
+  uint8_t *str;
+  uint8_t str_lgt = 0;
+
+  // Link payload pointer to the string corresponding at request
+  switch (udd_g_ctrlreq.req.wValue & 0xff) {
+  case UDI_CDC_IAD_STRING_ID:
+    str_lgt = sizeof(udi_cdc_name) - 1;
+    str = udi_cdc_name;
+    break;
+  case UDI_MSC_STRING_ID:
+    str_lgt = sizeof(udi_msc_name) - 1;
+    str = udi_msc_name;
+    break;
+  case 0xEE:
+    str_lgt = sizeof(udi_msft_magic) - 1;
+    str = udi_msft_magic;
+    break;
+  default:
+    return false;
+  }
+
+  for (uint8_t i = 0; i < str_lgt; i++)
+    extra_strings_desc.string[i] = cpu_to_le16((le16_t)str[i]);
+
+  extra_strings_desc.header.bLength = 2 + str_lgt * 2;
+  udd_g_ctrlreq.payload_size = extra_strings_desc.header.bLength;
+  udd_g_ctrlreq.payload = (uint8_t*)&extra_strings_desc;
+
+  // if the string is larger than request length, then cut it
+  if (udd_g_ctrlreq.payload_size > udd_g_ctrlreq.req.wLength) {
+    udd_g_ctrlreq.payload_size = udd_g_ctrlreq.req.wLength;
+  }
+
+  return true;
 }
 
-/*! \brief Configures communication line
- *
- * \param cfg      line configuration
- */
-void usb_task_cdc_config(uint8_t port, usb_cdc_line_coding_t * cfg)
-{
+/**************************************************************************************************
+** Handle device requests that the ASF stack doesn't
+*/
+bool usb_task_other_requests(void) {
+  uint8_t* ptr = 0;
+  uint16_t size = 0;
+
+  if (Udd_setup_type() == USB_REQ_TYPE_VENDOR) {
+    //if (udd_g_ctrlreq.req.bRequest == 0x30)
+    if (1) {
+      if (udd_g_ctrlreq.req.wIndex == 0x04) {
+        ptr = (uint8_t*)&microsoft_compatible_id_descriptor;
+        size = (udd_g_ctrlreq.req.wLength);
+        if (size > microsoft_compatible_id_descriptor.dwLength)
+          size = microsoft_compatible_id_descriptor.dwLength;
+      }
+      else if (udd_g_ctrlreq.req.wIndex == 0x05) {
+        ptr = (uint8_t*)&microsoft_extended_properties_descriptor;
+        size = (udd_g_ctrlreq.req.wLength);
+        if (size > microsoft_extended_properties_descriptor.dwLength)
+          size = microsoft_extended_properties_descriptor.dwLength;
+      }
+      else
+        return false;
+    }
+  }
+
+  udd_g_ctrlreq.payload_size = size;
+  if (size == 0) {
+    udd_g_ctrlreq.callback = 0;
+    udd_g_ctrlreq.over_under_run = 0;
+  }
+  else
+    udd_g_ctrlreq.payload = ptr;
+
+  return true;
 }
 
-void usb_task_cdc_set_dtr(uint8_t port, bool b_enable)
-{
-	if (b_enable) {
-	} else {
-	}
+void HAL_init(void) {
+  uint16_t *ptr;
+
+  udd_disable();
+  UDD_SetStack(&USBD_ISR);
+
+  // Start USB stack to authorize VBus monitoring
+  udc_start();
+
+  // Patch in filament diameter - Be careful: String is in UNICODE (2bytes per char)
+  ptr = &microsoft_extended_properties_descriptor.PropertyData[0];
+  while (ptr[0] || ptr[1]) { // Double 0 flags end of resource
+
+    // Found the filamentdiameter= unicode string
+    if (ptr[0] == 'r' && ptr[1] == '=') {
+      char diam[16];
+      char *sptr;
+
+      // Patch in the filament diameter
+      sprintf_P(diam, PSTR("%d"), (int)((DEFAULT_NOMINAL_FILAMENT_DIA) * 1000.0));
+
+      // And copy it to the proper place, expanding it to unicode
+      sptr = &diam[0];
+      ptr += 2;
+      while (*sptr) *ptr++ = *sptr++;
+
+      // Done!
+      break;
+    }
+
+    // Go to the next character
+    ptr++;
+  }
 }
 
-#endif
\ No newline at end of file
+#endif // ARDUINO_ARCH_SAM
diff --git a/Marlin/src/HAL/HAL_DUE/usb/usb_task.h b/Marlin/src/HAL/HAL_DUE/usb/usb_task.h
index 01f498fb96..f535c9df7a 100644
--- a/Marlin/src/HAL/HAL_DUE/usb/usb_task.h
+++ b/Marlin/src/HAL/HAL_DUE/usb/usb_task.h
@@ -66,33 +66,37 @@ void usb_task_msc_disable(void);
  *
  * \retval true if cdc startup is successfully done
  */
-bool usb_task_cdc_enable(uint8_t port);
+bool usb_task_cdc_enable(const uint8_t port);
 
 /*! \brief Closes the communication port
  * This is called by CDC interface when USB Host disable it.
  */
-void usb_task_cdc_disable(uint8_t port);
+void usb_task_cdc_disable(const uint8_t port);
 
 /*! \brief Save new DTR state to change led behavior.
  * The DTR notify that the terminal have open or close the communication port.
  */
-void usb_task_cdc_set_dtr(uint8_t port, bool b_enable);
+void usb_task_cdc_set_dtr(const uint8_t port, const bool b_enable);
 
 /*! \brief Called by UDC when USB Host request a extra string different
  * of this specified in USB device descriptor
  */
 bool usb_task_extra_string(void);
 
+/*! \brief Called by UDC when USB Host performs unknown requests
+ */
+bool usb_task_other_requests(void);
+
 /*! \brief Called by CDC interface
  * Callback running when CDC device have received data
  */
-void usb_task_cdc_rx_notify(uint8_t port);
+void usb_task_cdc_rx_notify(const uint8_t port);
 
 /*! \brief Configures communication line
  *
  * \param cfg      line configuration
  */
-void usb_task_cdc_config(uint8_t port, usb_cdc_line_coding_t * cfg); 
+void usb_task_cdc_config(const uint8_t port, usb_cdc_line_coding_t *cfg);
 
 /* The USB device interrupt
  */
-- 
GitLab