mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
machine: add simulated PWM/timer peripherals
I will soon use these as part of the TinyGo tour, to explain the PWM peripherals on common chips.
This commit is contained in:
committed by
Ron Evans
parent
612a38e363
commit
72b19555dc
@@ -0,0 +1,45 @@
|
||||
//go:build !baremetal && (gemma_m0 || qtpy || trinket_m0 || arduino_mkr1000 || arduino_mkrwifi1010 || arduino_nano33 || arduino_zero || circuitplay_express || feather_m0_express || feather_m0 || itsybitsy_m0 || p1am_100 || xiao)
|
||||
|
||||
// Simulated atsamd21 chips.
|
||||
|
||||
package machine
|
||||
|
||||
// The timer channels/pins match the hardware, and encode the same information
|
||||
// as pinTimerMapping but in a more generic (less efficient) way.
|
||||
|
||||
var TCC0 = timerType{
|
||||
instance: 0,
|
||||
frequency: 48e6,
|
||||
bits: 24,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 64, 256, 1024},
|
||||
channelPins: [][]Pin{
|
||||
{PA04, PA08, PB10, PA14, PB16, PA22, PB30}, // channel 0
|
||||
{PA05, PA09, PB11, PA15, PB17, PA23, PB31}, // channel 1
|
||||
{PA10, PB12, PA12, PA16, PA18, PA20}, // channel 2
|
||||
{PA11, PB13, PA13, PA17, PA19, PA21}, // channel 3
|
||||
},
|
||||
}
|
||||
|
||||
var TCC1 = timerType{
|
||||
instance: 1,
|
||||
frequency: 48e6,
|
||||
bits: 24,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 64, 256, 1024},
|
||||
channelPins: [][]Pin{
|
||||
{PA06, PA10, PA30}, // channel 0
|
||||
{PA07, PA11, PA31}, // channel 1
|
||||
{PA08, PA24, PB30}, // channel 2
|
||||
{PA09, PA25, PB31}, // channel 3
|
||||
},
|
||||
}
|
||||
|
||||
var TCC2 = timerType{
|
||||
instance: 2,
|
||||
frequency: 48e6,
|
||||
bits: 16,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 64, 256, 1024},
|
||||
channelPins: [][]Pin{
|
||||
{PA00, PA12, PA16}, // channel 0
|
||||
{PA01, PA13, PA17}, // channel 1
|
||||
},
|
||||
}
|
||||
@@ -48,6 +48,103 @@ func gpioSet(pin Pin, value bool)
|
||||
//export __tinygo_gpio_get
|
||||
func gpioGet(pin Pin) bool
|
||||
|
||||
// Generic PWM/timer peripheral. Properties can be configured depending on the
|
||||
// hardware.
|
||||
type timerType struct {
|
||||
// Static properties.
|
||||
instance int32
|
||||
frequency uint64
|
||||
bits int
|
||||
prescalers []int
|
||||
channelPins [][]Pin
|
||||
|
||||
// Configured 'top' value.
|
||||
top uint32
|
||||
}
|
||||
|
||||
// Configure the PWM/timer peripheral.
|
||||
func (t *timerType) Configure(config PWMConfig) error {
|
||||
// Note: for very large period values, this multiplication will overflow.
|
||||
top := config.Period * t.frequency / 1e9
|
||||
if config.Period == 0 {
|
||||
top = 0xffff // default for LEDs
|
||||
}
|
||||
|
||||
// The maximum value that can be stored with the given number of bits in
|
||||
// this timer.
|
||||
maxTop := uint64(1)<<uint64(t.bits) - 1
|
||||
|
||||
// Look for an appropriate prescaler value.
|
||||
var prescaler int
|
||||
for _, div := range t.prescalers {
|
||||
if top/uint64(div) <= maxTop {
|
||||
prescaler = div
|
||||
top = top / uint64(div)
|
||||
break
|
||||
}
|
||||
}
|
||||
if prescaler == 0 {
|
||||
return ErrPWMPeriodTooLong
|
||||
}
|
||||
|
||||
// Set these values as the configuration.
|
||||
t.top = uint32(top)
|
||||
pwmConfigure(t.instance, float64(t.frequency)/float64(prescaler), uint32(top))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Channel returns a PWM channel for the given pin. Note that one channel may be
|
||||
// shared between multiple pins, and so will have the same duty cycle. If this
|
||||
// is not desirable, look for a different PWM/timer peripheral or consider using
|
||||
// a different pin.
|
||||
func (t *timerType) Channel(pin Pin) (uint8, error) {
|
||||
for ch, pins := range t.channelPins {
|
||||
// For nrf52xxx chips specifically we can assign any channel to any pin.
|
||||
// We use a similar (identical?) logic to the hardware implementation,
|
||||
// and pick the first empty channel.
|
||||
if pins == nil {
|
||||
t.channelPins[ch] = []Pin{pin}
|
||||
pwmChannelConfigure(t.instance, int32(ch), pin)
|
||||
return uint8(ch), nil
|
||||
}
|
||||
|
||||
// Check whether the pin can be used on this channel.
|
||||
for _, p := range pins {
|
||||
if p == pin {
|
||||
pwmChannelConfigure(t.instance, int32(ch), pin)
|
||||
return uint8(ch), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0, ErrInvalidOutputPin
|
||||
}
|
||||
|
||||
func (t *timerType) Set(channel uint8, value uint32) {
|
||||
pwmChannelSet(t.instance, channel, value)
|
||||
}
|
||||
|
||||
// Top returns the current counter top, for use in duty cycle calculation. It
|
||||
// will only change with a call to Configure or SetPeriod, otherwise it is
|
||||
// constant.
|
||||
//
|
||||
// The value returned here is hardware dependent. In general, it's best to treat
|
||||
// it as an opaque value that can be divided by some number and passed to Set
|
||||
// (see Set documentation for more information).
|
||||
func (t *timerType) Top() uint32 {
|
||||
return t.top
|
||||
}
|
||||
|
||||
//export __tinygo_pwm_configure
|
||||
func pwmConfigure(instance int32, frequency float64, top uint32)
|
||||
|
||||
//export __tinygo_pwm_channel_configure
|
||||
func pwmChannelConfigure(instance, channel int32, pin Pin)
|
||||
|
||||
//export __tinygo_pwm_channel_set
|
||||
func pwmChannelSet(instance int32, channel uint8, value uint32)
|
||||
|
||||
type SPI struct {
|
||||
Bus uint8
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
//go:build !baremetal && (bluemicro840 || circuitplay_bluefruit || clue_alpha || feather_nrf52840_sense || feather_nrf52840 || itsybitsy_nrf52840 || mdbt50qrx || nano_33_ble || nicenano || nrf52840_mdk || particle_3rd_gen || pca10056 || pca10059 || rak4631 || reelboard || xiao_ble)
|
||||
|
||||
// Simulator support for nrf52840 based boards.
|
||||
|
||||
package machine
|
||||
|
||||
// Channel values below are nil, so that they get filled in on the first use.
|
||||
// This is the same as what happens on baremetal.
|
||||
|
||||
var PWM0 = timerType{
|
||||
instance: 0,
|
||||
frequency: 16e6,
|
||||
bits: 15,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128},
|
||||
channelPins: [][]Pin{
|
||||
nil, // channel 0
|
||||
nil, // channel 1
|
||||
nil, // channel 2
|
||||
nil, // channel 3
|
||||
},
|
||||
}
|
||||
|
||||
var PWM1 = timerType{
|
||||
instance: 1,
|
||||
frequency: 16e6,
|
||||
bits: 15,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128},
|
||||
channelPins: [][]Pin{
|
||||
nil, // channel 0
|
||||
nil, // channel 1
|
||||
nil, // channel 2
|
||||
nil, // channel 3
|
||||
},
|
||||
}
|
||||
|
||||
var PWM2 = timerType{
|
||||
instance: 2,
|
||||
frequency: 16e6,
|
||||
bits: 15,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128},
|
||||
channelPins: [][]Pin{
|
||||
nil, // channel 0
|
||||
nil, // channel 1
|
||||
nil, // channel 2
|
||||
nil, // channel 3
|
||||
},
|
||||
}
|
||||
|
||||
var PWM3 = timerType{
|
||||
instance: 3,
|
||||
frequency: 16e6,
|
||||
bits: 15,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128},
|
||||
channelPins: [][]Pin{
|
||||
nil, // channel 0
|
||||
nil, // channel 1
|
||||
nil, // channel 2
|
||||
nil, // channel 3
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
//go:build !baremetal && (ae_rp2040 || badger2040_w || badger2040 || challenger_rp2040 || elecrow_rp2040 || feather_rp2040 || gopher_badge || kb2040 || macropad_rp2040 || nano_rp2040 || pico || qtpy_rp2040 || thingplus_rp2040 || thumby || trinkey_qt2040 || tufty2040 || waveshare_rp2040_tiny || waveshare_rp2040_zero || xiao_rp2040)
|
||||
|
||||
// Simulator support for the RP2040.
|
||||
//
|
||||
// This is *only* for the RP2040. RP2350 is a different chip with slightly
|
||||
// different characteristics.
|
||||
|
||||
package machine
|
||||
|
||||
var PWM0 = timerType{
|
||||
instance: 0,
|
||||
frequency: 200e6,
|
||||
bits: 16,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256}, // actually a continuing range, TODO
|
||||
channelPins: [][]Pin{
|
||||
{GPIO0, GPIO16}, // channel A (0)
|
||||
{GPIO1, GPIO17}, // channel B (1)
|
||||
},
|
||||
}
|
||||
|
||||
var PWM1 = timerType{
|
||||
instance: 0,
|
||||
frequency: 200e6,
|
||||
bits: 16,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256},
|
||||
channelPins: [][]Pin{
|
||||
{GPIO2, GPIO18}, // channel A (0)
|
||||
{GPIO3, GPIO19}, // channel B (1)
|
||||
},
|
||||
}
|
||||
|
||||
var PWM2 = timerType{
|
||||
instance: 0,
|
||||
frequency: 200e6,
|
||||
bits: 16,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256},
|
||||
channelPins: [][]Pin{
|
||||
{GPIO4, GPIO20}, // channel A (0)
|
||||
{GPIO5, GPIO21}, // channel B (1)
|
||||
},
|
||||
}
|
||||
|
||||
var PWM3 = timerType{
|
||||
instance: 0,
|
||||
frequency: 200e6,
|
||||
bits: 16,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256},
|
||||
channelPins: [][]Pin{
|
||||
{GPIO6, GPIO22}, // channel A (0)
|
||||
{GPIO7, GPIO23}, // channel B (1)
|
||||
},
|
||||
}
|
||||
|
||||
var PWM4 = timerType{
|
||||
instance: 0,
|
||||
frequency: 200e6,
|
||||
bits: 16,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256},
|
||||
channelPins: [][]Pin{
|
||||
{GPIO8, GPIO24}, // channel A (0)
|
||||
{GPIO9, GPIO25}, // channel B (1)
|
||||
},
|
||||
}
|
||||
|
||||
var PWM5 = timerType{
|
||||
instance: 0,
|
||||
frequency: 200e6,
|
||||
bits: 16,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256},
|
||||
channelPins: [][]Pin{
|
||||
{GPIO10, GPIO26}, // channel A (0)
|
||||
{GPIO11, GPIO27}, // channel B (1)
|
||||
},
|
||||
}
|
||||
|
||||
var PWM6 = timerType{
|
||||
instance: 0,
|
||||
frequency: 200e6,
|
||||
bits: 16,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256},
|
||||
channelPins: [][]Pin{
|
||||
{GPIO12, GPIO28}, // channel A (0)
|
||||
{GPIO13, GPIO29}, // channel B (1)
|
||||
},
|
||||
}
|
||||
|
||||
var PWM7 = timerType{
|
||||
instance: 0,
|
||||
frequency: 200e6,
|
||||
bits: 16,
|
||||
prescalers: []int{1, 2, 4, 8, 16, 32, 64, 128, 256},
|
||||
channelPins: [][]Pin{
|
||||
{GPIO14}, // channel A (0)
|
||||
{GPIO15}, // channel B (1)
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user