machine/rp2350: extending support to include the rp2350b

This commit is contained in:
soypat
2025-02-09 21:12:22 -03:00
committed by Ron Evans
parent e7118e5bda
commit 0ec1cb1e19
10 changed files with 133 additions and 69 deletions
+2
View File
@@ -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
+10
View File
@@ -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
+18 -2
View File
@@ -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()
+48
View File
@@ -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)
)
+6 -38
View File
@@ -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
}
-6
View File
@@ -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
+31 -8
View File
@@ -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 -7
View File
@@ -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
}
+5
View File
@@ -0,0 +1,5 @@
{
"inherits": ["rp2350"],
"build-tags": ["rp2350b"],
"serial-port": ["2e8a:000f"]
}