diff --git a/src/machine/machine_rp2.go b/src/machine/machine_rp2.go index 6c09fedfe..9afefa538 100644 --- a/src/machine/machine_rp2.go +++ b/src/machine/machine_rp2.go @@ -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 diff --git a/src/machine/machine_rp2_2040.go b/src/machine/machine_rp2_2040.go index 484d8e923..0691b8d77 100644 --- a/src/machine/machine_rp2_2040.go +++ b/src/machine/machine_rp2_2040.go @@ -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 diff --git a/src/machine/machine_rp2_2350.go b/src/machine/machine_rp2_2350.go index 4e12bebe3..32b739c62 100644 --- a/src/machine/machine_rp2_2350.go +++ b/src/machine/machine_rp2_2350.go @@ -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() diff --git a/src/machine/machine_rp2_2350b.go b/src/machine/machine_rp2_2350b.go new file mode 100644 index 000000000..c1e4a3a66 --- /dev/null +++ b/src/machine/machine_rp2_2350b.go @@ -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) +) diff --git a/src/machine/machine_rp2_adc.go b/src/machine/machine_rp2_adc.go index 13504d719..fc9a8268e 100644 --- a/src/machine/machine_rp2_adc.go +++ b/src/machine/machine_rp2_adc.go @@ -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 } diff --git a/src/machine/machine_rp2_clocks.go b/src/machine/machine_rp2_clocks.go index cc152a7f8..ba5bb67af 100644 --- a/src/machine/machine_rp2_clocks.go +++ b/src/machine/machine_rp2_clocks.go @@ -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 diff --git a/src/machine/machine_rp2_gpio.go b/src/machine/machine_rp2_gpio.go index d49d12f2b..6854f8aad 100644 --- a/src/machine/machine_rp2_gpio.go +++ b/src/machine/machine_rp2_gpio.go @@ -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() } diff --git a/src/machine/machine_rp2_pins.go b/src/machine/machine_rp2_pins.go index 93f2d50a0..43b31f938 100644 --- a/src/machine/machine_rp2_pins.go +++ b/src/machine/machine_rp2_pins.go @@ -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 ) diff --git a/src/machine/machine_rp2040_pwm.go b/src/machine/machine_rp2_pwm.go similarity index 95% rename from src/machine/machine_rp2040_pwm.go rename to src/machine/machine_rp2_pwm.go index f72d6dd03..1a511daf1 100644 --- a/src/machine/machine_rp2040_pwm.go +++ b/src/machine/machine_rp2_pwm.go @@ -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 } diff --git a/targets/rp2350b.json b/targets/rp2350b.json new file mode 100644 index 000000000..5db4d4849 --- /dev/null +++ b/targets/rp2350b.json @@ -0,0 +1,5 @@ +{ + "inherits": ["rp2350"], + "build-tags": ["rp2350b"], + "serial-port": ["2e8a:000f"] +} \ No newline at end of file