mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-06 20:13:40 +00:00
machine/rp2350: extending support to include the rp2350b
This commit is contained in:
@@ -16,6 +16,8 @@ const (
|
||||
// Note: On RP2350, most spinlocks are unusable due to Errata 2
|
||||
_NUMSPINLOCKS = 32
|
||||
_PICO_SPINLOCK_ID_IRQ = 9
|
||||
// is48Pin notes whether the chip is RP2040 with 32 pins or RP2350 with 48 pins.
|
||||
is48Pin = _NUMBANK0_GPIOS == 48
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
|
||||
@@ -45,6 +45,16 @@ const (
|
||||
PinPIO1
|
||||
)
|
||||
|
||||
// Analog pins on RP2040.
|
||||
const (
|
||||
ADC0 Pin = GPIO26
|
||||
ADC1 Pin = GPIO27
|
||||
ADC2 Pin = GPIO28
|
||||
ADC3 Pin = GPIO29
|
||||
|
||||
thermADC = 30
|
||||
)
|
||||
|
||||
const (
|
||||
clkGPOUT0 clockIndex = iota // GPIO Muxing 0
|
||||
clkGPOUT1 // GPIO Muxing 1
|
||||
|
||||
@@ -33,6 +33,16 @@ const (
|
||||
rp.PADS_BANK0_GPIO0_ISO_Msk
|
||||
)
|
||||
|
||||
// Analog pins on RP2350.
|
||||
const (
|
||||
ADC0 Pin = GPIO26
|
||||
ADC1 Pin = GPIO27
|
||||
ADC2 Pin = GPIO28
|
||||
ADC3 Pin = GPIO29
|
||||
|
||||
thermADC = 30
|
||||
)
|
||||
|
||||
const (
|
||||
PinOutput PinMode = iota
|
||||
PinInput
|
||||
@@ -126,11 +136,17 @@ func (p Pin) Configure(config PinConfig) {
|
||||
return
|
||||
}
|
||||
p.init()
|
||||
mask := uint32(1) << p
|
||||
|
||||
switch config.Mode {
|
||||
case PinOutput:
|
||||
p.setFunc(fnSIO)
|
||||
rp.SIO.GPIO_OE_SET.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OE_SET.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OE_SET.Set(mask)
|
||||
}
|
||||
case PinInput:
|
||||
p.setFunc(fnSIO)
|
||||
p.pulloff()
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
//go:build rp2350b
|
||||
|
||||
package machine
|
||||
|
||||
// RP2350B has additional pins.
|
||||
|
||||
const (
|
||||
GPIO30 Pin = 30 // peripherals: PWM7 channel A
|
||||
GPIO31 Pin = 31 // peripherals: PWM7 channel B
|
||||
GPIO32 Pin = 32 // peripherals: PWM8 channel A
|
||||
GPIO33 Pin = 33 // peripherals: PWM8 channel B
|
||||
GPIO34 Pin = 34 // peripherals: PWM9 channel A
|
||||
GPIO35 Pin = 35 // peripherals: PWM9 channel B
|
||||
GPIO36 Pin = 36 // peripherals: PWM10 channel A
|
||||
GPIO37 Pin = 37 // peripherals: PWM10 channel B
|
||||
GPIO38 Pin = 38 // peripherals: PWM11 channel A
|
||||
GPIO39 Pin = 39 // peripherals: PWM11 channel B
|
||||
GPIO40 Pin = 40 // peripherals: PWM8 channel A
|
||||
GPIO41 Pin = 41 // peripherals: PWM8 channel B
|
||||
GPIO42 Pin = 42 // peripherals: PWM9 channel A
|
||||
GPIO43 Pin = 43 // peripherals: PWM9 channel B
|
||||
GPIO44 Pin = 44 // peripherals: PWM10 channel A
|
||||
GPIO45 Pin = 45 // peripherals: PWM10 channel B
|
||||
GPIO46 Pin = 46 // peripherals: PWM11 channel A
|
||||
GPIO47 Pin = 47 // peripherals: PWM11 channel B
|
||||
)
|
||||
|
||||
// Analog pins on 2350b.
|
||||
const (
|
||||
ADC0 Pin = GPIO40
|
||||
ADC1 Pin = GPIO41
|
||||
ADC2 Pin = GPIO42
|
||||
ADC3 Pin = GPIO43
|
||||
ADC4 Pin = GPIO44
|
||||
ADC5 Pin = GPIO45
|
||||
ADC6 Pin = GPIO46
|
||||
ADC7 Pin = GPIO47
|
||||
|
||||
thermADC = 48
|
||||
)
|
||||
|
||||
// Additional PWMs on the RP2350B.
|
||||
var (
|
||||
PWM8 = getPWMGroup(8)
|
||||
PWM9 = getPWMGroup(9)
|
||||
PWM10 = getPWMGroup(10)
|
||||
PWM11 = getPWMGroup(11)
|
||||
)
|
||||
@@ -11,15 +11,6 @@ import (
|
||||
// ADCChannel is the ADC peripheral mux channel. 0-4.
|
||||
type ADCChannel uint8
|
||||
|
||||
// ADC channels. Only ADC_TEMP_SENSOR is public. The other channels are accessed via Machine.ADC objects
|
||||
const (
|
||||
adc0_CH ADCChannel = iota
|
||||
adc1_CH
|
||||
adc2_CH
|
||||
adc3_CH // Note: GPIO29 not broken out on pico board
|
||||
adcTempSensor // Internal temperature sensor channel
|
||||
)
|
||||
|
||||
// Used to serialise ADC sampling
|
||||
var adcLock sync.Mutex
|
||||
|
||||
@@ -58,20 +49,10 @@ func (a ADC) Get() uint16 {
|
||||
|
||||
// GetADCChannel returns the channel associated with the ADC pin.
|
||||
func (a ADC) GetADCChannel() (c ADCChannel, err error) {
|
||||
err = nil
|
||||
switch a.Pin {
|
||||
case ADC0:
|
||||
c = adc0_CH
|
||||
case ADC1:
|
||||
c = adc1_CH
|
||||
case ADC2:
|
||||
c = adc2_CH
|
||||
case ADC3:
|
||||
c = adc3_CH
|
||||
default:
|
||||
err = errors.New("no ADC channel for pin value")
|
||||
if a.Pin < ADC0 {
|
||||
return 0, errors.New("no ADC channel for pin value")
|
||||
}
|
||||
return c, err
|
||||
return ADCChannel(a.Pin - ADC0), nil
|
||||
}
|
||||
|
||||
// Configure sets the channel's associated pin to analog input mode.
|
||||
@@ -113,12 +94,12 @@ func ReadTemperature() (millicelsius int32) {
|
||||
if rp.ADC.CS.Get()&rp.ADC_CS_EN == 0 {
|
||||
InitADC()
|
||||
}
|
||||
|
||||
thermChan, _ := ADC{Pin: thermADC}.GetADCChannel()
|
||||
// Enable temperature sensor bias source
|
||||
rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN)
|
||||
|
||||
// T = 27 - (ADC_voltage - 0.706)/0.001721
|
||||
return (27000<<16 - (int32(adcTempSensor.getVoltage())-706<<16)*581) >> 16
|
||||
return (27000<<16 - (int32(thermChan.getVoltage())-706<<16)*581) >> 16
|
||||
}
|
||||
|
||||
// waitForReady spins waiting for the ADC peripheral to become ready.
|
||||
@@ -129,18 +110,5 @@ func waitForReady() {
|
||||
|
||||
// The Pin method returns the GPIO Pin associated with the ADC mux channel, if it has one.
|
||||
func (c ADCChannel) Pin() (p Pin, err error) {
|
||||
err = nil
|
||||
switch c {
|
||||
case adc0_CH:
|
||||
p = ADC0
|
||||
case adc1_CH:
|
||||
p = ADC1
|
||||
case adc2_CH:
|
||||
p = ADC2
|
||||
case adc3_CH:
|
||||
p = ADC3
|
||||
default:
|
||||
err = errors.New("no associated pin for channel")
|
||||
}
|
||||
return p, err
|
||||
return Pin(c) + ADC0, nil
|
||||
}
|
||||
|
||||
@@ -13,12 +13,6 @@ func CPUFrequency() uint32 {
|
||||
return 125 * MHz
|
||||
}
|
||||
|
||||
// Returns the period of a clock cycle for the raspberry pi pico in nanoseconds.
|
||||
// Used in PWM API.
|
||||
func cpuPeriod() uint32 {
|
||||
return 1e9 / CPUFrequency()
|
||||
}
|
||||
|
||||
// clockIndex identifies a hardware clock
|
||||
type clockIndex uint8
|
||||
|
||||
|
||||
@@ -63,8 +63,13 @@ func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||
|
||||
// set drives the pin high
|
||||
func (p Pin) set() {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_SET.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OUT_SET.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_SET.Set(mask)
|
||||
}
|
||||
}
|
||||
|
||||
func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||
@@ -73,18 +78,31 @@ func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||
|
||||
// clr drives the pin low
|
||||
func (p Pin) clr() {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_CLR.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OUT_CLR.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_CLR.Set(mask)
|
||||
}
|
||||
}
|
||||
|
||||
// xor toggles the pin
|
||||
func (p Pin) xor() {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_XOR.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OUT_XOR.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_XOR.Set(mask)
|
||||
}
|
||||
}
|
||||
|
||||
// get returns the pin value
|
||||
func (p Pin) get() bool {
|
||||
if is48Pin && p >= 32 {
|
||||
return rp.SIO.GPIO_HI_IN.HasBits(1 << (p % 32))
|
||||
}
|
||||
return rp.SIO.GPIO_IN.HasBits(1 << p)
|
||||
}
|
||||
|
||||
@@ -134,8 +152,13 @@ func (p Pin) setFunc(fn pinFunc) {
|
||||
|
||||
// init initializes the gpio pin
|
||||
func (p Pin) init() {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OE_CLR.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OE_CLR.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OE_CLR.Set(mask)
|
||||
}
|
||||
p.clr()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build rp2040 || rp2350 || ae_rp2040 || badger2040 || challenger_rp2040 || feather_rp2040 || gopher_badge || kb2040 || macropad_rp2040 || nano_rp2040 || pico || qtpy_rp2040 || thingplus_rp2040 || thumby || tufty2040 || waveshare_rp2040_zero || xiao_rp2040
|
||||
//go:build rp2040 || rp2350 || gopher_badge
|
||||
|
||||
package machine
|
||||
|
||||
@@ -34,10 +34,4 @@ const (
|
||||
GPIO27 Pin = 27 // peripherals: PWM5 channel B
|
||||
GPIO28 Pin = 28 // peripherals: PWM6 channel A
|
||||
GPIO29 Pin = 29 // peripherals: PWM6 channel B
|
||||
|
||||
// Analog pins
|
||||
ADC0 Pin = GPIO26
|
||||
ADC1 Pin = GPIO27
|
||||
ADC2 Pin = GPIO28
|
||||
ADC3 Pin = GPIO29
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build rp2040
|
||||
//go:build rp2040 || rp2350
|
||||
|
||||
package machine
|
||||
|
||||
@@ -15,7 +15,7 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
maxPWMPins = 29
|
||||
maxPWMPins = _NUMBANK0_GPIOS - 1
|
||||
)
|
||||
|
||||
// pwmGroup is one PWM peripheral, which consists of a counter and two output
|
||||
@@ -146,12 +146,13 @@ func (p *pwmGroup) Counter() uint32 {
|
||||
|
||||
// Period returns the used PWM period in nanoseconds.
|
||||
func (p *pwmGroup) Period() uint64 {
|
||||
periodPerCycle := cpuPeriod()
|
||||
freq := CPUFrequency()
|
||||
top := p.getWrap()
|
||||
phc := p.getPhaseCorrect()
|
||||
Int, frac := p.getClockDiv()
|
||||
// Line below can overflow if operations done without care.
|
||||
return (16*uint64(Int) + uint64(frac)) * uint64((top+1)*(phc+1)*periodPerCycle) / 16 // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
|
||||
// Lines below can overflow if operations done without care.
|
||||
term2 := 16 * uint64((top+1)*(phc+1)) * 1e9 / uint64(freq) // 1e9/freq == CPU period in nanoseconds.
|
||||
return (uint64(Int) + uint64(frac)) * term2 / 16 // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
|
||||
}
|
||||
|
||||
// SetInverting sets whether to invert the output of this channel.
|
||||
@@ -279,9 +280,9 @@ func (pwm *pwmGroup) setPeriod(period uint64) error {
|
||||
// DIV_INT + DIV_FRAC/16 = cycles / ( (TOP+1) * (CSRPHCorrect+1) ) // DIV_FRAC/16 is always 0 in this equation
|
||||
// where cycles must be converted to time:
|
||||
// target_period = cycles * period_per_cycle ==> cycles = target_period/period_per_cycle
|
||||
periodPerCycle := uint64(cpuPeriod())
|
||||
freq := uint64(CPUFrequency())
|
||||
phc := uint64(pwm.getPhaseCorrect())
|
||||
rhs := 16 * period / ((1 + phc) * periodPerCycle * (1 + topStart)) // right-hand-side of equation, scaled so frac is not divided
|
||||
rhs := 16e9 * period / ((1 + phc) * freq * (1 + topStart)) // right-hand-side of equation, scaled so frac is not divided
|
||||
whole := rhs / 16
|
||||
frac := rhs % 16
|
||||
switch {
|
||||
@@ -296,7 +297,7 @@ func (pwm *pwmGroup) setPeriod(period uint64) error {
|
||||
|
||||
// Step 2 is acquiring a better top value. Clearing the equation:
|
||||
// TOP = cycles / ( (DIVINT+DIVFRAC/16) * (CSRPHCorrect+1) ) - 1
|
||||
top := 16*period/((16*whole+frac)*periodPerCycle*(1+phc)) - 1
|
||||
top := 16e9*period/((16*whole+frac)*freq*(1+phc)) - 1
|
||||
if top > maxTop {
|
||||
top = maxTop
|
||||
}
|
||||
@@ -400,6 +401,9 @@ func (pwm *pwmGroup) getClockDiv() (Int, frac uint8) {
|
||||
// pwmGPIOToSlice Determine the PWM channel that is attached to the specified GPIO.
|
||||
// gpio must be less than 30. Returns the PWM slice number that controls the specified GPIO.
|
||||
func pwmGPIOToSlice(gpio Pin) (slicenum uint8) {
|
||||
if is48Pin && gpio >= 32 {
|
||||
return uint8(8 + ((gpio-32)/2)%4)
|
||||
}
|
||||
return (uint8(gpio) >> 1) & 7
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"inherits": ["rp2350"],
|
||||
"build-tags": ["rp2350b"],
|
||||
"serial-port": ["2e8a:000f"]
|
||||
}
|
||||
Reference in New Issue
Block a user