samd support suspend and resume. Though cannot distinguish between Suspend and Disconnect
should work with #47
This commit is contained in:
		| @@ -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(); | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 hathach
					hathach