diff --git a/examples/device/cdc_msc_hid/ses/samd51/samd51.emProject b/examples/device/cdc_msc_hid/ses/samd51/samd51.emProject index 280afdcd1..cc34dc63d 100644 --- a/examples/device/cdc_msc_hid/ses/samd51/samd51.emProject +++ b/examples/device/cdc_msc_hid/ses/samd51/samd51.emProject @@ -71,6 +71,11 @@ + + + + + diff --git a/src/portable/microchip/samd21/dcd_samd21.c b/src/portable/microchip/samd21/dcd_samd21.c index 39d59486d..8ecfd3668 100644 --- a/src/portable/microchip/samd21/dcd_samd21.c +++ b/src/portable/microchip/samd21/dcd_samd21.c @@ -38,19 +38,20 @@ static ATTR_ALIGNED(4) UsbDeviceDescBank sram_registers[8][2]; static ATTR_ALIGNED(4) uint8_t _setup_packet[8]; // Setup the control endpoint 0. -static void bus_reset(void) { - // Max size of packets is 64 bytes. - UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT]; - bank_out->PCKSIZE.bit.SIZE = 0x3; - UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN]; - bank_in->PCKSIZE.bit.SIZE = 0x3; +static void bus_reset(void) +{ + // Max size of packets is 64 bytes. + UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT]; + bank_out->PCKSIZE.bit.SIZE = 0x3; + UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN]; + bank_in->PCKSIZE.bit.SIZE = 0x3; - UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0]; - ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1); - ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP; + UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0]; + ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1); + ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP; - // Prepare for setup packet - dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet)); + // Prepare for setup packet + dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet)); } @@ -79,6 +80,7 @@ void dcd_init (uint8_t rhport) USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY; while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {} + USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST; } @@ -103,6 +105,10 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {} USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN; + + // Enable SUSPEND interrupt since the bus signal D+/D- are stable now. + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending + USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND; } void dcd_set_config (uint8_t rhport, uint8_t config_num) @@ -111,17 +117,13 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) (void) config_num; // Nothing to do -#if 0 - // Enable suspend to detect disconnection - // TODO need to distinguish Suspend vs Disconnect - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; - USB->DEVICE.INTENSET.reg |= USB_DEVICE_INTENSET_SUSPEND; -#endif } void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; + + USB->DEVICE.CTRLB.bit.UPRSM = 1; } /*------------------------------------------------------------------*/ @@ -305,35 +307,44 @@ void maybe_transfer_complete(void) { void USB_Handler(void) { uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg; + USB->DEVICE.INTFLAG.reg = int_status; // clear interrupt /*------------- Interrupt Processing -------------*/ - if ( int_status & USB_DEVICE_INTFLAG_EORST ) - { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; - bus_reset(); - dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); - } - if ( int_status & USB_DEVICE_INTFLAG_SOF ) { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF; dcd_event_bus_signal(0, DCD_EVENT_SOF, true); } -#if 0 + // SAMD doesn't distinguish between Suspend and Disconnect state. + // Both condition will cause SUSPEND interrupt triggered. + // To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only + // enabled when we received SET_ADDRESS request and cleared on Bus Reset if ( int_status & USB_DEVICE_INTFLAG_SUSPEND ) { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SUSPEND; + // Enable wakeup interrupt + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending + USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP; - // disable interrupt to prevent it continue to trigger - USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTENCLR_SUSPEND; - - // TODO need to distinguish Suspend vs Disconnect - // reset address to 0, force host to re-enumerate after resume - USB->DEVICE.DADD.reg = 0; - dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true); + dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); + } + + // Wakeup interrupt is only enabled when we got suspended. + // Wakeup interrupt will disable itself + if ( int_status & USB_DEVICE_INTFLAG_WAKEUP ) + { + // disable wakeup interrupt itself + USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP; + dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); + } + + if ( int_status & USB_DEVICE_INTFLAG_EORST ) + { + // Disable both suspend and wakeup interrupt + USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND; + + bus_reset(); + dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); } -#endif // Setup packet received. maybe_handle_setup_packet(); diff --git a/src/portable/microchip/samd51/dcd_samd51.c b/src/portable/microchip/samd51/dcd_samd51.c index a1702b056..d2e7aaf7d 100644 --- a/src/portable/microchip/samd51/dcd_samd51.c +++ b/src/portable/microchip/samd51/dcd_samd51.c @@ -38,19 +38,20 @@ static UsbDeviceDescBank sram_registers[8][2]; static ATTR_ALIGNED(4) uint8_t _setup_packet[8]; // Setup the control endpoint 0. -static void bus_reset(void) { - // Max size of packets is 64 bytes. - UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT]; - bank_out->PCKSIZE.bit.SIZE = 0x3; - UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN]; - bank_in->PCKSIZE.bit.SIZE = 0x3; +static void bus_reset(void) +{ + // Max size of packets is 64 bytes. + UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT]; + bank_out->PCKSIZE.bit.SIZE = 0x3; + UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN]; + bank_in->PCKSIZE.bit.SIZE = 0x3; - UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0]; - ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1); - ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP; + UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0]; + ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1); + ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP; - // Prepare for setup packet - dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet)); + // Prepare for setup packet + dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet)); } @@ -78,6 +79,8 @@ void dcd_init (uint8_t rhport) USB->DEVICE.CTRLB.reg = USB_DEVICE_CTRLB_SPDCONF_FS; USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY; while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {} + + USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST; } @@ -108,6 +111,10 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr) while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {} USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN; + + // Enable SUSPEND interrupt since the bus signal D+/D- are stable now. + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending + USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND; } void dcd_set_config (uint8_t rhport, uint8_t config_num) @@ -120,6 +127,8 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num) void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; + + USB->DEVICE.CTRLB.bit.UPRSM = 1; } /*------------------------------------------------------------------*/ @@ -270,12 +279,42 @@ USB_TRFAIL1_PERR_0, USB_TRFAIL1_PERR_1, USB_TRFAIL1_PERR_2, USB_TRFAIL1_PERR_3, USB_TRFAIL1_PERR_4, USB_TRFAIL1_PERR_5, USB_TRFAIL1_PERR_6, USB_TRFAIL1_PERR_7, USB_UPRSM, USB_WAKEUP */ void USB_0_Handler(void) { - uint32_t int_status = USB->DEVICE.INTFLAG.reg; + uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg; /*------------- Interrupt Processing -------------*/ + // SAMD doesn't distinguish between Suspend and Disconnect state. + // Both condition will cause SUSPEND interrupt triggered. + // To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only + // enabled when we received SET_ADDRESS request and cleared on Bus Reset + if ( int_status & USB_DEVICE_INTFLAG_SUSPEND ) + { + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SUSPEND; + + // Enable wakeup interrupt + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending + USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP; + + dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true); + } + + // Wakeup interrupt is only enabled when we got suspended. + // Wakeup interrupt will disable itself + if ( int_status & USB_DEVICE_INTFLAG_WAKEUP ) + { + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; + + // disable wakeup interrupt itself + USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP; + dcd_event_bus_signal(0, DCD_EVENT_RESUME, true); + } + if ( int_status & USB_DEVICE_INTFLAG_EORST ) { - USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_EORST; + USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST; + + // Disable both suspend and wakeup interrupt + USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND; + bus_reset(); dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true); } @@ -283,6 +322,7 @@ void USB_0_Handler(void) { // Setup packet received. maybe_handle_setup_packet(); } + /* USB_SOF_HSOF */ void USB_1_Handler(void) { USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;