Skip to content

Conversation

@sago35
Copy link
Member

@sago35 sago35 commented Feb 16, 2021

This PR improves the USBCDC speed of atsamd2x.
The atsamd5x version is #1481 .

I checked it on Windows 10 and found the following

  • 13 byte : fmt.Printf("hello world\r\n")
    • old : 648.298 us
    • new : 88.284 us
  • 11 byte : println("hello world")
    • old : 592.844 us
    • new : 22.224 us
  • 1024 byte + "\r\n"
    • old : 51.735 ms
    • new : 1.906 ms
  • 1024 * 10 byte + "\r\n"
    • old : 513.601 ms
    • new : 18.888ms

@sago35
Copy link
Member Author

sago35 commented Feb 16, 2021

The differences from atsamd5x version are as follows.

diff --git a/5x.txt b/2x.txt
index 023b2d8..8f36d1a 100644
--- a/5x.txt
+++ b/2x.txt
@@ -1,96 +1,96 @@
 // USBCDC is the USB CDC aka serial over USB interface on the SAMD21.
 type USBCDC struct {
 	Buffer  *RingBuffer
 	TxIdx   volatile.Register8
 	waitTxc bool
 	sent    bool
 }
 
 const (
 	usbcdcTxSizeMask uint8 = 0x3F
 	usbcdcTxBankMask uint8 = ^usbcdcTxSizeMask
 	usbcdcTxBank1st  uint8 = 0x00
 	usbcdcTxBank2nd  uint8 = usbcdcTxSizeMask + 1
 )
 
 // Flush flushes buffered data.
 func (usbcdc *USBCDC) Flush() error {
 	if usbLineInfo.lineState > 0 {
 		idx := usbcdc.TxIdx.Get()
 		sz := idx & usbcdcTxSizeMask
 		bk := idx & usbcdcTxBankMask
 		if 0 < sz {
 
 			if usbcdc.waitTxc {
 				// waiting for the next flush(), because the transmission is not complete
 				return nil
 			}
 			usbcdc.waitTxc = true
 
 			// set the data
 			usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][bk]))))
 			if bk == usbcdcTxBank1st {
 				usbcdc.TxIdx.Set(usbcdcTxBank2nd)
 			} else {
 				usbcdc.TxIdx.Set(usbcdcTxBank1st)
 			}
 
 			// clean multi packet size of bytes already sent
 			usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Mask << usb_DEVICE_PCKSIZE_MULTI_PACKET_SIZE_Pos)
 
 			// set count of bytes to be sent
 			usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
 			usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.SetBits((uint32(sz) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
 
 			// clear transfer complete flag
-			setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
+			setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
 
 			// send data by setting bank ready
-			setEPSTATUSSET(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
+			setEPSTATUSSET(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
 			UART0.sent = true
 		}
 	}
 	return nil
 }
 
 // WriteByte writes a byte of data to the USB CDC interface.
 func (usbcdc *USBCDC) WriteByte(c byte) error {
 	// Supposedly to handle problem with Windows USB serial ports?
 	if usbLineInfo.lineState > 0 {
 		ok := false
 		for {
 			mask := interrupt.Disable()
 
 			idx := UART0.TxIdx.Get()
 			if (idx & usbcdcTxSizeMask) < usbcdcTxSizeMask {
 				udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][idx] = c
 				UART0.TxIdx.Set(idx + 1)
 				ok = true
 			}
 
 			interrupt.Restore(mask)
 
 			if ok {
 				break
 			} else {
 				mask := interrupt.Disable()
 				if UART0.sent {
 					if UART0.waitTxc {
-						if (getEPINTFLAG(usb_CDC_ENDPOINT_IN) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) != 0 {
-							setEPSTATUSCLR(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
-							setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
+						if (getEPINTFLAG(usb_CDC_ENDPOINT_IN) & sam.USB_DEVICE_EPINTFLAG_TRCPT1) != 0 {
+							setEPSTATUSCLR(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPSTATUSCLR_BK1RDY)
+							setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
 							UART0.waitTxc = false
 							UART0.Flush()
 						}
 					} else {
 						UART0.Flush()
 					}
 				}
 				interrupt.Restore(mask)
 			}
 		}
 	}
 
 	return nil
 }
 

@deadprogram
Copy link
Member

Fantastic work @sago35 you are so fast! Almost as fast as the new USBCDC code 🏎️

Now merging. Thanks!

@deadprogram deadprogram merged commit ba634c4 into dev Feb 16, 2021
@deadprogram deadprogram deleted the improve-usbcdc-samd2x branch February 16, 2021 13:52
@deadprogram
Copy link
Member

Was just looking at https://github.com/tinygo-org/tinygo/blob/dev/src/machine/usb_nrf52840.go which is structured in a very similar way. Seems like a similar change could be made there as well.

@sago35
Copy link
Member Author

sago35 commented Feb 19, 2021

@deadprogram
I think nrf can be sped up in the same way.
I have feather-nrf52840, so I'll check it out.

@deadprogram
Copy link
Member

Oh please oh please! I really need it.

@sago35 sago35 mentioned this pull request Feb 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants