|
|
@@ -9,13 +9,20 @@ uint32_t qtd_in[8] __attribute__ ((aligned(32))); |
|
|
|
uint32_t qtd_outack[8] __attribute__ ((aligned(32))); |
|
|
|
uint32_t setupbuf[2] __attribute__ ((aligned(8))); |
|
|
|
uint32_t inbuf[16] __attribute__ ((aligned(64))); |
|
|
|
|
|
|
|
uint8_t port_state; |
|
|
|
#define PORT_STATE_DISCONNECTED 0 |
|
|
|
#define PORT_STATE_DEBOUNCE 1 |
|
|
|
#define PORT_STATE_RESET 2 |
|
|
|
#define PORT_STATE_RECOVERY 3 |
|
|
|
#define PORT_STATE_ACTIVE 4 |
|
|
|
|
|
|
|
void setup() |
|
|
|
{ |
|
|
|
// Test board has a USB data mux (this won't be on final Teensy 3.6) |
|
|
|
pinMode(32, OUTPUT); // pin 32 = USB switch, high=connect device |
|
|
|
digitalWrite(32, LOW); |
|
|
|
pinMode(30, OUTPUT); // pin 30 = debug info - use oscilloscope |
|
|
|
digitalWrite(30, LOW); |
|
|
|
// Teensy 3.6 has USB host power controlled by PTE6 |
|
|
|
PORTE_PCR6 = PORT_PCR_MUX(1); |
|
|
|
GPIOE_PDDR |= (1<<6); |
|
|
@@ -60,17 +67,6 @@ void setup() |
|
|
|
//SIM_SOPT2 = SIM_SOPT2 & (~SIM_SOPT2_CLKOUTSEL(7)) | SIM_SOPT2_CLKOUTSEL(4); // MCGIRCLK |
|
|
|
//CORE_PIN9_CONFIG = PORT_PCR_MUX(5); // CLKOUT on PTC3 Alt5 (Arduino pin 9) |
|
|
|
|
|
|
|
// EHCI registers page default |
|
|
|
// -------------- ---- ------- |
|
|
|
// USBHS_USBCMD 1599 00080000 |
|
|
|
// USBHS_USBSTS 1602 00000000 |
|
|
|
// USBHS_USBINTR 1606 00000000 |
|
|
|
// USBHS_FRINDEX 1609 00000000 |
|
|
|
// USBHS_PERIODICLISTBASE 1610 undefine |
|
|
|
// USBHS_ASYNCLISTADDR 1612 undefine |
|
|
|
// USBHS_PORTSC 1619 00002000 |
|
|
|
// USBHS_USBMODE 1629 00005000 |
|
|
|
|
|
|
|
print("begin ehci reset"); |
|
|
|
USBHS_USBCMD |= USBHS_USBCMD_RST; |
|
|
|
count = 0; |
|
|
@@ -102,6 +98,7 @@ void setup() |
|
|
|
qtd_dummy[5] = 0; |
|
|
|
qtd_dummy[6] = 0; |
|
|
|
qtd_dummy[7] = 0; |
|
|
|
port_state = PORT_STATE_DISCONNECTED; |
|
|
|
|
|
|
|
// turn on the USBHS controller |
|
|
|
USBHS_USBMODE = USBHS_USBMODE_TXHSD(5) | USBHS_USBMODE_CM(3); // host mode |
|
|
@@ -113,6 +110,8 @@ void setup() |
|
|
|
USBHS_USBCMD_FS2 | USBHS_USBCMD_FS(0) | // periodic table is 64 pointers |
|
|
|
// USBHS_USBCMD_PSE | |
|
|
|
USBHS_USBCMD_ASE; |
|
|
|
|
|
|
|
//USBHS_PORTSC1 = USBHS_PORTSC_PP; |
|
|
|
USBHS_PORTSC1 |= USBHS_PORTSC_PP; |
|
|
|
//USBHS_PORTSC1 |= USBHS_PORTSC_PFSC; // force 12 Mbit/sec |
|
|
|
//USBHS_PORTSC1 |= USBHS_PORTSC_PHCD; // phy off |
|
|
@@ -123,8 +122,114 @@ void setup() |
|
|
|
Serial.println(USBHS_PERIODICLISTBASE, HEX); |
|
|
|
Serial.print("periodictable = "); |
|
|
|
Serial.println((uint32_t)periodictable, HEX); |
|
|
|
|
|
|
|
NVIC_ENABLE_IRQ(IRQ_USBHS); |
|
|
|
USBHS_USBINTR = USBHS_USBINTR_UE | USBHS_USBINTR_PCE | USBHS_USBINTR_TIE0; |
|
|
|
|
|
|
|
delay(25); |
|
|
|
Serial.println("Plug in device..."); |
|
|
|
digitalWrite(32, HIGH); // connect device |
|
|
|
} |
|
|
|
|
|
|
|
void pulse(int usec) |
|
|
|
{ |
|
|
|
// connect oscilloscope to see these pulses.... |
|
|
|
digitalWriteFast(30, HIGH); |
|
|
|
delayMicroseconds(usec); |
|
|
|
digitalWriteFast(30, LOW); |
|
|
|
} |
|
|
|
|
|
|
|
// EHCI registers page default |
|
|
|
// -------------- ---- ------- |
|
|
|
// USBHS_USBCMD 1599 00080000 USB Command |
|
|
|
// USBHS_USBSTS 1602 00000000 USB Status |
|
|
|
// USBHS_USBINTR 1606 00000000 USB Interrupt Enable |
|
|
|
// USBHS_FRINDEX 1609 00000000 Frame Index Register |
|
|
|
// USBHS_PERIODICLISTBASE 1610 undefine Periodic Frame List Base Address |
|
|
|
// USBHS_ASYNCLISTADDR 1612 undefine Asynchronous List Address |
|
|
|
// USBHS_PORTSC1 1619 00002000 Port Status and Control |
|
|
|
// USBHS_USBMODE 1629 00005000 USB Mode |
|
|
|
// USBHS_GPTIMERnCTL 1591 00000000 General Purpose Timer n Control |
|
|
|
|
|
|
|
// PORT_STATE_DISCONNECTED 0 |
|
|
|
// PORT_STATE_DEBOUNCE 1 |
|
|
|
// PORT_STATE_RESET 2 |
|
|
|
// PORT_STATE_RECOVERY 3 |
|
|
|
// PORT_STATE_ACTIVE 4 |
|
|
|
|
|
|
|
void usbhs_isr(void) // USBHS_ISR_HOST |
|
|
|
{ |
|
|
|
uint32_t stat = USBHS_USBSTS; |
|
|
|
USBHS_USBSTS = stat; // clear pending interrupts |
|
|
|
//stat &= USBHS_USBINTR; // mask away unwanted interrupts |
|
|
|
Serial.print("isr:"); |
|
|
|
Serial.print(stat, HEX); |
|
|
|
Serial.println(); |
|
|
|
|
|
|
|
if (stat & USBHS_USBSTS_PCI) { // port change detected |
|
|
|
const uint32_t portstat = USBHS_PORTSC1; |
|
|
|
Serial.print("port change: "); |
|
|
|
Serial.print(portstat, HEX); |
|
|
|
Serial.println(); |
|
|
|
USBHS_PORTSC1 = portstat | (USBHS_PORTSC_OCC|USBHS_PORTSC_PEC|USBHS_PORTSC_CSC); |
|
|
|
if (portstat & USBHS_PORTSC_OCC) { |
|
|
|
Serial.println(" overcurrent change"); |
|
|
|
} |
|
|
|
if (portstat & USBHS_PORTSC_CSC) { |
|
|
|
if (portstat & USBHS_PORTSC_CCS) { |
|
|
|
Serial.println(" connect"); |
|
|
|
if (port_state == PORT_STATE_DISCONNECTED |
|
|
|
|| port_state == PORT_STATE_DEBOUNCE) { |
|
|
|
// 100 ms debounce (USB 2.0: TATTDB, page 150 & 188) |
|
|
|
port_state = PORT_STATE_DEBOUNCE; |
|
|
|
USBHS_GPTIMER0LD = 100000; // microseconds |
|
|
|
USBHS_GPTIMER0CTL = |
|
|
|
USBHS_GPTIMERCTL_RST | USBHS_GPTIMERCTL_RUN; |
|
|
|
stat &= ~USBHS_USBSTS_TI0; |
|
|
|
} |
|
|
|
} else { |
|
|
|
Serial.println(" disconnect"); |
|
|
|
port_state = PORT_STATE_DISCONNECTED; |
|
|
|
// TODO: delete & clean up device state... |
|
|
|
} |
|
|
|
} |
|
|
|
if (portstat & USBHS_PORTSC_PEC) { |
|
|
|
// PEC bit only detects disable |
|
|
|
Serial.println(" disable"); |
|
|
|
} else if (port_state == PORT_STATE_RESET && portstat & USBHS_PORTSC_PE) { |
|
|
|
Serial.println(" port enabled"); |
|
|
|
port_state = PORT_STATE_RECOVERY; |
|
|
|
// 10 ms reset recover (USB 2.0: TRSTRCY, page 151 & 188) |
|
|
|
USBHS_GPTIMER0LD = 10000; // microseconds |
|
|
|
USBHS_GPTIMER0CTL = USBHS_GPTIMERCTL_RST | USBHS_GPTIMERCTL_RUN; |
|
|
|
|
|
|
|
} |
|
|
|
if (portstat & USBHS_PORTSC_FPR) { |
|
|
|
Serial.println(" force resume"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
pulse(1); |
|
|
|
} |
|
|
|
if (stat & USBHS_USBSTS_TI0) { // timer 0 |
|
|
|
Serial.println("timer"); |
|
|
|
pulse(2); |
|
|
|
if (port_state == PORT_STATE_DEBOUNCE) { |
|
|
|
port_state = PORT_STATE_RESET; |
|
|
|
USBHS_PORTSC1 |= USBHS_PORTSC_PR; // begin reset sequence |
|
|
|
Serial.println(" begin reset"); |
|
|
|
} else if (port_state == PORT_STATE_RECOVERY) { |
|
|
|
port_state = PORT_STATE_ACTIVE; |
|
|
|
Serial.println(" end recovery"); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void port_status() |
|
|
|
{ |
|
|
|
uint32_t n; |
|
|
@@ -240,11 +345,13 @@ void read_descriptor(uint16_t value, uint16_t index, uint32_t len) |
|
|
|
Serial.println(qtd_in[2], HEX); |
|
|
|
Serial.println(qtd_outack[2], HEX); |
|
|
|
Serial.println(qtd_setup[2], HEX); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void loop() |
|
|
|
{ |
|
|
|
/* |
|
|
|
static unsigned int count=0; |
|
|
|
|
|
|
|
port_status(); |
|
|
@@ -265,9 +372,10 @@ void loop() |
|
|
|
if (count == 22) { |
|
|
|
read_descriptor(1, 0, 8); // device descriptor |
|
|
|
} |
|
|
|
if (count > 5000) { |
|
|
|
if (count > 500) { |
|
|
|
while (1) ; // stop here |
|
|
|
} |
|
|
|
*/ |
|
|
|
} |
|
|
|
|
|
|
|
void print(const char *s) |