Skip to content

Commit 76811d3

Browse files
Add RP2350B generic/Pimoroni PGA2350 support (#2433)
* Add support for the extra 16 GPIO pins in the menus and core. * Clean up Generic RP2350 PSRAM ("none" is valid) and flash (other than 16MB) options. * Add extra GPIO<->peripheral connections * Add Pimoroni PGA2350 RP2350B-based board * Pins 32-47 can be used for PIOPrograms * Avoid hang when PSRAM fails to initialize * Move libpico to an RP2350B board for SDK (otherwise the SDK drops all GPIOHI support)
1 parent 20c69bd commit 76811d3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1032
-254
lines changed

boards.txt

Lines changed: 473 additions & 135 deletions
Large diffs are not rendered by default.

cores/rp2040/Arduino.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ extern const String emptyString;
133133
// Template which will evaluate at *compile time* to a single 32b number
134134
// with the specified bits set.
135135
template <size_t N>
136-
constexpr uint32_t __bitset(const int (&a)[N], size_t i = 0U) {
137-
return i < N ? (1L << a[i]) | __bitset(a, i + 1) : 0;
136+
constexpr uint64_t __bitset(const int (&a)[N], size_t i = 0U) {
137+
return i < N ? (1LL << a[i]) | __bitset(a, i + 1) : 0;
138138
}
139139
#endif
140140

@@ -149,3 +149,12 @@ constexpr uint32_t __bitset(const int (&a)[N], size_t i = 0U) {
149149

150150
// PSRAM decorator
151151
#define PSRAM __attribute__((section("\".psram\"")))
152+
153+
// General GPIO/ADC layout info
154+
#ifdef PICO_RP2350B
155+
#define __GPIOCNT 48
156+
#define __FIRSTANALOGGPIO 40
157+
#else
158+
#define __GPIOCNT 30
159+
#define __FIRSTANALOGGPIO 26
160+
#endif

cores/rp2040/PIOProgram.cpp

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <Arduino.h>
2222
#include "PIOProgram.h"
2323
#include <map>
24+
#include <hardware/claim.h>
2425

2526
#if defined(PICO_RP2350)
2627
#define PIOS pio0, pio1, pio2
@@ -31,6 +32,8 @@
3132
#endif
3233

3334
static std::map<const pio_program_t *, int> __pioMap[PIOCNT];
35+
static bool __pioAllocated[PIOCNT];
36+
static bool __pioHighGPIO[PIOCNT];
3437
auto_init_mutex(_pioMutex);
3538

3639
PIOProgram::PIOProgram(const pio_program_t *pgm) {
@@ -47,16 +50,30 @@ PIOProgram::~PIOProgram() {
4750
}
4851

4952
// Possibly load into a PIO and allocate a SM
50-
bool PIOProgram::prepare(PIO *pio, int *sm, int *offset) {
53+
bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
5154
CoreMutex m(&_pioMutex);
5255
PIO pi[PIOCNT] = { PIOS };
5356

57+
#if 0
58+
uint usm;
59+
uint uoff;
60+
auto ret = pio_claim_free_sm_and_add_program_for_gpio_range(_pgm, pio, &usm, &uoff, start, cnt, true);
61+
*sm = usm;
62+
*offset = uoff;
63+
DEBUGV("clain %d\n", ret);
64+
return ret;
65+
#endif
66+
67+
bool needsHigh = (start + cnt) >= 32;
68+
DEBUGV("PIOProgram %p: Searching for high=%d, pins %d-%d\n", _pgm, needsHigh ? 1 : 0, start, start + cnt - 1);
69+
5470
// If it's already loaded into PIO IRAM, try and allocate in that specific PIO
5571
for (int o = 0; o < PIOCNT; o++) {
5672
auto p = __pioMap[o].find(_pgm);
57-
if (p != __pioMap[o].end()) {
73+
if ((p != __pioMap[o].end()) && (__pioHighGPIO[o] == needsHigh)) {
5874
int idx = pio_claim_unused_sm(pi[o], false);
5975
if (idx >= 0) {
76+
DEBUGV("PIOProgram %p: Reusing IMEM ON PIO %p(high=%d) for pins %d-%d\n", _pgm, pi[o], __pioHighGPIO[o] ? 1 : 0, start, start + cnt - 1);
6077
_pio = pi[o];
6178
_sm = idx;
6279
*pio = pi[o];
@@ -69,19 +86,52 @@ bool PIOProgram::prepare(PIO *pio, int *sm, int *offset) {
6986

7087
// Not in any PIO IRAM, so try and add
7188
for (int o = 0; o < PIOCNT; o++) {
72-
if (pio_can_add_program(pi[o], _pgm)) {
73-
int idx = pio_claim_unused_sm(pi[o], false);
74-
if (idx >= 0) {
75-
int off = pio_add_program(pi[o], _pgm);
76-
__pioMap[o].insert({_pgm, off});
77-
_pio = pi[o];
78-
_sm = idx;
79-
*pio = pi[o];
80-
*sm = idx;
81-
*offset = off;
82-
return true;
89+
if (__pioAllocated[o] && (__pioHighGPIO[o] == needsHigh)) {
90+
DEBUGV("PIOProgram: Checking PIO %p\n", pi[o]);
91+
if (pio_can_add_program(pi[o], _pgm)) {
92+
int idx = pio_claim_unused_sm(pi[o], false);
93+
if (idx >= 0) {
94+
DEBUGV("PIOProgram %p: Adding IMEM ON PIO %p(high=%d) for pins %d-%d\n", _pgm, pi[o], __pioHighGPIO[o] ? 1 : 0, start, start + cnt - 1);
95+
int off = pio_add_program(pi[o], _pgm);
96+
__pioMap[o].insert({_pgm, off});
97+
_pio = pi[o];
98+
_sm = idx;
99+
*pio = pi[o];
100+
*sm = idx;
101+
*offset = off;
102+
return true;
103+
} else {
104+
DEBUGV("PIOProgram: can't claim unused SM\n");
105+
}
106+
} else {
107+
DEBUGV("PIOProgram: can't add program\n");
83108
}
109+
} else {
110+
DEBUGV("PIOProgram: Skipping PIO %p, wrong allocated/needhi\n", pi[o]);
111+
}
112+
}
113+
114+
// No existing PIOs can meet, is there an unallocated one we can allocate?
115+
PIO p;
116+
uint idx;
117+
uint off;
118+
auto rc = pio_claim_free_sm_and_add_program_for_gpio_range(_pgm, &p, &idx, &off, start, cnt, true);
119+
if (rc) {
120+
int o = 0;
121+
while (p != pi[o]) {
122+
o++;
84123
}
124+
assert(!__pioAllocated[o]);
125+
__pioAllocated[o] = true;
126+
__pioHighGPIO[o] = needsHigh;
127+
DEBUGV("PIOProgram %p: Allocating new PIO %p(high=%d) for pins %d-%d\n", _pgm, pi[o], __pioHighGPIO[o] ? 1 : 0, start, start + cnt - 1);
128+
__pioMap[o].insert({_pgm, off});
129+
_pio = pi[o];
130+
_sm = idx;
131+
*pio = pi[o];
132+
*sm = idx;
133+
*offset = off;
134+
return true;
85135
}
86136

87137
// Nope, no room either for SMs or INSNs

cores/rp2040/PIOProgram.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class PIOProgram {
2828
PIOProgram(const pio_program_t *pgm);
2929
~PIOProgram();
3030
// Possibly load into a PIO and allocate a SM
31-
bool prepare(PIO *pio, int *sm, int *offset);
31+
bool prepare(PIO *pio, int *sm, int *offset, int gpio_start = 0, int gpio_cnt = 1);
3232

3333
private:
3434
const pio_program_t *_pgm;

cores/rp2040/SerialPIO.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ static std::map<int, PIOProgram*> _rxMap;
3333
// Duplicate a program and replace the first insn with a "set x, repl"
3434
static pio_program_t *pio_make_uart_prog(int repl, const pio_program_t *pg) {
3535
pio_program_t *p = new pio_program_t;
36+
memcpy(p, pg, sizeof(*p));
3637
p->length = pg->length;
3738
p->origin = pg->origin;
3839
uint16_t *insn = (uint16_t *)malloc(p->length * 2);
@@ -193,7 +194,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
193194
_txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/;
194195
_txPgm = _getTxProgram(_txBits);
195196
int off;
196-
if (!_txPgm->prepare(&_txPIO, &_txSM, &off)) {
197+
if (!_txPgm->prepare(&_txPIO, &_txSM, &off, _tx, 1)) {
197198
DEBUGCORE("ERROR: Unable to allocate PIO TX UART, out of PIO resources\n");
198199
// ERROR, no free slots
199200
return;
@@ -221,7 +222,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
221222
_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
222223
_rxPgm = _getRxProgram(_rxBits);
223224
int off;
224-
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off)) {
225+
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off, _rx, 1)) {
225226
DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n");
226227
return;
227228
}

cores/rp2040/SerialUART.cpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,16 @@ extern void serialEvent1() __attribute__((weak));
3232
extern void serialEvent2() __attribute__((weak));
3333

3434
bool SerialUART::setRX(pin_size_t pin) {
35-
constexpr uint32_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
35+
#ifdef RP2350B
36+
constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29, 33, 45}) /* UART0 */,
37+
__bitset({5, 9, 21, 25, 37, 41}) /* UART1 */
38+
};
39+
#else
40+
constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
3641
__bitset({5, 9, 21, 25}) /* UART1 */
3742
};
38-
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
43+
#endif
44+
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
3945
_rx = pin;
4046
return true;
4147
}
@@ -53,10 +59,16 @@ bool SerialUART::setRX(pin_size_t pin) {
5359
}
5460

5561
bool SerialUART::setTX(pin_size_t pin) {
56-
constexpr uint32_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
62+
#ifdef RP2350B
63+
constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28, 32, 44}) /* UART0 */,
64+
__bitset({4, 8, 20, 24, 36, 40}) /* UART1 */
65+
};
66+
#else
67+
constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
5768
__bitset({4, 8, 20, 24}) /* UART1 */
5869
};
59-
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
70+
#endif
71+
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
6072
_tx = pin;
6173
return true;
6274
}
@@ -74,10 +86,16 @@ bool SerialUART::setTX(pin_size_t pin) {
7486
}
7587

7688
bool SerialUART::setRTS(pin_size_t pin) {
77-
constexpr uint32_t valid[2] = { __bitset({3, 15, 19}) /* UART0 */,
89+
#ifdef RP2350B
90+
constexpr uint64_t valid[2] = { __bitset({3, 15, 19, 31, 35, 47}) /* UART0 */,
91+
__bitset({7, 11, 23, 27, 39, 43}) /* UART1 */
92+
};
93+
#else
94+
constexpr uint64_t valid[2] = { __bitset({3, 15, 19}) /* UART0 */,
7895
__bitset({7, 11, 23, 27}) /* UART1 */
7996
};
80-
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1 << pin) & valid[uart_get_index(_uart)]))) {
97+
#endif
98+
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
8199
_rts = pin;
82100
return true;
83101
}
@@ -95,10 +113,16 @@ bool SerialUART::setRTS(pin_size_t pin) {
95113
}
96114

97115
bool SerialUART::setCTS(pin_size_t pin) {
98-
constexpr uint32_t valid[2] = { __bitset({2, 14, 18}) /* UART0 */,
116+
#ifdef RP2350B
117+
constexpr uint64_t valid[2] = { __bitset({2, 14, 18, 30, 34, 46}) /* UART0 */,
118+
__bitset({6, 10, 22, 26, 38, 42}) /* UART1 */
119+
};
120+
#else
121+
constexpr uint64_t valid[2] = { __bitset({2, 14, 18}) /* UART0 */,
99122
__bitset({6, 10, 22, 26}) /* UART1 */
100123
};
101-
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1 << pin) & valid[uart_get_index(_uart)]))) {
124+
#endif
125+
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
102126
_cts = pin;
103127
return true;
104128
}

cores/rp2040/Tone.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ int64_t _stopTonePIO(alarm_id_t id, void *user_data) {
5656
}
5757

5858
void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
59-
if (pin > 29) {
59+
if (pin >= __GPIOCNT) {
6060
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
6161
return;
6262
}
@@ -81,7 +81,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
8181
newTone = new Tone();
8282
newTone->pin = pin;
8383
pinMode(pin, OUTPUT);
84-
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &newTone->off)) {
84+
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &newTone->off, pin, 1)) {
8585
DEBUGCORE("ERROR: tone unable to start, out of PIO resources\n");
8686
// ERROR, no free slots
8787
delete newTone;
@@ -118,7 +118,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
118118
void noTone(uint8_t pin) {
119119
CoreMutex m(&_toneMutex);
120120

121-
if ((pin > 29) || !m) {
121+
if ((pin > __GPIOCNT) || !m) {
122122
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
123123
return;
124124
}

cores/rp2040/pio_uart.pio

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ wait_bit:
4444
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
4545
// Tell PIO to initially drive output-high on the selected pin, then map PIO
4646
// onto that pin with the IO muxes.
47-
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
48-
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
47+
pio_sm_set_set_pins(pio, sm, pin_tx, 1);
48+
pio_sm_set_consecutive_pindirs(pio, sm, pin_tx, 1, true);
4949
pio_gpio_init(pio, pin_tx);
5050

5151
pio_sm_config c = pio_tx_program_get_default_config(offset);

cores/rp2040/pio_uart.pio.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ static inline pio_sm_config pio_tx_program_get_default_config(uint offset) {
4848
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
4949
// Tell PIO to initially drive output-high on the selected pin, then map PIO
5050
// onto that pin with the IO muxes.
51-
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
52-
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
51+
pio_sm_set_set_pins(pio, sm, pin_tx, 1);
52+
pio_sm_set_consecutive_pindirs(pio, sm, pin_tx, 1, true);
5353
pio_gpio_init(pio, pin_tx);
5454
pio_sm_config c = pio_tx_program_get_default_config(offset);
5555
// OUT shifts to right, no autopull

cores/rp2040/psram.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ static bool __psram_heap_init() {
332332
return true;
333333
}
334334

335+
if (!__psram_heap_size) {
336+
return false;
337+
}
335338
_mem_heap = NULL;
336339
_mem_psram_pool = NULL;
337340
_mem_heap = tlsf_create_with_pool((void *)&__psram_heap_start__, __psram_heap_size, 16 * 1024 * 1024);

0 commit comments

Comments
 (0)