Skip to content

Commit 1408e89

Browse files
committed
Implement auto-discovery of required hardware resources.
PIO-USB uses DMA channel, PIO instructions and State Machines to run its logic. These hardware resources are limited and usually can be shared between different modules. The current approach is the user to configure these resources manually and to resolve any possible conflicts. This approach may not work in all cases, especially in more complex systems. This patch implements logic for auto-discovery and allocation of required hardware resources. The Pico SDK has dedicated APIs for that. The existing approach for manually configuration still works, the auto-discovery logic is on top of it. How it can be triggered: - Instead of specifying a resource in pio_usb_configuration_t, set "-1". - Auto-discovery is supported of all resources: pio_tx_num, pio_rx_num, tx_ch, sm_tx, sm_rx and sm_eop. - Mixed mode is also supported - some of the resources can be set manually, others can be auto-discovered. Signed-off-by: Tzvetomir Stoyanov <[email protected]>
1 parent 0ca3657 commit 1408e89

File tree

2 files changed

+174
-41
lines changed

2 files changed

+174
-41
lines changed

src/pio_usb.c

Lines changed: 166 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -226,39 +226,107 @@ int __no_inline_not_in_flash_func(pio_usb_bus_receive_packet_and_handshake)(
226226
return -1;
227227
}
228228

229-
static __always_inline void add_pio_host_rx_program(PIO pio,
229+
static __always_inline int try_add_pio_host_rx_program(PIO pio,
230230
const pio_program_t *program,
231231
const pio_program_t *debug_program,
232-
uint *offset, int debug_pin) {
233-
if (debug_pin < 0) {
234-
*offset = pio_add_program(pio, program);
235-
} else {
236-
*offset = pio_add_program(pio, debug_program);
232+
int *offset, int debug_pin) {
233+
const pio_program_t *prog;
234+
235+
if (debug_pin < 0)
236+
prog = program;
237+
else
238+
prog = debug_program;
239+
240+
if (pio_can_add_program(pio, prog)) {
241+
*offset = pio_add_program(pio, prog);
242+
return prog->length;
237243
}
244+
245+
return -1;
238246
}
239247

240-
static void __no_inline_not_in_flash_func(initialize_host_programs)(
241-
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port) {
248+
static __always_inline void remove_pio_host_rx_program(PIO pio,
249+
const pio_program_t *program,
250+
const pio_program_t *debug_program,
251+
int offset, int debug_pin) {
252+
if (debug_pin < 0) {
253+
pio_remove_program(pio, program, offset);
254+
} else {
255+
pio_remove_program(pio, debug_program, offset);
256+
}
257+
}
258+
259+
static bool __no_inline_not_in_flash_func(try_initialize_host_programs)(
260+
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port,
261+
uint *tx_inst_count, uint *rx_inst_count) {
262+
int offset_tx = -1, offset_rx = -1, offset_eop = -1;
263+
int sm_tx = -1, sm_rx = -1, sm_eop = -1;
264+
int ret;
265+
242266
// TX program should be placed at address 0
243-
pio_add_program_at_offset(pp->pio_usb_tx, pp->fs_tx_program, 0);
244-
pp->offset_tx = 0;
267+
if (pio_can_add_program_at_offset(pp->pio_usb_tx, pp->fs_tx_program, 0)) {
268+
offset_tx = pio_add_program_at_offset(pp->pio_usb_tx, pp->fs_tx_program, 0);
269+
if (tx_inst_count)
270+
*tx_inst_count = pp->fs_tx_program->length;
271+
} else {
272+
goto err_out;
273+
}
274+
ret = try_add_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
275+
&usb_nrzi_decoder_debug_program, &offset_rx, c->debug_pin_rx);
276+
if (ret <= 0)
277+
goto err_out;
278+
if (rx_inst_count)
279+
*rx_inst_count = ret;
280+
ret = try_add_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
281+
&usb_edge_detector_debug_program, &offset_eop, c->debug_pin_eop);
282+
if (ret <= 0)
283+
goto err_out;
284+
if (rx_inst_count)
285+
*rx_inst_count += ret;
286+
if (c->sm_tx < 0) {
287+
sm_tx = pio_claim_unused_sm(pp->pio_usb_tx, false);
288+
if (sm_tx < 0)
289+
goto err_out;
290+
} else {
291+
pp->sm_tx = c->sm_tx;
292+
pio_sm_claim(pp->pio_usb_tx, pp->sm_tx);
293+
}
294+
if (c->sm_rx < 0) {
295+
sm_rx = pio_claim_unused_sm(pp->pio_usb_rx, false);
296+
if (sm_rx < 0)
297+
goto err_out;
298+
} else {
299+
pp->sm_rx = c->sm_rx;
300+
pio_sm_claim(pp->pio_usb_rx, pp->sm_rx);
301+
}
302+
if (c->sm_eop < 0) {
303+
sm_eop = pio_claim_unused_sm(pp->pio_usb_rx, false);
304+
if (sm_eop < 0)
305+
goto err_out;
306+
} else {
307+
pp->sm_eop = c->sm_eop;
308+
pio_sm_claim(pp->pio_usb_rx, pp->sm_eop);
309+
}
310+
pp->offset_tx = offset_tx;
311+
pp->offset_rx = offset_rx;
312+
pp->offset_eop = offset_eop;
313+
if (c->sm_rx < 0)
314+
pp->sm_rx = sm_rx;
315+
if (c->sm_tx < 0)
316+
pp->sm_tx = sm_tx;
317+
if (c->sm_eop < 0)
318+
pp->sm_eop = sm_eop;
245319
usb_tx_fs_program_init(pp->pio_usb_tx, pp->sm_tx, pp->offset_tx, port->pin_dp,
246320
port->pin_dm);
247321
pp->tx_start_instr = pio_encode_jmp(pp->offset_tx + 4);
248322
pp->tx_reset_instr = pio_encode_jmp(pp->offset_tx + 2);
249323

250-
add_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
251-
&usb_nrzi_decoder_debug_program, &pp->offset_rx,
252-
c->debug_pin_rx);
253324
usb_rx_fs_program_init(pp->pio_usb_rx, pp->sm_rx, pp->offset_rx, port->pin_dp,
254325
port->pin_dm, c->debug_pin_rx);
255326
pp->rx_reset_instr = pio_encode_jmp(pp->offset_rx);
256327
pp->rx_reset_instr2 = pio_encode_set(pio_x, 0);
257328

258-
add_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
259-
&usb_edge_detector_debug_program, &pp->offset_eop,
260-
c->debug_pin_eop);
261-
eop_detect_fs_program_init(pp->pio_usb_rx, c->sm_eop, pp->offset_eop,
329+
eop_detect_fs_program_init(pp->pio_usb_rx, pp->sm_eop, pp->offset_eop,
262330
port->pin_dp, port->pin_dm, true,
263331
c->debug_pin_eop);
264332

@@ -267,6 +335,25 @@ static void __no_inline_not_in_flash_func(initialize_host_programs)(
267335
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_rx, port->pin_dp);
268336
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_eop, port->pin_dm);
269337
pio_sm_set_in_pins(pp->pio_usb_rx, pp->sm_eop, port->pin_dp);
338+
339+
return true;
340+
341+
err_out:
342+
if (offset_tx >= 0)
343+
pio_remove_program(pp->pio_usb_tx, pp->fs_tx_program, offset_tx);
344+
if (offset_rx >= 0)
345+
remove_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
346+
&usb_nrzi_decoder_debug_program, offset_rx, c->debug_pin_rx);
347+
if (offset_eop >= 0)
348+
remove_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
349+
&usb_edge_detector_debug_program, offset_eop, c->debug_pin_eop);
350+
if (sm_tx >= 0)
351+
pio_sm_unclaim(pp->pio_usb_tx, sm_tx);
352+
if (sm_rx >= 0)
353+
pio_sm_unclaim(pp->pio_usb_rx, sm_rx);
354+
if (sm_eop >= 0)
355+
pio_sm_unclaim(pp->pio_usb_rx, sm_eop);
356+
return false;
270357
}
271358

272359
static void configure_tx_channel(uint8_t ch, PIO pio, uint sm) {
@@ -281,15 +368,43 @@ static void configure_tx_channel(uint8_t ch, PIO pio, uint sm) {
281368
dma_channel_set_write_addr(ch, &pio->txf[sm], false);
282369
}
283370

371+
static bool init_host_programs(
372+
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port,
373+
uint *tx_inst_count, uint *rx_inst_count) {
374+
bool pio_rx_auto = false, pio_tx_auto = false;
375+
376+
if (!pp->pio_usb_tx) {
377+
pio_tx_auto = true;
378+
pp->pio_usb_tx = pio0;
379+
}
380+
if (!pp->pio_usb_rx) {
381+
pio_rx_auto = true;
382+
pp->pio_usb_rx = pio1;
383+
}
384+
if (try_initialize_host_programs(pp, c, port, tx_inst_count, rx_inst_count))
385+
return true;
386+
if (!pio_tx_auto && !pio_rx_auto)
387+
return false;
388+
if (pio_tx_auto)
389+
pp->pio_usb_tx = pio1;
390+
if (pio_rx_auto)
391+
pp->pio_usb_rx = pio0;
392+
return try_initialize_host_programs(pp, c, port, tx_inst_count, rx_inst_count);
393+
}
394+
284395
static void apply_config(pio_port_t *pp, const pio_usb_configuration_t *c,
285396
root_port_t *port) {
286-
pp->pio_usb_tx = pio_get_instance(c->pio_tx_num);
287-
pp->sm_tx = c->sm_tx;
288-
pp->tx_ch = c->tx_ch;
289-
pp->pio_usb_rx = pio_get_instance(c->pio_rx_num);
290-
pp->sm_rx = c->sm_rx;
291-
pp->sm_eop = c->sm_eop;
292-
port->pin_dp = c->pin_dp;
397+
if (c->pio_tx_num >= 0)
398+
pp->pio_usb_tx = pio_get_instance(c->pio_tx_num);
399+
else
400+
pp->pio_usb_tx = NULL;
401+
402+
if (c->pio_rx_num >=-0)
403+
pp->pio_usb_rx = pio_get_instance(c->pio_rx_num);
404+
else
405+
pp->pio_usb_tx = NULL;
406+
407+
port->pin_dp = c->pin_dp;
293408

294409
uint highest_pin;
295410
if (c->pinout == PIO_USB_PINOUT_DPDM) {
@@ -319,10 +434,6 @@ static void apply_config(pio_port_t *pp, const pio_usb_configuration_t *c,
319434

320435
pp->debug_pin_rx = c->debug_pin_rx;
321436
pp->debug_pin_eop = c->debug_pin_eop;
322-
323-
pio_sm_claim(pp->pio_usb_tx, pp->sm_tx);
324-
pio_sm_claim(pp->pio_usb_rx, pp->sm_rx);
325-
pio_sm_claim(pp->pio_usb_rx, pp->sm_eop);
326437
}
327438

328439
static void port_pin_drive_setting(const root_port_t *port) {
@@ -332,16 +443,36 @@ static void port_pin_drive_setting(const root_port_t *port) {
332443
gpio_set_drive_strength(port->pin_dm, GPIO_DRIVE_STRENGTH_12MA);
333444
}
334445

446+
static void get_dma_channel(pio_port_t *pp, const pio_usb_configuration_t *c) {
447+
if (c->tx_ch < 0) {
448+
pp->tx_ch = dma_claim_unused_channel(true);
449+
} else {
450+
pp->tx_ch = c->tx_ch;
451+
dma_channel_claim(pp->tx_ch + 1);
452+
}
453+
}
454+
455+
static void dump_allocated_hw_resources(
456+
const pio_port_t *pp, uint tx_inst_count, uint rx_inst_count) {
457+
printf("pio-usb is using:\n");
458+
printf("\tUSB transmitter: %d instructions @ PIO %d, State Machine %d, DMA %d\n",
459+
tx_inst_count, pp->pio_usb_tx == pio1 ? 1 : 0, pp->sm_tx, pp->tx_ch);
460+
printf("\tUSB receiver: %d instructions @ PIO %d, State Machines %d and %d\n",
461+
rx_inst_count, pp->pio_usb_rx == pio1 ? 1 : 0, pp->sm_rx, pp->sm_eop);
462+
}
463+
335464
void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
336465
root_port_t *root) {
337-
memset(root, 0, sizeof(root_port_t));
466+
uint tx_inst_count = 0, rx_inst_count = 0;
338467

339-
pp->pio_usb_tx = pio_get_instance(c->pio_tx_num);
340-
dma_claim_mask(1<<c->tx_ch);
341-
configure_tx_channel(c->tx_ch, pp->pio_usb_tx, c->sm_tx);
468+
memset(root, 0, sizeof(root_port_t));
469+
get_dma_channel(pp, c);
342470

343471
apply_config(pp, c, root);
344-
initialize_host_programs(pp, c, root);
472+
if (!init_host_programs(pp, c, root, &tx_inst_count, &rx_inst_count))
473+
panic("pio-usb: Not enough hardware resources - State Machines and instructions");
474+
configure_tx_channel(pp->tx_ch, pp->pio_usb_tx, pp->sm_tx);
475+
345476
port_pin_drive_setting(root);
346477
root->initialized = true;
347478
root->dev_addr = 0;
@@ -355,6 +486,8 @@ void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
355486
pio_usb_ll_encode_tx_data(raw_packet, 2, stall_encoded);
356487
raw_packet[1] = USB_PID_PRE;
357488
pio_usb_ll_encode_tx_data(raw_packet, 2, pre_encoded);
489+
490+
dump_allocated_hw_resources(pp, tx_inst_count, rx_inst_count);
358491
}
359492

360493
//--------------------------------------------------------------------+

src/pio_usb_configuration.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ typedef enum {
88

99
typedef struct {
1010
uint8_t pin_dp;
11-
uint8_t pio_tx_num;
12-
uint8_t sm_tx;
13-
uint8_t tx_ch;
14-
uint8_t pio_rx_num;
15-
uint8_t sm_rx;
16-
uint8_t sm_eop;
11+
int8_t pio_tx_num;
12+
int8_t sm_tx;
13+
int8_t tx_ch;
14+
int8_t pio_rx_num;
15+
int8_t sm_rx;
16+
int8_t sm_eop;
1717
void* alarm_pool;
1818
int8_t debug_pin_rx;
1919
int8_t debug_pin_eop;
@@ -30,8 +30,8 @@ typedef struct {
3030
#define PIO_USB_DMA_TX_DEFAULT 0
3131

3232
#define PIO_USB_RX_DEFAULT 0
33-
#define PIO_SM_USB_RX_DEFAULT 1
34-
#define PIO_SM_USB_EOP_DEFAULT 2
33+
#define PIO_SM_USB_RX_DEFAULT 0
34+
#define PIO_SM_USB_EOP_DEFAULT 0
3535

3636
#define PIO_USB_DEBUG_PIN_NONE (-1)
3737

0 commit comments

Comments
 (0)