Skip to content

feat: target board generation [PROPOSAL] #4999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from

Conversation

mikesmitty
Copy link
Contributor

@mikesmitty mikesmitty commented Aug 16, 2025

At the networking SIG meeting the other day we got a little off topic, but one of the things that came up was reducing initial user friction and the relative difficulty of adding support for a new board. One idea that was mentioned was the fact that the -target flag can be used to specify an external json file and at least in my mind is the obvious choice for board-definitions. Its purpose is already to store board-specific information and passing in external json target files would make custom board definitions very easily accessible (a very popular request, of course: #3288, #3152, #2607, #2239)

I took a look over the various board definitions and the vast majority of the code boils down to just a few things:

  • Constants associating board labels, on-board LED(s), etc. to MCU pins
  • Constants or variables specifying the default UART/I2C/SPI pins to be configured
  • Variables specifying USB vendor/product id

All that can be reduced to a template generated from a JSON target file very easily so I put this together and converted a handful of targets as a demo.

The way this works is to take in the board section added to a target definition that contains the pin aliases, usb variables, etc. and templates out a file that is added to the cached TINYGOROOT for that target. I chose to put it into the cache because I wanted to avoid requiring that the TINYGOROOT be writable, but that can be changed pretty easily.

As a handy side-effect, this also makes auto-generating board definitions for already-supported MCUs fairly simple and would further reduce new-user friction if they find that their favorite board is already supported.

@mikesmitty
Copy link
Contributor Author

mikesmitty commented Aug 16, 2025

As an example, here is the file generated for a metro-rp2350 target:
$TINYGOROOT/goroot-$HASHKEY/src/machine/boardgen_metro-rp2350.go

// Code generated by board-generator. DO NOT EDIT.
//go:build cortexm && baremetal && linux && arm && rp2350 && rp && rp2350b && metro_rp2350

package machine

// Pin aliases for the Adafruit Metro RP2350.

const (
	GP0                 = GPIO0
	GP1                 = GPIO1
	GP2                 = GPIO2
	GP3                 = GPIO3
	GP4                 = GPIO4
	GP5                 = GPIO5
	GP6                 = GPIO6
	GP7                 = GPIO7
	GP8                 = GPIO8
	GP9                 = GPIO9
	GP10                = GPIO10
	GP11                = GPIO11
	GP12                = GPIO12
	GP13                = GPIO13
	GP14                = GPIO14
	GP15                = GPIO15
	GP16                = GPIO16
	GP17                = GPIO17
	GP18                = GPIO18
	GP19                = GPIO19
	GP20                = GPIO20
	GP21                = GPIO21
	GP22                = GPIO22
	GP23                = GPIO23
	GP24                = GPIO24
	GP25                = GPIO25
	GP26                = GPIO26
	GP27                = GPIO27
	GP28                = GPIO28
	GP29                = GPIO29
	GP30                = GPIO30
	GP31                = GPIO31
	GP32                = GPIO32
	GP33                = GPIO33
	GP34                = GPIO34
	GP35                = GPIO35
	GP36                = GPIO36
	GP37                = GPIO37
	GP38                = GPIO38
	GP39                = GPIO39
	GP40                = GPIO40
	GP41                = GPIO41
	GP42                = GPIO42
	GP43                = GPIO43
	GP44                = GPIO44
	GP45                = GPIO45
	GP46                = GPIO46
	BUTTON              = GPIO24
	LED                 = GPIO23
	NEOPIXEL            = GPIO25
	WS2812              = GPIO25
	RX                  = GPIO1
	TX                  = GPIO0
	D2                  = GPIO2
	D3                  = GPIO3
	D4                  = GPIO4
	D5                  = GPIO5
	D6                  = GPIO6
	D7                  = GPIO7
	D8                  = GPIO8
	D9                  = GPIO9
	D10                 = GPIO10
	D11                 = GPIO11
	D22                 = GPIO22
	D23                 = GPIO23
	A0                  = GPIO41
	A1                  = GPIO42
	A2                  = GPIO43
	A3                  = GPIO44
	A4                  = GPIO45
	A5                  = GPIO46
	I2C0_SDA_PIN        = GP20
	I2C0_SCL_PIN        = GP21
	I2C1_SDA_PIN        = GP2
	I2C1_SCL_PIN        = GP3
	SPI0_SCK_PIN        = GPIO18
	SPI0_SDO_PIN        = GPIO19
	SPI0_SDI_PIN        = GPIO16
	SPI1_SCK_PIN        = GPIO30
	SPI1_SDO_PIN        = GPIO31
	SPI1_SDI_PIN        = GPIO28
	MOSI                = SPI1_SDO_PIN
	MISO                = SPI1_SDI_PIN
	SCK                 = SPI1_SCK_PIN
	SD_SCK              = GPIO34
	SD_MOSI             = GPIO35
	SD_MISO             = GPIO36
	SDIO_DATA1          = GPIO37
	SDIO_DATA2          = GPIO38
	SD_CS               = GPIO39
	SD_CARD_DETECT      = GPIO40
	CKN                 = GPIO15
	CKP                 = GPIO14
	D0N                 = GPIO19
	D0P                 = GPIO18
	D1N                 = GPIO17
	D1P                 = GPIO16
	D2N                 = GPIO13
	D2P                 = GPIO12
	D26                 = GPIO26
	D27                 = GPIO27
	SCL                 = GPIO21
	SDA                 = GPIO20
	USB_HOST_DATA_PLUS  = GPIO32
	USB_HOST_DATA_MINUS = GPIO33
	USB_HOST_5V_POWER   = GPIO29
	UART0_TX_PIN        = GPIO0
	UART0_RX_PIN        = GPIO1
	UART1_TX_PIN        = GPIO8
	UART1_RX_PIN        = GPIO9
	UART_TX_PIN         = UART0_TX_PIN
	UART_RX_PIN         = UART0_RX_PIN
)

const (
	xoscFreq                = 12
	usb_STRING_MANUFACTURER = "Adafruit"
	usb_STRING_PRODUCT      = "Metro RP2350"
)

var (
	DefaultUART        = UART0
	usb_VID     uint16 = 0x239A
	usb_PID     uint16 = 0x814E
)

@aykevl
Copy link
Member

aykevl commented Aug 17, 2025

Oh this is an interesting approach!
Does this mean the cached GOROOT is board specific now?

@aykevl
Copy link
Member

aykevl commented Aug 17, 2025

I have been thinking about another approach, that is not necessarily competing with this PR but related. It's to provide some configurations (such as clock frequency / crystal selection / USB VID+PID / other configs) through flags set in the JSON file. One issue I have is that I make custom hardware and I run it at a low frequency to reduce current consumption. Right now I basically just reconfigure the clock, but it would be more convenient if I can just set a flag on the command line.

Something like:

{
    // ...
    "configs": {
        "main-clock": ["LSI-131kHz", "LSI-262kHz", "LSI-524kHz", "HSI-16MHz", "HSI-32MHz", ...],
    }
}

And then the clock can be set either in a JSON file or via a command line flag (-config-main-clock=LSI-131kHz etc).

This could then be used in the runtime like so (switch should get optimized at compile time):

switch tinygo.getConfig("main-clock") {
case "LSI-131kHz":
    // configure with main clock set to 131kHz
// etc
}

Something similar could be used for USB VID/PID pairs.

Anyway, this is somewhat off-topic but perhaps another way some configuration could be done. It wouldn't work for pin constants, obviously.

@mikesmitty
Copy link
Contributor Author

Oh this is an interesting approach! Does this mean the cached GOROOT is board specific now?

Yep, I made sure a file with the target name is added to the hash key to make sure it would split the caches out and avoid inter-mixing.

I really like those ideas you mentioned. I'll do some thinking about how they could be integrated

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.

2 participants