-
Notifications
You must be signed in to change notification settings - Fork 946
machine/rp2040: add PWM implementation #2015
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
Conversation
Tests have failed probably because two functions are missing: PWM Blinky Examplepackage main
import (
"machine"
"time"
)
var (
LED = machine.GPIO25
pin2 = machine.GPIO26
uart = machine.UART0
)
func main() {
// configure UART to print stuff
{
err := uart.Configure(machine.UARTConfig{BaudRate: 9600})
if err != nil {
panic(err)
}
}
pin := LED
pin.Configure(machine.PinConfig{Mode: machine.PinPWM})
pwm, err := machine.NewPWM(pin)
if err != nil {
println(err.Error())
}
var per uint64 = 1e9 / 500
err = pwm.Configure(machine.PWMConfig{Period: per})
if err != nil {
println(err.Error())
}
ch, err := pwm.Channel(pin)
if err != nil {
println(err.Error())
}
println("slice", pwm.Peripheral(pin), " ch:", ch)
if !pwm.IsEnabled() {
println("NOT ENABLED")
}
println("period:", pwm.Period(), "target_period:", per)
time.Sleep(time.Millisecond)
for {
for i := 1; i < 255; i++ {
pwm.Set(ch, pwm.Top()/uint32(i))
time.Sleep(time.Millisecond * 5)
}
}
} |
Ready for resolve of merge conflicts, please. 😸 |
@deadprogram Done dealio |
Hello @deadprogram, seems like I used the wrong function name for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that the PWM of the RP2040 is structured a little bit differently than other chips: it groups all PWM timers into one peripheral. Most chips have multiple PWMs where each PWM instance has just one timer. However, if you look closely you can see that it is actually not that different: it's as if the RP2040 has 8 PWM peripherals that each have two channel outputs. Therefore, I would suggest exposing it like that:
var (
PWM0 = ...
PWM1 = ...
PWM2 = ...
// etc
}
In this API, you can use the PWM like this:
pwm := machine.PWM0
pwm.Configure(...) // enables the given PWM
ch, _ := pwm.Channel(pin) // configures the pin
ch.Set(ch, value) // set the channel value
I understand the need for a NewPWM
, and I agree we should have something like that (also for other chips). However, there is one big catch: it's not clear which PWMs alias each other. For example, if you set the frequency for pin 2, it will also change the frequency for pin 3, 18, and 19. This is in fact one of the main reasons of the somewhat complex API. That's why I would suggest leaving it out for now.
(Also, I think the name NewPWM
is misleading as the function doesn't create anything new: PWM resources are fixed hardware resources and can't be made on the fly).
src/machine/machine_rp2040_pwm.go
Outdated
targetPeriod := uint32(period) | ||
periodPerCycle := getPeriod() | ||
top := pwm.getWrap(sliceNum) | ||
phc := pwm.getPhaseCorrect(sliceNum) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment, phase correct PWM isn't supported so I would suggest not taking this into account.
(I believe phase correct PWM is only relevant for specific motor control applications)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean I should leave it commented out as a TODO for when phase correct is added, if ever?
@aykevl I've applied sweeping changes inspired by your comments. There may be more use of unsafe but I think this is much cleaner. Let me know what you think! |
CI tests are failing, and there is a merge conflict. Can you please look at that @soypat thank you! |
I changed a method to a function. One can obtain the peripheral number with |
Was not able to get working with the PWM example in the main TinyGo examples. Some mappings are missing, and I might not have them correct for the Pico board. |
add documentation rp2040 pwm fixes and functionality added machine/rp2040: add PWM implementation
@deadprogram I had to add a |
Next release of TinyGo should have support for I2C+SPI+PWM. PWM would be supported as soon as tinygo-org/tinygo#2015 is merged. Added some pointers on how to debug/get USB output using picoprobe.
Tested and is now working as expected. Squashing/merging now, thanks for working on this @soypat |
* 'dev' of github.com:tinygo-org/tinygo: src/runtime: reset heapptr to heapStart after preinit() docker: use go 1.17 for docker dev build machine/feather-rp2040: add pin name definition for feather targets: add openocd configuration for rp2040 Implement os.Executable board/nano-rp2040: define NINA_SPI and fix wifinina pins machine/rp2040: add PWM implementation (tinygo-org#2015)
Next release of TinyGo should have support for I2C+SPI+PWM. PWM would be supported as soon as tinygo-org/tinygo#2015 is merged. Added some pointers on how to debug/get USB output using picoprobe.
Next release of TinyGo should have support for I2C+SPI+PWM. PWM would be supported as soon as tinygo-org/tinygo#2015 is merged. Added some pointers on how to debug/get USB output using picoprobe.
Next release of TinyGo should have support for I2C+SPI+PWM. PWM would be supported as soon as tinygo-org/tinygo#2015 is merged. Added some pointers on how to debug/get USB output using picoprobe.
Please take a look. Tested and works with on-board LED and GPIO5. Solves #1993 .