tinygo
tinygo copied to clipboard
Compiler option for selecting output implementation
I would like feedback on this as a possible mechanism for allowing to disable the USB CDC implementation on boards where it is the default output for print()
This is useful for devices/applications that need more control over the USB interface. Such a capability is probably a necessity in order to be able to implement other USB interface classes such as HID, MSD, etc.
This draft implementation utilizes a build tag named no_default_usb which causes UART0 (used as the destination for putchar) to be a UART implementation instead of configuring/using USB CDC. Right now I've only implemented this for samd targets, but if it looks good it will be easy to do the same for nrf52840 (which I believe is only other chipset with USB CDC support at the moment)
I have hit a more general problem too. Enabling the UART on Nordic chips means a lot of current is constantly consumed. I fixed this in a battery powered application by disabling the UART, but it's not ideal. So I see three options here:
- Use USB-CDC (when available)
- Use native UART
- Don't provide an output
You could imagine other options such as ARM SemiHosting, which may be useful if the extra UART connection is inconvenient or unavailable.
Strawman proposal: add a -output flag to the compiler which can be set as needed (-output=usb, -output=uart, -output=none). The builder will set a build tag accordingly, such as output.uart. This is more extensible than the binary option with a single build tag.
What do you think?
Strawman proposal: add a -output flag to the compiler which can be set as needed (-output=usb, -output=uart, -output=none). The builder will set a build tag accordingly, such as output.uart. This is more extensible than the binary option with a single build tag.
Good idea.
I agree, I think it is a good proposal, especially if we add that option as something that can be specified in the target JSON file (and overridden from the command line of course).
As long as we are considering general cases, one other configuration would be to allow for a custom putchar function. Currently this is more or less impossible on most platforms because it would require replacing machine.UART0, which is for the most part a concrete type. Maybe that is something that could be added later after the options you mentioned for the -output flag are implemented, just wanted to mention it now though in case it is worth considering as it is sort of the most general case I can think of.
Yes, now you say it, that should definitely be possible. I've considered it before but didn't see a good way to do it. However, I think this would work, perhaps with -output=custom that allows setting a custom putchar function with no impact on normal execution:
// +build output.custom
package runtime
var customOutput func(c char)
func putchar(c char) {
if customOutput != nil {
customOutput(c)
}
}
func SetOutput(putchar func(c char)) {
customOutput = putchar
}
Regarding implementation, I would propose the following:
- Provide a new
outputproperty that is set in the JSON file but can also be overridden from the command line. On many chips, it is set touart. On some chips it isusb(orusb-cdc?), on very bare bones chips it may be set tonone(e.g. the Digispark, which doesn't have hardware UART support). - The compiler automatically adds a new build tag based on this, for example
output.uart(analogous toscheduler.tasks). - Each target doesn't implement the generic
putcharand doesn't configure the output at startup. Instead, it provides a number of functions for each:uartPutchar,uartConfigure,usbPutchar,usbConfigure, etc. - A few new runtime files (for example src/runtime/output-uart.go, src/runtime/output-usb.go etc) provide generic
outputConfigureandputcharfunctions that call the target or board specific functions such asuartPutchar.
This design also avoids odd things like the following, by using the none output instead:
https://github.com/tinygo-org/tinygo/blob/26a0819119287713efe95f2ec0c091070c0bd3a3/src/runtime/runtime_arm7tdmi.go#L12-L14
Yes, in my opinion that is a good design that can be implemented cleanly. I can go ahead and get started implementing this and have it ready for review pretty soon