Skip to content

Commit 0ec1cb1

Browse files
soypatdeadprogram
authored andcommitted
machine/rp2350: extending support to include the rp2350b
1 parent e7118e5 commit 0ec1cb1

10 files changed

+133
-69
lines changed

src/machine/machine_rp2.go

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ const (
1616
// Note: On RP2350, most spinlocks are unusable due to Errata 2
1717
_NUMSPINLOCKS = 32
1818
_PICO_SPINLOCK_ID_IRQ = 9
19+
// is48Pin notes whether the chip is RP2040 with 32 pins or RP2350 with 48 pins.
20+
is48Pin = _NUMBANK0_GPIOS == 48
1921
)
2022

2123
// UART on the RP2040

src/machine/machine_rp2_2040.go

+10
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ const (
4545
PinPIO1
4646
)
4747

48+
// Analog pins on RP2040.
49+
const (
50+
ADC0 Pin = GPIO26
51+
ADC1 Pin = GPIO27
52+
ADC2 Pin = GPIO28
53+
ADC3 Pin = GPIO29
54+
55+
thermADC = 30
56+
)
57+
4858
const (
4959
clkGPOUT0 clockIndex = iota // GPIO Muxing 0
5060
clkGPOUT1 // GPIO Muxing 1

src/machine/machine_rp2_2350.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ const (
3333
rp.PADS_BANK0_GPIO0_ISO_Msk
3434
)
3535

36+
// Analog pins on RP2350.
37+
const (
38+
ADC0 Pin = GPIO26
39+
ADC1 Pin = GPIO27
40+
ADC2 Pin = GPIO28
41+
ADC3 Pin = GPIO29
42+
43+
thermADC = 30
44+
)
45+
3646
const (
3747
PinOutput PinMode = iota
3848
PinInput
@@ -126,11 +136,17 @@ func (p Pin) Configure(config PinConfig) {
126136
return
127137
}
128138
p.init()
129-
mask := uint32(1) << p
139+
130140
switch config.Mode {
131141
case PinOutput:
132142
p.setFunc(fnSIO)
133-
rp.SIO.GPIO_OE_SET.Set(mask)
143+
if is48Pin && p >= 32 {
144+
mask := uint32(1) << (p % 32)
145+
rp.SIO.GPIO_HI_OE_SET.Set(mask)
146+
} else {
147+
mask := uint32(1) << p
148+
rp.SIO.GPIO_OE_SET.Set(mask)
149+
}
134150
case PinInput:
135151
p.setFunc(fnSIO)
136152
p.pulloff()

src/machine/machine_rp2_2350b.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//go:build rp2350b
2+
3+
package machine
4+
5+
// RP2350B has additional pins.
6+
7+
const (
8+
GPIO30 Pin = 30 // peripherals: PWM7 channel A
9+
GPIO31 Pin = 31 // peripherals: PWM7 channel B
10+
GPIO32 Pin = 32 // peripherals: PWM8 channel A
11+
GPIO33 Pin = 33 // peripherals: PWM8 channel B
12+
GPIO34 Pin = 34 // peripherals: PWM9 channel A
13+
GPIO35 Pin = 35 // peripherals: PWM9 channel B
14+
GPIO36 Pin = 36 // peripherals: PWM10 channel A
15+
GPIO37 Pin = 37 // peripherals: PWM10 channel B
16+
GPIO38 Pin = 38 // peripherals: PWM11 channel A
17+
GPIO39 Pin = 39 // peripherals: PWM11 channel B
18+
GPIO40 Pin = 40 // peripherals: PWM8 channel A
19+
GPIO41 Pin = 41 // peripherals: PWM8 channel B
20+
GPIO42 Pin = 42 // peripherals: PWM9 channel A
21+
GPIO43 Pin = 43 // peripherals: PWM9 channel B
22+
GPIO44 Pin = 44 // peripherals: PWM10 channel A
23+
GPIO45 Pin = 45 // peripherals: PWM10 channel B
24+
GPIO46 Pin = 46 // peripherals: PWM11 channel A
25+
GPIO47 Pin = 47 // peripherals: PWM11 channel B
26+
)
27+
28+
// Analog pins on 2350b.
29+
const (
30+
ADC0 Pin = GPIO40
31+
ADC1 Pin = GPIO41
32+
ADC2 Pin = GPIO42
33+
ADC3 Pin = GPIO43
34+
ADC4 Pin = GPIO44
35+
ADC5 Pin = GPIO45
36+
ADC6 Pin = GPIO46
37+
ADC7 Pin = GPIO47
38+
39+
thermADC = 48
40+
)
41+
42+
// Additional PWMs on the RP2350B.
43+
var (
44+
PWM8 = getPWMGroup(8)
45+
PWM9 = getPWMGroup(9)
46+
PWM10 = getPWMGroup(10)
47+
PWM11 = getPWMGroup(11)
48+
)

src/machine/machine_rp2_adc.go

+6-38
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,6 @@ import (
1111
// ADCChannel is the ADC peripheral mux channel. 0-4.
1212
type ADCChannel uint8
1313

14-
// ADC channels. Only ADC_TEMP_SENSOR is public. The other channels are accessed via Machine.ADC objects
15-
const (
16-
adc0_CH ADCChannel = iota
17-
adc1_CH
18-
adc2_CH
19-
adc3_CH // Note: GPIO29 not broken out on pico board
20-
adcTempSensor // Internal temperature sensor channel
21-
)
22-
2314
// Used to serialise ADC sampling
2415
var adcLock sync.Mutex
2516

@@ -58,20 +49,10 @@ func (a ADC) Get() uint16 {
5849

5950
// GetADCChannel returns the channel associated with the ADC pin.
6051
func (a ADC) GetADCChannel() (c ADCChannel, err error) {
61-
err = nil
62-
switch a.Pin {
63-
case ADC0:
64-
c = adc0_CH
65-
case ADC1:
66-
c = adc1_CH
67-
case ADC2:
68-
c = adc2_CH
69-
case ADC3:
70-
c = adc3_CH
71-
default:
72-
err = errors.New("no ADC channel for pin value")
52+
if a.Pin < ADC0 {
53+
return 0, errors.New("no ADC channel for pin value")
7354
}
74-
return c, err
55+
return ADCChannel(a.Pin - ADC0), nil
7556
}
7657

7758
// Configure sets the channel's associated pin to analog input mode.
@@ -113,12 +94,12 @@ func ReadTemperature() (millicelsius int32) {
11394
if rp.ADC.CS.Get()&rp.ADC_CS_EN == 0 {
11495
InitADC()
11596
}
116-
97+
thermChan, _ := ADC{Pin: thermADC}.GetADCChannel()
11798
// Enable temperature sensor bias source
11899
rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN)
119100

120101
// T = 27 - (ADC_voltage - 0.706)/0.001721
121-
return (27000<<16 - (int32(adcTempSensor.getVoltage())-706<<16)*581) >> 16
102+
return (27000<<16 - (int32(thermChan.getVoltage())-706<<16)*581) >> 16
122103
}
123104

124105
// waitForReady spins waiting for the ADC peripheral to become ready.
@@ -129,18 +110,5 @@ func waitForReady() {
129110

130111
// The Pin method returns the GPIO Pin associated with the ADC mux channel, if it has one.
131112
func (c ADCChannel) Pin() (p Pin, err error) {
132-
err = nil
133-
switch c {
134-
case adc0_CH:
135-
p = ADC0
136-
case adc1_CH:
137-
p = ADC1
138-
case adc2_CH:
139-
p = ADC2
140-
case adc3_CH:
141-
p = ADC3
142-
default:
143-
err = errors.New("no associated pin for channel")
144-
}
145-
return p, err
113+
return Pin(c) + ADC0, nil
146114
}

src/machine/machine_rp2_clocks.go

-6
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@ func CPUFrequency() uint32 {
1313
return 125 * MHz
1414
}
1515

16-
// Returns the period of a clock cycle for the raspberry pi pico in nanoseconds.
17-
// Used in PWM API.
18-
func cpuPeriod() uint32 {
19-
return 1e9 / CPUFrequency()
20-
}
21-
2216
// clockIndex identifies a hardware clock
2317
type clockIndex uint8
2418

src/machine/machine_rp2_gpio.go

+31-8
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,13 @@ func (p Pin) PortMaskSet() (*uint32, uint32) {
6363

6464
// set drives the pin high
6565
func (p Pin) set() {
66-
mask := uint32(1) << p
67-
rp.SIO.GPIO_OUT_SET.Set(mask)
66+
if is48Pin && p >= 32 {
67+
mask := uint32(1) << (p % 32)
68+
rp.SIO.GPIO_HI_OUT_SET.Set(mask)
69+
} else {
70+
mask := uint32(1) << p
71+
rp.SIO.GPIO_OUT_SET.Set(mask)
72+
}
6873
}
6974

7075
func (p Pin) PortMaskClear() (*uint32, uint32) {
@@ -73,18 +78,31 @@ func (p Pin) PortMaskClear() (*uint32, uint32) {
7378

7479
// clr drives the pin low
7580
func (p Pin) clr() {
76-
mask := uint32(1) << p
77-
rp.SIO.GPIO_OUT_CLR.Set(mask)
81+
if is48Pin && p >= 32 {
82+
mask := uint32(1) << (p % 32)
83+
rp.SIO.GPIO_HI_OUT_CLR.Set(mask)
84+
} else {
85+
mask := uint32(1) << p
86+
rp.SIO.GPIO_OUT_CLR.Set(mask)
87+
}
7888
}
7989

8090
// xor toggles the pin
8191
func (p Pin) xor() {
82-
mask := uint32(1) << p
83-
rp.SIO.GPIO_OUT_XOR.Set(mask)
92+
if is48Pin && p >= 32 {
93+
mask := uint32(1) << (p % 32)
94+
rp.SIO.GPIO_HI_OUT_XOR.Set(mask)
95+
} else {
96+
mask := uint32(1) << p
97+
rp.SIO.GPIO_OUT_XOR.Set(mask)
98+
}
8499
}
85100

86101
// get returns the pin value
87102
func (p Pin) get() bool {
103+
if is48Pin && p >= 32 {
104+
return rp.SIO.GPIO_HI_IN.HasBits(1 << (p % 32))
105+
}
88106
return rp.SIO.GPIO_IN.HasBits(1 << p)
89107
}
90108

@@ -134,8 +152,13 @@ func (p Pin) setFunc(fn pinFunc) {
134152

135153
// init initializes the gpio pin
136154
func (p Pin) init() {
137-
mask := uint32(1) << p
138-
rp.SIO.GPIO_OE_CLR.Set(mask)
155+
if is48Pin && p >= 32 {
156+
mask := uint32(1) << (p % 32)
157+
rp.SIO.GPIO_HI_OE_CLR.Set(mask)
158+
} else {
159+
mask := uint32(1) << p
160+
rp.SIO.GPIO_OE_CLR.Set(mask)
161+
}
139162
p.clr()
140163
}
141164

src/machine/machine_rp2_pins.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//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
1+
//go:build rp2040 || rp2350 || gopher_badge
22

33
package machine
44

@@ -34,10 +34,4 @@ const (
3434
GPIO27 Pin = 27 // peripherals: PWM5 channel B
3535
GPIO28 Pin = 28 // peripherals: PWM6 channel A
3636
GPIO29 Pin = 29 // peripherals: PWM6 channel B
37-
38-
// Analog pins
39-
ADC0 Pin = GPIO26
40-
ADC1 Pin = GPIO27
41-
ADC2 Pin = GPIO28
42-
ADC3 Pin = GPIO29
4337
)

src/machine/machine_rp2040_pwm.go renamed to src/machine/machine_rp2_pwm.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build rp2040
1+
//go:build rp2040 || rp2350
22

33
package machine
44

@@ -15,7 +15,7 @@ var (
1515
)
1616

1717
const (
18-
maxPWMPins = 29
18+
maxPWMPins = _NUMBANK0_GPIOS - 1
1919
)
2020

2121
// pwmGroup is one PWM peripheral, which consists of a counter and two output
@@ -146,12 +146,13 @@ func (p *pwmGroup) Counter() uint32 {
146146

147147
// Period returns the used PWM period in nanoseconds.
148148
func (p *pwmGroup) Period() uint64 {
149-
periodPerCycle := cpuPeriod()
149+
freq := CPUFrequency()
150150
top := p.getWrap()
151151
phc := p.getPhaseCorrect()
152152
Int, frac := p.getClockDiv()
153-
// Line below can overflow if operations done without care.
154-
return (16*uint64(Int) + uint64(frac)) * uint64((top+1)*(phc+1)*periodPerCycle) / 16 // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
153+
// Lines below can overflow if operations done without care.
154+
term2 := 16 * uint64((top+1)*(phc+1)) * 1e9 / uint64(freq) // 1e9/freq == CPU period in nanoseconds.
155+
return (uint64(Int) + uint64(frac)) * term2 / 16 // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
155156
}
156157

157158
// SetInverting sets whether to invert the output of this channel.
@@ -279,9 +280,9 @@ func (pwm *pwmGroup) setPeriod(period uint64) error {
279280
// DIV_INT + DIV_FRAC/16 = cycles / ( (TOP+1) * (CSRPHCorrect+1) ) // DIV_FRAC/16 is always 0 in this equation
280281
// where cycles must be converted to time:
281282
// target_period = cycles * period_per_cycle ==> cycles = target_period/period_per_cycle
282-
periodPerCycle := uint64(cpuPeriod())
283+
freq := uint64(CPUFrequency())
283284
phc := uint64(pwm.getPhaseCorrect())
284-
rhs := 16 * period / ((1 + phc) * periodPerCycle * (1 + topStart)) // right-hand-side of equation, scaled so frac is not divided
285+
rhs := 16e9 * period / ((1 + phc) * freq * (1 + topStart)) // right-hand-side of equation, scaled so frac is not divided
285286
whole := rhs / 16
286287
frac := rhs % 16
287288
switch {
@@ -296,7 +297,7 @@ func (pwm *pwmGroup) setPeriod(period uint64) error {
296297

297298
// Step 2 is acquiring a better top value. Clearing the equation:
298299
// TOP = cycles / ( (DIVINT+DIVFRAC/16) * (CSRPHCorrect+1) ) - 1
299-
top := 16*period/((16*whole+frac)*periodPerCycle*(1+phc)) - 1
300+
top := 16e9*period/((16*whole+frac)*freq*(1+phc)) - 1
300301
if top > maxTop {
301302
top = maxTop
302303
}
@@ -400,6 +401,9 @@ func (pwm *pwmGroup) getClockDiv() (Int, frac uint8) {
400401
// pwmGPIOToSlice Determine the PWM channel that is attached to the specified GPIO.
401402
// gpio must be less than 30. Returns the PWM slice number that controls the specified GPIO.
402403
func pwmGPIOToSlice(gpio Pin) (slicenum uint8) {
404+
if is48Pin && gpio >= 32 {
405+
return uint8(8 + ((gpio-32)/2)%4)
406+
}
403407
return (uint8(gpio) >> 1) & 7
404408
}
405409

targets/rp2350b.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"inherits": ["rp2350"],
3+
"build-tags": ["rp2350b"],
4+
"serial-port": ["2e8a:000f"]
5+
}

0 commit comments

Comments
 (0)