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 Atmel Support
- */
+
+// Support and FAQ: visit Atmel Support
#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)
-{
+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; }
- // 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);
- }
-}
-
-/*! \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.
- *
- * return true, if the string ID requested is know and managed by this functions
- */
-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 udd_g_ctrlreq.req.wLength) {
- udd_g_ctrlreq.payload_size = udd_g_ctrlreq.req.wLength;
- }
- return true;
-}
-
-bool usb_task_msc_enable(void)
-{
- main_b_msc_enable = true;
- return 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(uint8_t port)
-{
- main_b_cdc_enable = true;
- return true;
-}
-
-void usb_task_cdc_disable(uint8_t port)
-{
- main_b_cdc_enable = false;
-}
-
-bool usb_task_cdc_isenabled(void)
-{
- return main_b_cdc_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(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) { }
+
+void usb_task_cdc_set_dtr(const uint8_t port, const bool b_enable) {
+ if (b_enable) {
+ } else {
+ }
}
-void usb_task_cdc_set_dtr(uint8_t port, bool b_enable)
-{
- if (b_enable) {
- } else {
- }
+/// 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;
+
+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;
+
+// 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},
+ }
+ }
+};
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+#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"
+
+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;
}
-#endif
\ No newline at end of file
+/**************************************************************************************************
+** 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*)µsoft_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*)µsoft_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 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 = µsoft_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 // 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
*/