Skip to content
Open
Show file tree
Hide file tree
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
14 changes: 14 additions & 0 deletions src/machine/machine_atsamd21_usb.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ func (dev *USBDevice) Configure(config UARTConfig) {
dev.initcomplete = true
}

// Attach connects the device to the USB bus, allowing the host to detect and
// enumerate it. It can be used together with Detach to delay enumeration
// until the USB configuration (device identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH)
}

// Detach disconnects the device from the USB bus. To the host this appears
// as if the device was unplugged. A subsequent Attach makes the host
// enumerate the device again.
func (dev *USBDevice) Detach() {
sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_DETACH)
}

func handlePadCalibration() {
// Load Pad Calibration data from non-volatile memory
// This requires registers that are not included in the SVD file.
Expand Down
14 changes: 14 additions & 0 deletions src/machine/machine_atsamd51_usb.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ func (dev *USBDevice) Configure(config UARTConfig) {
dev.initcomplete = true
}

// Attach connects the device to the USB bus, allowing the host to detect and
// enumerate it. It can be used together with Detach to delay enumeration
// until the USB configuration (device identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH)
}

// Detach disconnects the device from the USB bus. To the host this appears
// as if the device was unplugged. A subsequent Attach makes the host
// enumerate the device again.
func (dev *USBDevice) Detach() {
sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_DETACH)
}

func handlePadCalibration() {
// Load Pad Calibration data from non-volatile memory
// This requires registers that are not included in the SVD file.
Expand Down
15 changes: 15 additions & 0 deletions src/machine/machine_nrf52840_usb.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,21 @@ func (dev *USBDevice) Configure(config UARTConfig) {
dev.initcomplete = true
}

// Attach connects the device to the USB bus by enabling the DP pull-up,
// allowing the host to detect and enumerate it. It can be used together with
// Detach to delay enumeration until the USB configuration (device
// identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
nrf.USBD.USBPULLUP.Set(1)
}

// Detach disconnects the device from the USB bus by disabling the DP pull-up.
// To the host this appears as if the device was unplugged. A subsequent
// Attach makes the host enumerate the device again.
func (dev *USBDevice) Detach() {
nrf.USBD.USBPULLUP.Set(0)
}

func handleUSBIRQ(interrupt.Interrupt) {
if nrf.USBD.EVENTS_SOF.Get() == 1 {
nrf.USBD.EVENTS_SOF.Set(0)
Expand Down
15 changes: 15 additions & 0 deletions src/machine/machine_rp2040_usb.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@ func (dev *USBDevice) Configure(config UARTConfig) {
rp.USBCTRL_REGS.SIE_CTRL.SetBits(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN)
}

// Attach connects the device to the USB bus by enabling the DP pull-up,
// allowing the host to detect and enumerate it. It can be used together with
// Detach to delay enumeration until the USB configuration (device
// identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
rp.USBCTRL_REGS.SIE_CTRL.SetBits(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

RP2040/RP2350 provide atomic bitmask set/clear aliases at +0x2000 and
+0x3000 (RP2040 datasheet 2.1.2, p.18:
https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf), which
modify only the selected bits. SIE_CTRL is also touched from the ISR,
so this avoids the read-modify-write. Could we use those aliases here
for PULLUP_EN?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks for the great suggestion. I think we can definitely use it here, but it would probably be better handled in a separate PR—for example, by integrating it into implementations like SetBits() / ClearBits()/ ....

However, this suggested approach might only work for registers and not for standard RAM. If that’s the case, we might need to consider a slightly more complex approach.

Since that change would have a broad impact, it's likely better to target the dev branch right after the upcoming release, rather than squeezing it into TinyGo 0.42.

Would you be open to creating a separate PR for that?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I created Issue #5564

@rdon-key rdon-key Jul 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Understood. I'll look into a more general solution, although it may take some time.

For this PR, could we keep the change local and use the atomic aliases directly?

For example:

// USBCTRL_REGS aliases for atomic bitmask set/clear (datasheet section 2.1.2).
var (
	usbSet = (*rp.USBCTRL_REGS_Type)(unsafe.Pointer(
		uintptr(unsafe.Pointer(rp.USBCTRL_REGS)) + 0x2000))
	usbClr = (*rp.USBCTRL_REGS_Type)(unsafe.Pointer(
		uintptr(unsafe.Pointer(rp.USBCTRL_REGS)) + 0x3000))
)

func (dev *USBDevice) Attach() {
	usbSet.SIE_CTRL.Set(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN)
}

func (dev *USBDevice) Detach() {
	usbClr.SIE_CTRL.Set(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN)
}

And similarly for RP2350.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't think there is a need to change to a new method in this PR.

This code is a new change and has no impact on other parts. Furthermore, by using SetBits() and similar functions, the internal implementation will be updated to a better form. There is no reason to leave open the possibility of an implementation that differs from the future SetBits().

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks. Understood. I still think this should use the atomic write even temporarily, but it's your call.

}

// Detach disconnects the device from the USB bus by disabling the DP pull-up.
// To the host this appears as if the device was unplugged. A subsequent
// Attach makes the host enumerate the device again.
func (dev *USBDevice) Detach() {
rp.USBCTRL_REGS.SIE_CTRL.ClearBits(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN)
}

func handleUSBIRQ(intr interrupt.Interrupt) {
status := rp.USBCTRL_REGS.INTS.Get()

Expand Down
15 changes: 15 additions & 0 deletions src/machine/machine_rp2350_usb.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ func (dev *USBDevice) Configure(config UARTConfig) {
rp.USB.SetMAIN_CTRL_PHY_ISO(0x0)
}

// Attach connects the device to the USB bus by enabling the DP pull-up,
// allowing the host to detect and enumerate it. It can be used together with
// Detach to delay enumeration until the USB configuration (device
// identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
rp.USB.SIE_CTRL.SetBits(rp.USB_SIE_CTRL_PULLUP_EN)
}

// Detach disconnects the device from the USB bus by disabling the DP pull-up.
// To the host this appears as if the device was unplugged. A subsequent
// Attach makes the host enumerate the device again.
func (dev *USBDevice) Detach() {
rp.USB.SIE_CTRL.ClearBits(rp.USB_SIE_CTRL_PULLUP_EN)
}

func handleUSBIRQ(intr interrupt.Interrupt) {
status := rp.USB.INTS.Get()

Expand Down
Loading