Skip to content

Commit 2b6e7e8

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 0f747aa commit 2b6e7e8

File tree

2 files changed

+168
-40
lines changed

2 files changed

+168
-40
lines changed

src/pio_usb.c

Lines changed: 162 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -202,43 +202,154 @@ int __no_inline_not_in_flash_func(pio_usb_bus_receive_packet_and_handshake)(
202202
return -1;
203203
}
204204

205-
static __always_inline void add_pio_host_rx_program(PIO pio,
205+
static __always_inline int try_add_pio_host_rx_program(PIO pio,
206206
const pio_program_t *program,
207207
const pio_program_t *debug_program,
208-
uint *offset, int debug_pin) {
208+
int *offset, int debug_pin) {
209+
const pio_program_t *prog;
210+
211+
if (debug_pin < 0)
212+
prog = program;
213+
else
214+
prog = debug_program;
215+
216+
if (pio_can_add_program(pio, prog)) {
217+
*offset = pio_add_program(pio, prog);
218+
return prog->length;
219+
}
220+
221+
return -1;
222+
}
223+
224+
static __always_inline void remove_pio_host_rx_program(PIO pio,
225+
const pio_program_t *program,
226+
const pio_program_t *debug_program,
227+
int offset, int debug_pin) {
209228
if (debug_pin < 0) {
210-
*offset = pio_add_program(pio, program);
229+
pio_remove_program(pio, program, offset);
211230
} else {
212-
*offset = pio_add_program(pio, debug_program);
231+
pio_remove_program(pio, debug_program, offset);
213232
}
214233
}
215234

216-
static void __no_inline_not_in_flash_func(initialize_host_programs)(
217-
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port) {
218-
pp->offset_tx = pio_add_program(pp->pio_usb_tx, pp->fs_tx_program);
235+
static bool __no_inline_not_in_flash_func(try_initialize_host_programs)(
236+
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port,
237+
uint *tx_inst_count, uint *rx_inst_count) {
238+
int offset_tx = -1, offset_rx = -1, offset_eop = -1;
239+
int sm_tx = -1, sm_rx = -1, sm_eop = -1;
240+
int ret;
241+
242+
if (pio_can_add_program(pp->pio_usb_tx, pp->fs_tx_program)) {
243+
offset_tx = pio_add_program(pp->pio_usb_tx, pp->fs_tx_program);
244+
if (tx_inst_count)
245+
*tx_inst_count = pp->fs_tx_program->length;
246+
} else {
247+
goto err_out;
248+
}
249+
ret = try_add_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
250+
&usb_nrzi_decoder_debug_program, &offset_rx, c->debug_pin_rx);
251+
if (ret <= 0)
252+
goto err_out;
253+
if (rx_inst_count)
254+
*rx_inst_count = ret;
255+
ret = try_add_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
256+
&usb_edge_detector_debug_program, &offset_eop, c->debug_pin_eop);
257+
if (ret <= 0)
258+
goto err_out;
259+
if (rx_inst_count)
260+
*rx_inst_count += ret;
261+
if (c->sm_tx < 0) {
262+
sm_tx = pio_claim_unused_sm(pp->pio_usb_tx, false);
263+
if (sm_tx < 0)
264+
goto err_out;
265+
} else {
266+
pp->sm_tx = c->sm_tx;
267+
pio_sm_claim(pp->pio_usb_tx, pp->sm_tx);
268+
}
269+
270+
if (c->sm_rx < 0) {
271+
sm_rx = pio_claim_unused_sm(pp->pio_usb_rx, false);
272+
if (sm_rx < 0)
273+
goto err_out;
274+
} else {
275+
pp->sm_rx = c->sm_rx;
276+
pio_sm_claim(pp->pio_usb_rx, pp->sm_rx);
277+
}
278+
if (c->sm_eop < 0) {
279+
sm_eop = pio_claim_unused_sm(pp->pio_usb_rx, false);
280+
if (sm_eop < 0)
281+
goto err_out;
282+
} else {
283+
pp->sm_eop = c->sm_eop;
284+
pio_sm_claim(pp->pio_usb_rx, pp->sm_eop);
285+
}
286+
287+
pp->offset_tx = offset_tx;
288+
pp->offset_rx = offset_rx;
289+
pp->offset_eop = offset_eop;
290+
if (c->sm_rx < 0)
291+
pp->sm_rx = sm_rx;
292+
if (c->sm_tx < 0)
293+
pp->sm_tx = sm_tx;
294+
if (c->sm_eop < 0)
295+
pp->sm_eop = sm_eop;
219296
usb_tx_fs_program_init(pp->pio_usb_tx, pp->sm_tx, pp->offset_tx,
220297
port->pin_dp, port->pin_dm);
221-
222-
add_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
223-
&usb_nrzi_decoder_debug_program, &pp->offset_rx,
224-
c->debug_pin_rx);
225298
usb_rx_fs_program_init(pp->pio_usb_rx, pp->sm_rx, pp->offset_rx, port->pin_dp,
226299
port->pin_dm, c->debug_pin_rx);
227-
pp->rx_reset_instr = pio_encode_jmp(pp->offset_rx);
228-
pp->rx_reset_instr2 = pio_encode_set(pio_x, 0);
229-
230-
add_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
231-
&usb_edge_detector_debug_program, &pp->offset_eop,
232-
c->debug_pin_eop);
233-
eop_detect_fs_program_init(pp->pio_usb_rx, c->sm_eop, pp->offset_eop,
300+
eop_detect_fs_program_init(pp->pio_usb_rx, pp->sm_eop, pp->offset_eop,
234301
port->pin_dp, port->pin_dm, true,
235302
c->debug_pin_eop);
303+
pp->rx_reset_instr = pio_encode_jmp(pp->offset_rx);
304+
pp->rx_reset_instr2 = pio_encode_set(pio_x, 0);
236305

237306
usb_tx_configure_pins(pp->pio_usb_tx, pp->sm_tx, port->pin_dp, port->pin_dm);
238-
239307
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_rx, port->pin_dp);
240308
pio_sm_set_jmp_pin(pp->pio_usb_rx, pp->sm_eop, port->pin_dm);
241309
pio_sm_set_in_pins(pp->pio_usb_rx, pp->sm_eop, port->pin_dp);
310+
311+
return true;
312+
313+
err_out:
314+
if (offset_tx >= 0)
315+
pio_remove_program(pp->pio_usb_tx, pp->fs_tx_program, offset_tx);
316+
if (offset_rx >= 0)
317+
remove_pio_host_rx_program(pp->pio_usb_rx, &usb_nrzi_decoder_program,
318+
&usb_nrzi_decoder_debug_program, offset_rx, c->debug_pin_rx);
319+
if (offset_eop >= 0)
320+
remove_pio_host_rx_program(pp->pio_usb_rx, &usb_edge_detector_program,
321+
&usb_edge_detector_debug_program, offset_eop, c->debug_pin_eop);
322+
if (sm_tx >= 0)
323+
pio_sm_unclaim(pp->pio_usb_tx, sm_tx);
324+
if (sm_rx >= 0)
325+
pio_sm_unclaim(pp->pio_usb_rx, sm_rx);
326+
if (sm_eop >= 0)
327+
pio_sm_unclaim(pp->pio_usb_rx, sm_eop);
328+
return false;
329+
}
330+
331+
static bool init_host_programs(
332+
pio_port_t *pp, const pio_usb_configuration_t *c, root_port_t *port,
333+
uint *tx_inst_count, uint *rx_inst_count) {
334+
bool pio_rx_auto = false, pio_tx_auto = false;
335+
336+
if (!pp->pio_usb_tx) {
337+
pio_tx_auto = true;
338+
pp->pio_usb_tx = pio0;
339+
}
340+
if (!pp->pio_usb_rx) {
341+
pio_rx_auto = true;
342+
pp->pio_usb_rx = pio1;
343+
}
344+
if (try_initialize_host_programs(pp, c, port, tx_inst_count, rx_inst_count))
345+
return true;
346+
if (!pio_tx_auto && !pio_rx_auto)
347+
return false;
348+
if (pio_tx_auto)
349+
pp->pio_usb_tx = pio1;
350+
if (pio_rx_auto)
351+
pp->pio_usb_rx = pio0;
352+
return try_initialize_host_programs(pp, c, port, tx_inst_count, rx_inst_count);
242353
}
243354

244355
static void configure_tx_channel(uint8_t ch, PIO pio, uint sm) {
@@ -255,12 +366,14 @@ static void configure_tx_channel(uint8_t ch, PIO pio, uint sm) {
255366

256367
static void apply_config(pio_port_t *pp, const pio_usb_configuration_t *c,
257368
root_port_t *port) {
258-
pp->pio_usb_tx = c->pio_tx_num == 0 ? pio0 : pio1;
259-
pp->sm_tx = c->sm_tx;
260-
pp->tx_ch = c->tx_ch;
261-
pp->pio_usb_rx = c->pio_rx_num == 0 ? pio0 : pio1;
262-
pp->sm_rx = c->sm_rx;
263-
pp->sm_eop = c->sm_eop;
369+
if (c->pio_tx_num >= 0)
370+
pp->pio_usb_tx = c->pio_tx_num == 0 ? pio0 : pio1;
371+
else
372+
pp->pio_usb_tx = NULL;
373+
if (c->pio_rx_num >=-0)
374+
pp->pio_usb_rx = c->pio_rx_num == 0 ? pio0 : pio1;
375+
else
376+
pp->pio_usb_tx = NULL;
264377
port->pin_dp = c->pin_dp;
265378

266379
if (c->pinout == PIO_USB_PINOUT_DPDM) {
@@ -277,10 +390,24 @@ static void apply_config(pio_port_t *pp, const pio_usb_configuration_t *c,
277390

278391
pp->debug_pin_rx = c->debug_pin_rx;
279392
pp->debug_pin_eop = c->debug_pin_eop;
393+
}
280394

281-
pio_sm_claim(pp->pio_usb_tx, pp->sm_tx);
282-
pio_sm_claim(pp->pio_usb_rx, pp->sm_rx);
283-
pio_sm_claim(pp->pio_usb_rx, pp->sm_eop);
395+
static void get_dma_channel(pio_port_t *pp, const pio_usb_configuration_t *c) {
396+
if (c->tx_ch < 0) {
397+
pp->tx_ch = dma_claim_unused_channel(true);
398+
} else {
399+
pp->tx_ch = c->tx_ch;
400+
dma_channel_claim(pp->tx_ch + 1);
401+
}
402+
}
403+
404+
static void dump_allocated_hw_resources(
405+
const pio_port_t *pp, uint tx_inst_count, uint rx_inst_count) {
406+
printf("pio-usb is using:\n");
407+
printf("\tUSB transmitter: %d instructions @ PIO %d, State Machine %d, DMA %d\n",
408+
tx_inst_count, pp->pio_usb_tx == pio1 ? 1 : 0, pp->sm_tx, pp->tx_ch);
409+
printf("\tUSB receiver: %d instructions @ PIO %d, State Machines %d and %d\n",
410+
rx_inst_count, pp->pio_usb_rx == pio1 ? 1 : 0, pp->sm_rx, pp->sm_eop);
284411
}
285412

286413
static void port_pin_drive_setting(const root_port_t *port) {
@@ -292,17 +419,18 @@ static void port_pin_drive_setting(const root_port_t *port) {
292419

293420
void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
294421
root_port_t *root) {
295-
memset(root, 0, sizeof(root_port_t));
296-
297-
pp->pio_usb_tx = c->pio_tx_num == 0 ? pio0 : pio1;
298-
dma_claim_mask(1<<c->tx_ch);
299-
configure_tx_channel(c->tx_ch, pp->pio_usb_tx, c->sm_tx);
422+
uint tx_inst_count = 0, rx_inst_count = 0;
300423

424+
memset(root, 0, sizeof(root_port_t));
425+
get_dma_channel(pp, c);
301426
apply_config(pp, c, root);
302-
initialize_host_programs(pp, c, root);
427+
if (!init_host_programs(pp, c, root, &tx_inst_count, &rx_inst_count))
428+
panic("pio-usb: Not enough hardware resources - State Machines and instructions");
429+
configure_tx_channel(pp->tx_ch, pp->pio_usb_tx, pp->sm_tx);
303430
port_pin_drive_setting(root);
304431
root->initialized = true;
305432
root->dev_addr = 0;
433+
dump_allocated_hw_resources(pp, tx_inst_count, rx_inst_count);
306434
}
307435

308436
//--------------------------------------------------------------------+

src/pio_usb_configuration.h

Lines changed: 6 additions & 6 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;

0 commit comments

Comments
 (0)