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.
This commit is contained in:
parent
2b1e6829b3
commit
729a9f55fc
@ -111,6 +111,9 @@
|
|||||||
#define DELAY_NS(x) DELAY_CYCLES( (x) * (F_CPU/1000000) / 1000)
|
#define DELAY_NS(x) DELAY_CYCLES( (x) * (F_CPU/1000000) / 1000)
|
||||||
|
|
||||||
typedef uint8_t (*pfnSpiTransfer) (uint8_t b);
|
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 */
|
/* ---------------- Macros to be able to access definitions from asm */
|
||||||
|
|
||||||
@ -183,26 +186,32 @@
|
|||||||
/* Bit 0 */
|
/* Bit 0 */
|
||||||
" str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]" "\n\t" /* Access the proper SODR or CODR registers based on that bit */
|
" 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 */
|
" 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 */
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */
|
||||||
|
|
||||||
: [mosi_mask]"+r"( MOSI_MASK ),
|
: [idx]"+r"( idx )
|
||||||
[mosi_port]"+r"( MOSI_PORT_PLUS30 ),
|
: [txval]"r"( bout ) ,
|
||||||
[sck_mask]"+r"( SCK_MASK ),
|
[mosi_mask]"r"( MOSI_MASK ),
|
||||||
[sck_port]"+r"( SCK_PORT_PLUS30 ),
|
[mosi_port]"r"( MOSI_PORT_PLUS30 ),
|
||||||
[idx]"+r"( idx ),
|
[sck_mask]"r"( SCK_MASK ),
|
||||||
[txval]"+r"( bout )
|
[sck_port]"r"( SCK_PORT_PLUS30 )
|
||||||
:
|
|
||||||
: "cc"
|
: "cc"
|
||||||
);
|
);
|
||||||
|
|
||||||
return 0;
|
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)
|
// run at ~8 .. ~10Mhz - Rx version (Tx line not altered)
|
||||||
static uint8_t spiTransferRx0(uint8_t bout) { // using Mode 0
|
static uint8_t spiTransferRx0(uint8_t bout) { // using Mode 0
|
||||||
int bin = 0, work = 0;
|
register uint32_t bin;
|
||||||
register uint32_t MISO_PORT_PLUS3C = ((uint32_t) PORT(MISO_PIN)) + 0x3C; /* PDSR of port */
|
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_PORT_PLUS30 = ((uint32_t) PORT(SCK_PIN)) + 0x30; /* SODR of port */
|
||||||
register uint32_t SCK_MASK = PIN_MASK(SCK_PIN);
|
register uint32_t SCK_MASK = PIN_MASK(SCK_PIN);
|
||||||
UNUSED(bout);
|
UNUSED(bout);
|
||||||
@ -213,70 +222,61 @@
|
|||||||
|
|
||||||
/* bit 7 */
|
/* bit 7 */
|
||||||
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */
|
" 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 */
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */
|
||||||
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */
|
" bfi %[bin],%[work],#7,#1" "\n\t" /* Store read bit as the bit 7 */
|
||||||
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */
|
|
||||||
|
|
||||||
/* bit 6 */
|
/* bit 6 */
|
||||||
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */
|
" 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 */
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */
|
||||||
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */
|
" bfi %[bin],%[work],#6,#1" "\n\t" /* Store read bit as the bit 6 */
|
||||||
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */
|
|
||||||
|
|
||||||
/* bit 5 */
|
/* bit 5 */
|
||||||
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */
|
" 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 */
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */
|
||||||
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */
|
" bfi %[bin],%[work],#5,#1" "\n\t" /* Store read bit as the bit 5 */
|
||||||
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */
|
|
||||||
|
|
||||||
/* bit 4 */
|
/* bit 4 */
|
||||||
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */
|
" 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 */
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */
|
||||||
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */
|
" bfi %[bin],%[work],#4,#1" "\n\t" /* Store read bit as the bit 4 */
|
||||||
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */
|
|
||||||
|
|
||||||
/* bit 3 */
|
/* bit 3 */
|
||||||
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */
|
" 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 */
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */
|
||||||
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */
|
" bfi %[bin],%[work],#3,#1" "\n\t" /* Store read bit as the bit 3 */
|
||||||
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */
|
|
||||||
|
|
||||||
/* bit 2 */
|
/* bit 2 */
|
||||||
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */
|
" 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 */
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */
|
||||||
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */
|
" bfi %[bin],%[work],#2,#1" "\n\t" /* Store read bit as the bit 2 */
|
||||||
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */
|
|
||||||
|
|
||||||
/* bit 1 */
|
/* bit 1 */
|
||||||
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */
|
" 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 */
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */
|
||||||
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */
|
" bfi %[bin],%[work],#1,#1" "\n\t" /* Store read bit as the bit 1 */
|
||||||
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */
|
|
||||||
|
|
||||||
/* bit 0 */
|
/* bit 0 */
|
||||||
" str %[sck_mask],[%[sck_port]]" "\n\t" /* SODR */
|
" 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 */
|
" str %[sck_mask],[%[sck_port],#0x4]" "\n\t" /* CODR */
|
||||||
" lsrs %[work],%[work],%[miso_shift]" "\n\t" /* Isolate input into carry */
|
" bfi %[bin],%[work],#0,#1" "\n\t" /* Store read bit as the bit 0 */
|
||||||
" adc %[bin],%[bin],%[bin]" "\n\t" /* Shift left result and add the carry */
|
|
||||||
|
|
||||||
: [miso_port]"+r"( MISO_PORT_PLUS3C ),
|
: [bin]"+r"(bin),
|
||||||
[sck_mask]"+r"( SCK_MASK ),
|
|
||||||
[sck_port]"+r"( SCK_PORT_PLUS30 ),
|
|
||||||
[bin]"+r"(bin),
|
|
||||||
[work]"+r"(work)
|
[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"
|
: "cc"
|
||||||
);
|
);
|
||||||
|
|
||||||
return (uint8_t)bin;
|
return bin;
|
||||||
}
|
}
|
||||||
|
|
||||||
// run at ~4Mhz
|
// run at ~4Mhz
|
||||||
@ -317,10 +317,182 @@
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pointers to generic functions
|
// Pointers to generic functions for byte transfers
|
||||||
static pfnSpiTransfer spiTransferTx = spiTransferX;
|
static pfnSpiTransfer spiTransferTx = spiTransferX;
|
||||||
static pfnSpiTransfer spiTransferRx = 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() {
|
void spiBegin() {
|
||||||
SET_OUTPUT(SS_PIN);
|
SET_OUTPUT(SS_PIN);
|
||||||
WRITE(SS_PIN, HIGH);
|
WRITE(SS_PIN, HIGH);
|
||||||
@ -329,6 +501,38 @@
|
|||||||
SET_OUTPUT(MOSI_PIN);
|
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
|
* spiRate should be
|
||||||
* 0 : 8 - 10 MHz
|
* 0 : 8 - 10 MHz
|
||||||
@ -344,15 +548,21 @@
|
|||||||
case 0:
|
case 0:
|
||||||
spiTransferTx = spiTransferTx0;
|
spiTransferTx = spiTransferTx0;
|
||||||
spiTransferRx = spiTransferRx0;
|
spiTransferRx = spiTransferRx0;
|
||||||
|
spiTxBlock = spiTxBlock0;
|
||||||
|
spiRxBlock = spiRxBlock0;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
spiTransferTx = spiTransfer1;
|
spiTransferTx = spiTransfer1;
|
||||||
spiTransferRx = spiTransfer1;
|
spiTransferRx = spiTransfer1;
|
||||||
|
spiTxBlock = spiTxBlockX;
|
||||||
|
spiRxBlock = spiRxBlockX;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
spiDelayCyclesX4 = (F_CPU/1000000) >> (6 - spiRate);
|
spiDelayCyclesX4 = (F_CPU/1000000) >> (6 - spiRate);
|
||||||
spiTransferTx = spiTransferX;
|
spiTransferTx = spiTransferX;
|
||||||
spiTransferRx = spiTransferX;
|
spiTransferRx = spiTransferX;
|
||||||
|
spiTxBlock = spiTxBlockX;
|
||||||
|
spiRxBlock = spiRxBlockX;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,41 +571,6 @@
|
|||||||
WRITE(SCK_PIN, LOW);
|
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
|
#pragma GCC reset_options
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -47,8 +47,12 @@
|
|||||||
#ifndef _CONF_USB_H_
|
#ifndef _CONF_USB_H_
|
||||||
#define _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"
|
#include "compiler.h"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* USB Device Configuration
|
* USB Device Configuration
|
||||||
* @{
|
* @{
|
||||||
@ -61,15 +65,15 @@
|
|||||||
#define USB_DEVICE_MINOR_VERSION 0
|
#define USB_DEVICE_MINOR_VERSION 0
|
||||||
#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA)
|
#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA)
|
||||||
#define USB_DEVICE_ATTR \
|
#define USB_DEVICE_ATTR \
|
||||||
(USB_CONFIG_ATTR_SELF_POWERED)
|
(USB_CONFIG_ATTR_SELF_POWERED)
|
||||||
// (USB_CONFIG_ATTR_BUS_POWERED)
|
// (USB_CONFIG_ATTR_BUS_POWERED)
|
||||||
// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_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_BUS_POWERED)
|
||||||
|
|
||||||
//! USB Device string definitions (Optional)
|
//! USB Device string definitions (Optional)
|
||||||
#define USB_DEVICE_MANUFACTURE_NAME "MARLIN 3D"
|
#define USB_DEVICE_MANUFACTURE_NAME "marlinfw.org"
|
||||||
#define USB_DEVICE_PRODUCT_NAME "CDC and MSC"
|
#define USB_DEVICE_PRODUCT_NAME CUSTOM_MACHINE_NAME
|
||||||
#define USB_DEVICE_SERIAL_NAME "123985739853" // Disk SN for MSC
|
#define USB_DEVICE_SERIAL_NAME "123985739853"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Device speeds support
|
* Device speeds support
|
||||||
@ -94,10 +98,11 @@
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
#define UDC_VBUS_EVENT(b_vbus_high)
|
#define UDC_VBUS_EVENT(b_vbus_high)
|
||||||
#define UDC_SOF_EVENT()
|
#define UDC_SOF_EVENT()
|
||||||
#define UDC_SUSPEND_EVENT()
|
#define UDC_SUSPEND_EVENT()
|
||||||
#define UDC_RESUME_EVENT()
|
#define UDC_RESUME_EVENT()
|
||||||
#define UDC_GET_EXTRA_STRING() usb_task_extra_string()
|
#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
|
//! USB Interfaces descriptor structure
|
||||||
#define UDI_COMPOSITE_DESC_T \
|
#define UDI_COMPOSITE_DESC_T \
|
||||||
usb_iad_desc_t udi_cdc_iad; \
|
usb_iad_desc_t udi_cdc_iad; \
|
||||||
udi_cdc_comm_desc_t udi_cdc_comm; \
|
udi_cdc_comm_desc_t udi_cdc_comm; \
|
||||||
udi_cdc_data_desc_t udi_cdc_data; \
|
udi_cdc_data_desc_t udi_cdc_data; \
|
||||||
udi_msc_desc_t udi_msc
|
udi_msc_desc_t udi_msc
|
||||||
|
|
||||||
//! USB Interfaces descriptor value for Full Speed
|
//! USB Interfaces descriptor value for Full Speed
|
||||||
#define UDI_COMPOSITE_DESC_FS \
|
#define UDI_COMPOSITE_DESC_FS \
|
||||||
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
|
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
|
||||||
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
|
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
|
||||||
.udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
|
.udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
|
||||||
.udi_msc = UDI_MSC_DESC_FS
|
.udi_msc = UDI_MSC_DESC_FS
|
||||||
|
|
||||||
//! USB Interfaces descriptor value for High Speed
|
//! USB Interfaces descriptor value for High Speed
|
||||||
#define UDI_COMPOSITE_DESC_HS \
|
#define UDI_COMPOSITE_DESC_HS \
|
||||||
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
|
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
|
||||||
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
|
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
|
||||||
.udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
|
.udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
|
||||||
.udi_msc = UDI_MSC_DESC_HS
|
.udi_msc = UDI_MSC_DESC_HS
|
||||||
|
|
||||||
//! USB Interface APIs
|
//! USB Interface APIs
|
||||||
#define UDI_COMPOSITE_API \
|
#define UDI_COMPOSITE_API \
|
||||||
&udi_api_cdc_comm, \
|
&udi_api_cdc_comm, \
|
||||||
&udi_api_cdc_data, \
|
&udi_api_cdc_data, \
|
||||||
&udi_api_msc
|
&udi_api_msc
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,9 +40,8 @@
|
|||||||
* \asf_license_stop
|
* \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
|
#ifdef ARDUINO_ARCH_SAM
|
||||||
|
|
||||||
@ -52,135 +51,241 @@
|
|||||||
static volatile bool main_b_msc_enable = false;
|
static volatile bool main_b_msc_enable = false;
|
||||||
static volatile bool main_b_cdc_enable = false;
|
static volatile bool main_b_cdc_enable = false;
|
||||||
|
|
||||||
void HAL_init(void) {
|
void HAL_idletask(void) {
|
||||||
udd_disable();
|
// Attend SD card access from the USB MSD -- Prioritize access to improve speed
|
||||||
UDD_SetStack(&USBD_ISR);
|
int delay = 2;
|
||||||
|
while (main_b_msc_enable && --delay > 0) {
|
||||||
|
if (udi_msc_process_trans()) delay = 10000;
|
||||||
|
|
||||||
// Start USB stack to authorize VBus monitoring
|
// Reset the watchdog, just to be sure
|
||||||
udc_start();
|
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
|
bool usb_task_cdc_enable(const uint8_t port) { return ((main_b_cdc_enable = true)); }
|
||||||
int delay = 2;
|
void usb_task_cdc_disable(const uint8_t port) { main_b_cdc_enable = false; }
|
||||||
while (main_b_msc_enable && --delay > 0 ) {
|
bool usb_task_cdc_isenabled(void) { return main_b_cdc_enable; }
|
||||||
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<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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \brief Called by CDC interface
|
/*! \brief Called by CDC interface
|
||||||
* Callback running when CDC device have received data
|
* 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
|
/*! \brief Configures communication line
|
||||||
*
|
*
|
||||||
* \param cfg line configuration
|
* \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)
|
/// Microsoft WCID descriptor
|
||||||
{
|
typedef struct USB_MicrosoftCompatibleDescriptor_Interface {
|
||||||
if (b_enable) {
|
uint8_t bFirstInterfaceNumber;
|
||||||
} else {
|
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
|
/**************************************************************************************************
|
||||||
|
** 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
|
||||||
|
@ -66,33 +66,37 @@ void usb_task_msc_disable(void);
|
|||||||
*
|
*
|
||||||
* \retval true if cdc startup is successfully done
|
* \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
|
/*! \brief Closes the communication port
|
||||||
* This is called by CDC interface when USB Host disable it.
|
* 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.
|
/*! \brief Save new DTR state to change led behavior.
|
||||||
* The DTR notify that the terminal have open or close the communication port.
|
* 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
|
/*! \brief Called by UDC when USB Host request a extra string different
|
||||||
* of this specified in USB device descriptor
|
* of this specified in USB device descriptor
|
||||||
*/
|
*/
|
||||||
bool usb_task_extra_string(void);
|
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
|
/*! \brief Called by CDC interface
|
||||||
* Callback running when CDC device have received data
|
* 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
|
/*! \brief Configures communication line
|
||||||
*
|
*
|
||||||
* \param cfg line configuration
|
* \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
|
/* The USB device interrupt
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user