Skip to content

Commit b40f675

Browse files
ArcaneNibbledlech
authored andcommitted
pbio/drv/rproc: Introduce remote coprocessor subsystem
This is currently going to be used to manage the EV3 PRUs, which involve a number of implicit dependencies between unrelated modules. This begins by moving the EV3 PWM logic to depend on the new subsystem.
1 parent b77115b commit b40f675

8 files changed

Lines changed: 123 additions & 44 deletions

File tree

bricks/_common/sources.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\
175175
drv/reset/reset_nxt.c \
176176
drv/reset/reset_stm32.c \
177177
drv/resistor_ladder/resistor_ladder.c \
178+
drv/rproc/rproc_ev3.c \
178179
drv/sound/beep_sampled.c \
179180
drv/sound/sound_ev3.c \
180181
drv/sound/sound_nxt.c \

lib/pbio/drv/core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "pwm/pwm.h"
2626
#include "random/random.h"
2727
#include "reset/reset.h"
28+
#include "rproc/rproc.h"
2829
#include "sound/sound.h"
2930
#include "uart/uart.h"
3031
#include "uart/uart_debug_first_port.h"
@@ -55,6 +56,7 @@ void pbdrv_init(void) {
5556
pbdrv_pwm_init();
5657
pbdrv_random_init();
5758
pbdrv_reset_init();
59+
pbdrv_rproc_init();
5860
pbdrv_sound_init();
5961
pbdrv_uart_init();
6062
pbdrv_uart_debug_init();

lib/pbio/drv/pwm/pwm_ev3.c

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,75 +5,36 @@
55

66
#if PBDRV_CONFIG_PWM_TIAM1808
77

8-
#include <stdio.h>
9-
#include <string.h>
10-
118
#include <pbdrv/pwm.h>
129
#include <pbdrv/gpio.h>
1310
#include <pbio/error.h>
1411

15-
#include <tiam1808/hw/hw_syscfg0_AM1808.h>
16-
#include <tiam1808/hw/hw_types.h>
17-
#include <tiam1808/hw/soc_AM1808.h>
18-
#include <tiam1808/pruss.h>
19-
#include <tiam1808/psc.h>
20-
#include <tiam1808/timer.h>
21-
2212
#include "../drv/pwm/pwm.h"
2313
#include "../../drv/led/led_pwm.h"
2414
#include "../../drv/pwm/pwm_ev3.h"
2515
#include "../../drv/gpio/gpio_ev3.h"
2616

27-
// This needs to match the interface expected by the PRU firmware
28-
typedef struct shared_ram {
29-
uint8_t pwms[PBDRV_PWM_EV3_NUM_CHANNELS];
30-
} shared_ram;
31-
static volatile shared_ram pru1_shared_ram __attribute__((section(".shared1")));
32-
3317
static pbio_error_t pbdrv_pwm_tiam1808_set_duty(pbdrv_pwm_dev_t *dev, uint32_t ch, uint32_t value) {
3418
// Blue not available.
3519
if (ch == PBDRV_LED_PWM_CHANNEL_INVALID) {
3620
return PBIO_SUCCESS;
3721
}
3822

39-
pru1_shared_ram.pwms[ch] = value;
23+
pbdrv_rproc_ev3_pru1_shared_ram.pwms[ch] = value;
4024
return PBIO_SUCCESS;
4125
}
4226

4327
static const pbdrv_pwm_driver_funcs_t pbdrv_pwm_tiam1808_funcs = {
4428
.set_duty = pbdrv_pwm_tiam1808_set_duty,
4529
};
4630

47-
extern char _pru1_start;
48-
extern char _pru1_end;
49-
5031
#define PINMUX_ALT_PRU1 4
5132

5233
void pbdrv_pwm_tiam1808_init(pbdrv_pwm_dev_t *devs) {
53-
// Enable Timer0 "34" half to count up to 256 * 256
54-
// This is used by the PRU to time the PWM
55-
TimerPreScalarCount34Set(SOC_TMR_0_REGS, 0);
56-
TimerPeriodSet(SOC_TMR_0_REGS, TMR_TIMER34, 256 * 256 - 1);
57-
TimerEnable(SOC_TMR_0_REGS, TMR_TIMER34, TMR_ENABLE_CONT);
58-
59-
// Clear shared command memory
60-
memset((void *)&pru1_shared_ram, 0, sizeof(shared_ram));
61-
62-
// Enable PRU1 and load its firmware
63-
PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_PRU, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
64-
PRUSSDRVPruDisable(1);
65-
PRUSSDRVPruReset(1);
66-
unsigned int *fw_start = (unsigned int *)&_pru1_start;
67-
uint32_t fw_sz = &_pru1_end - &_pru1_start;
68-
PRUSSDRVPruWriteMemory(PRUSS0_PRU1_IRAM, 0, fw_start, fw_sz);
69-
// Set constant table C30 to point to shared memory
70-
PRUSSDRVPruSetCTable(1, 30, (((uint32_t)&pru1_shared_ram) >> 8) & 0xffff);
71-
PRUSSDRVPruEnable(1);
72-
7334
devs[0].funcs = &pbdrv_pwm_tiam1808_funcs;
7435

7536
// Set GPIO alt modes for the PRU
76-
for (int j = 0; j < PBDRV_PWM_EV3_NUM_CHANNELS; j++) {
37+
for (int j = 0; j < PBDRV_RPROC_EV3_PRU1_NUM_PWM_CHANNELS; j++) {
7738
pbdrv_gpio_alt(&pbdrv_pwm_tiam1808_platform_data.gpios[j], PINMUX_ALT_PRU1);
7839
}
7940
}

lib/pbio/drv/pwm/pwm_ev3.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,12 @@
1212

1313
#include <pbdrv/pwm.h>
1414
#include <pbdrv/gpio.h>
15-
16-
#define PBDRV_PWM_EV3_NUM_CHANNELS 4
15+
#include "../rproc/rproc_ev3.h"
1716

1817
/** Platform-specific device information. */
1918
typedef struct {
2019
uint8_t id;
21-
pbdrv_gpio_t gpios[PBDRV_PWM_EV3_NUM_CHANNELS];
20+
pbdrv_gpio_t gpios[PBDRV_RPROC_EV3_PRU1_NUM_PWM_CHANNELS];
2221
} pbdrv_pwm_tiam1808_platform_data_t;
2322

2423
// Defined in platform.c

lib/pbio/drv/rproc/rproc.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 The Pybricks Authors
3+
4+
#ifndef _INTERNAL_PBDRV_RPROC_H_
5+
#define _INTERNAL_PBDRV_RPROC_H_
6+
7+
#include <stdbool.h>
8+
9+
#include <pbdrv/config.h>
10+
11+
#if PBDRV_CONFIG_RPROC
12+
13+
/**
14+
* Initializes "remote" coprocessors early during the startup sequence
15+
*/
16+
void pbdrv_rproc_init(void);
17+
18+
/**
19+
* Determines whether remote coprocessors have been initialized
20+
*/
21+
bool pbdrv_rproc_is_ready(void);
22+
23+
#else // PBDRV_CONFIG_RPROC
24+
25+
#define pbdrv_rproc_init()
26+
#define pbdrv_rproc_is_ready() true
27+
28+
#endif // PBDRV_CONFIG_RPROC
29+
30+
#endif // _INTERNAL_PBDRV_RPROC_H_

lib/pbio/drv/rproc/rproc_ev3.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 The Pybricks Authors
3+
4+
// Manages EV3 PRU coprocessor initialization
5+
6+
#include <pbdrv/config.h>
7+
8+
#if PBDRV_CONFIG_RPROC_EV3
9+
10+
#include <stdbool.h>
11+
#include <string.h>
12+
13+
#include <tiam1808/hw/hw_syscfg0_AM1808.h>
14+
#include <tiam1808/hw/soc_AM1808.h>
15+
#include <tiam1808/pruss.h>
16+
#include <tiam1808/psc.h>
17+
#include <tiam1808/timer.h>
18+
19+
#include "rproc_ev3.h"
20+
21+
volatile pbdrv_rproc_ev3_pru1_shared_ram_t pbdrv_rproc_ev3_pru1_shared_ram __attribute__((section(".shared1")));
22+
23+
static bool pbdrv_ev3_rproc_is_ready;
24+
25+
extern char _pru1_start;
26+
extern char _pru1_end;
27+
28+
void pbdrv_rproc_init(void) {
29+
// Enable PRU subsystem
30+
PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_PRU, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
31+
32+
// PRU1 initialization
33+
34+
// Enable Timer0 "34" half to count up to 256 * 256
35+
// This is used by the PRU to time the PWM
36+
TimerPreScalarCount34Set(SOC_TMR_0_REGS, 0);
37+
TimerPeriodSet(SOC_TMR_0_REGS, TMR_TIMER34, 256 * 256 - 1);
38+
TimerEnable(SOC_TMR_0_REGS, TMR_TIMER34, TMR_ENABLE_CONT);
39+
40+
// Clear shared command memory
41+
memset((void *)&pbdrv_rproc_ev3_pru1_shared_ram, 0, sizeof(pbdrv_rproc_ev3_pru1_shared_ram));
42+
43+
// Enable PRU1 and load its firmware
44+
PRUSSDRVPruDisable(1);
45+
PRUSSDRVPruReset(1);
46+
unsigned int *fw_start = (unsigned int *)&_pru1_start;
47+
uint32_t fw_sz = &_pru1_end - &_pru1_start;
48+
PRUSSDRVPruWriteMemory(PRUSS0_PRU1_IRAM, 0, fw_start, fw_sz);
49+
// Set constant table C30 to point to shared memory
50+
PRUSSDRVPruSetCTable(1, 30, (((uint32_t)&pbdrv_rproc_ev3_pru1_shared_ram) >> 8) & 0xffff);
51+
PRUSSDRVPruEnable(1);
52+
53+
// All good
54+
pbdrv_ev3_rproc_is_ready = true;
55+
}
56+
57+
bool pbdrv_rproc_is_ready(void) {
58+
return pbdrv_ev3_rproc_is_ready;
59+
}
60+
61+
#endif // PBDRV_CONFIG_RPROC_EV3

lib/pbio/drv/rproc/rproc_ev3.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: MIT
2+
// Copyright (c) 2025 The Pybricks Authors
3+
4+
#ifndef _INTERNAL_PBDRV_RPROC_EV3_H_
5+
#define _INTERNAL_PBDRV_RPROC_EV3_H_
6+
7+
#include <stdint.h>
8+
9+
// EV3 PRU interfaces and ABI
10+
// These need to match the interface expected by the PRU firmware
11+
12+
// PRU1 interface
13+
14+
#define PBDRV_RPROC_EV3_PRU1_NUM_PWM_CHANNELS 4
15+
16+
typedef struct {
17+
uint8_t pwms[PBDRV_RPROC_EV3_PRU1_NUM_PWM_CHANNELS];
18+
} pbdrv_rproc_ev3_pru1_shared_ram_t;
19+
20+
extern volatile pbdrv_rproc_ev3_pru1_shared_ram_t pbdrv_rproc_ev3_pru1_shared_ram;
21+
22+
#endif // _INTERNAL_PBDRV_RPROC_EV3_H_

lib/pbio/platform/ev3/pbdrvconfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@
7070
#define PBDRV_CONFIG_RESET (1)
7171
#define PBDRV_CONFIG_RESET_EV3 (1)
7272

73+
#define PBDRV_CONFIG_RPROC (1)
74+
#define PBDRV_CONFIG_RPROC_EV3 (1)
75+
7376
#define PBDRV_CONFIG_SOUND (1)
7477
#define PBDRV_CONFIG_SOUND_EV3 (1)
7578
#define PBDRV_CONFIG_SOUND_DEFAULT_VOLUME 75

0 commit comments

Comments
 (0)