Skip to content

Puya PY32F MCU support#5106

Open
burgrp wants to merge 31 commits intotinygo-org:devfrom
burgrp:py32
Open

Puya PY32F MCU support#5106
burgrp wants to merge 31 commits intotinygo-org:devfrom
burgrp:py32

Conversation

@burgrp
Copy link

@burgrp burgrp commented Dec 2, 2025

Hi, this is a port of of Puya PY32F super-cheap micro-controllers.
There are two new boards and supported (available on Aliexpress) for PY32F030 and PY32002b.
PY32F030 and PY32002b are supported, PY32F002a and PY32F071 will follow.
It follows the STM32 SVD pattern - there's a small TinyGo SVD repository dependent on Rust py32-rs repo. The repository is here: https://github.com/burgrp/py32-svd . I think it would be worth to move it to tinygo-org.

@deadprogram
Copy link
Member

Hello @burgrp thank you for working on this.

Have you seen this page?
https://tinygo.org/docs/guides/contributing

I think you will find it helpful. 😸

@deadprogram deadprogram changed the base branch from release to dev December 13, 2025 18:43
@deadprogram
Copy link
Member

@burgrp I have switched the branch for this PR to dev branch as mentioned here:
https://tinygo.org/docs/guides/contributing/#how-to-use-our-github-repository

Can you please rebase it against the latest dev so it can run all of the latest tests?
Also I made a few comments.

Planning on ordering a few of these myself, thanks for working on it!

@b0ch3nski
Copy link
Contributor

@burgrp You are updating bdwgc submodule which is probably not something you meant to do - this breaks a lot of stuff 🔥

@burgrp
Copy link
Author

burgrp commented Jan 27, 2026

You are right... I will fix it and hopefully it will be possible to merge the PR.

@burgrp
Copy link
Author

burgrp commented Feb 13, 2026

@b0ch3nski , the sub-module issue is fixed, all checks are passing

@b0ch3nski
Copy link
Contributor

Thanks! I think now there is some unrelated change also in net submodule 😬

@deadprogram
Copy link
Member

@b0ch3nski looks that way to me as well: https://github.com/tinygo-org/tinygo/pull/5106/changes#diff-d7ea94295bc068e99e5edeacb50734849fb40d5aa39cbc68be5e55c0d90bd60a

@burgrp one other thing that is needed is to add something to the smoketests to show that at least everything can build. Someplace appropriate in here, please: https://github.com/tinygo-org/tinygo/blob/dev/GNUmakefile#L567-L989

burgrp and others added 5 commits February 21, 2026 00:00
@burgrp
Copy link
Author

burgrp commented Feb 21, 2026

@b0ch3nski , @deadprogram smoketests added, net module update reverted

return uint8(p) & 0x0F
}

func (p Pin) getPort() (*py32.GPIO_Type, uint8) {
Copy link
Member

Choose a reason for hiding this comment

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

Better to use unsafe.Add() if you must. Probably even better to use a switch to avoid possible errors.

switch config.Mode {

case PinInputFloating:
port.MODER.ReplaceBits(gpioModeInput, gpioModeMask, pos)
Copy link
Member

Choose a reason for hiding this comment

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

I have not installed/run the gen-device-py32 yet, but I assume there are probably some functions like SetMODERInput() that are being generated. Using these are usually preferable, to avoid possible bugs from setting unexpected bits.

Copy link
Author

Choose a reason for hiding this comment

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

Unfortunately there is no SetMODERInput() generated. These helper functions are generated in form SetMODER_MODE0()...SetMODER_MODE15(), which are quite useless for parametric access.
I've fixed the machine constants to use the svd pin0 generated constants e.g.:
gpioModeOutput = py32.GPIO_MODER_MODE0_Output
so there is at least some binding to svd values.

const PinInput PinMode = PinInputFloating

const (
gpioModeInput = 0
Copy link
Member

Choose a reason for hiding this comment

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

Are any of these being generated from the SVD file already? See comment below.

Copy link
Author

Choose a reason for hiding this comment

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

See my comment above.

// peripheral clock frequency.
func InitSerialWithClock(clockHz uint32) {
py32UARTClockHz = clockHz
//Serial.ConfigureWithClock(UARTConfig{}, clockHz)
Copy link
Member

Choose a reason for hiding this comment

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

Commented line?

Copy link
Author

Choose a reason for hiding this comment

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

Fixed

py32.RCC.SetICSCR_HSI_FS(py32.RCC_ICSCR_HSI_FS_Freq24MHz)

ConfigureSystemTimer(24_000_000)
machine.InitSerial()
Copy link
Member

Choose a reason for hiding this comment

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

This perhaps needs to be moved into an init() function?

See #5200 (comment)

Copy link
Author

Choose a reason for hiding this comment

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

Fixed

],
"build-tags": [
"embedfire_py32f002b",
"default_uart_pins"
Copy link
Member

Choose a reason for hiding this comment

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

Formatting, please.

Copy link
Author

Choose a reason for hiding this comment

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

Fixed

@deadprogram
Copy link
Member

This is getting exciting @burgrp thank you so much for working on it! We were discussing during our TinyGo monthly meeting last night ❤️

I made some comments, hopefully @soypat and others can also take a look.

@soypat
Copy link
Contributor

soypat commented Feb 24, 2026

I've taken a look and have some reservations on exported API chosen. I'd like to better understand how we define APIs in machine package to understand if the exported functions implemented here match with what the rest of TinyGo does. Basically working on getting something like go doc -tags=rp2040 machine to work (which it does not currently)

@soypat
Copy link
Contributor

soypat commented Feb 25, 2026

I vibe coded a tool to help us understand the tinygo APIs better. I'll invite you all to check it out to understand what our APIs look like in TinyGo #5224

Copy link
Contributor

@soypat soypat left a comment

Choose a reason for hiding this comment

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

Running tgdoc I've found what look like discrepancies with usual TinyGo API.

You can browse our APIs by running go run ./cmd/tgdoc -http=:18080 ../tinygo/targets ../tinygo/src/machine given tinygodoc shares tinygo parent directory
https://github.com/tinygo-org/tinygodoc


// ConfigureWithClock initializes the UART using the provided peripheral clock
// frequency (in Hz). This avoids assuming a fixed MCU clock.
func (uart *UART) ConfigureWithClock(config UARTConfig, clockHz uint32) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

can we replace clockHz with CPUFrequency() internal call to Configure?

Copy link
Author

Choose a reason for hiding this comment

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

Fixed


// InitSerialWithClock configures the default Serial using the supplied
// peripheral clock frequency.
func InitSerialWithClock(clockHz uint32) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above, use CPUFrequency(). It is standard tinygo API, present on 160 targets.

Image
Copy link
Author

Choose a reason for hiding this comment

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

Fixed

}

// Configure pin for use by UART
func ConfigureUARTPin(pin Pin, af uint8) {
Copy link
Contributor

@soypat soypat Mar 2, 2026

Choose a reason for hiding this comment

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

Shouldn't this be Pin.Configure followed by an SetAltFunc? (is it really necessary to export this?)

Copy link
Contributor

Choose a reason for hiding this comment

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

Or unexport it if it is expected to only be called internally for UART configuration

Copy link
Author

@burgrp burgrp Mar 3, 2026

Choose a reason for hiding this comment

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

You are right, cleaned up to just Pin.Configure+SetAltFunc.
This needs to be exported, because other boards may need explicit call for non-default UART pins.

Comment on lines +16 to +18
func SetCPUFrequency(frequency uint32) {
CPUFrequencyHz = frequency
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a very confusing API- it does not actually change the frequency. Prefer unexporting it and either linking with //go:linkname compiler directive from runtime package or setting as constant at build time.

Copy link
Author

Choose a reason for hiding this comment

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

I agree - the function is removed. The variable CPUFrequencyHz still needs to be exported to allow clock change from user code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you want to allow changing CPU frequency from user code?

Copy link
Contributor

Choose a reason for hiding this comment

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

This API does not exist yet in TinyGo, we'd likely need to discuss the best design going forward if we are to add it

Copy link
Author

Choose a reason for hiding this comment

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

For two simple reasons (correct me if I'm not seeing something):

  1. TinyGo comes with a finite set of supported dev boards. In practice, final product boards differ, so they may need other setting.
  2. There may be application which need to set clock dynamically, e.g. to save energy.
Copy link
Contributor

Choose a reason for hiding this comment

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

Are you in immediate need of any of the two? I'm very hesitant on adding this API, especially if it is counter-intuitive. Setting the value of CPUFrequencyHz does not actually modify anything about the CPU's frequency. This is not good API design. We need to discuss this API before adding it

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I need that for one of my projects. Thanks for being open to discuss it!

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd hate for this to stay in a stale state while we discuss the CPUFrequency API. Could you implement CPU frequency API on your side and test things and let us know how your experimentation goes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants