Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 50 additions & 19 deletions src/machine/machine_atsamd51.go
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,10 @@ type UART struct {

var (
// UART0 is actually a USB CDC interface.
UART0 = USBCDC{Buffer: NewRingBuffer()}
UART0 = USBCDC{
Buffer: NewRingBuffer(),
TxBuffer: NewRingBuffer(),
}
)

const (
Expand Down Expand Up @@ -1708,33 +1711,55 @@ func (pwm PWM) getMux() PinMode {

// USBCDC is the USB CDC aka serial over USB interface on the SAMD21.
type USBCDC struct {
Buffer *RingBuffer
Buffer *RingBuffer
TxBuffer *RingBuffer
waitTxc bool
}

// 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?
// Flush flushes buffered data.
func (usbcdc *USBCDC) Flush() error {
if usbLineInfo.lineState > 0 {
// set the data
udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][0] = c
sz := usbcdc.TxBuffer.Used()
if 0 < sz {

usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN]))))
if usbcdc.waitTxc {
// waiting for the next flush(), because the transmission is not complete
return nil
}
usbcdc.waitTxc = true

// 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 the data
for i := uint8(0); i < sz; i++ {
udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN][i], _ = usbcdc.TxBuffer.Get()
}
Comment on lines +1732 to +1734
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This process is a byte copy, but it's a waste of time.
I will create a new PR that improves on this part of the process.

usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[usb_CDC_ENDPOINT_IN]))))

// set count of bytes to be sent
usbEndpointDescriptors[usb_CDC_ENDPOINT_IN].DeviceDescBank[1].PCKSIZE.SetBits((1 & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
// 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)

// clear transfer complete flag
setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
// 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)

// send data by setting bank ready
setEPSTATUSSET(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
// clear transfer complete flag
setEPINTFLAG(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)

// wait for transfer to complete
timeout := 3000
for (getEPINTFLAG(usb_CDC_ENDPOINT_IN) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) == 0 {
// send data by setting bank ready
setEPSTATUSSET(usb_CDC_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
}
}
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 {
// `timeout == 10000` waits for a bit over 1ms (120MHz)
timeout := 10000
ok := false
for !ok {
ok = usbcdc.TxBuffer.Put(c)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RingBuffer.Put() does not consider calling from multiple priorities.
interrupt.Disable() is required.

timeout--
if timeout == 0 {
return errUSBCDCWriteByteTimeout
Expand Down Expand Up @@ -1946,9 +1971,15 @@ func handleUSBIRQ(interrupt.Interrupt) {
case usb_CDC_ENDPOINT_IN, usb_CDC_ENDPOINT_ACM:
setEPSTATUSCLR(i, sam.USB_DEVICE_ENDPOINT_EPSTATUSCLR_BK1RDY)
setEPINTFLAG(i, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)

if i == usb_CDC_ENDPOINT_IN {
UART0.waitTxc = false
}
}
}
}

UART0.Flush()
}

func initEndpoint(ep, config uint32) {
Expand Down