diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index e23deb889..d6924c8b6 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -359,7 +359,8 @@ "-fsingle-precision-constant" ], "cStandard": "c11", - "intelliSenseMode": "gcc-arm" + "intelliSenseMode": "gcc-arm", + "compilerPath": "arm-none-eabi-gcc" }, { "name": "pbio/test", diff --git a/bricks/_common/sources.mk b/bricks/_common/sources.mk index 5523185ff..8140a32ef 100644 --- a/bricks/_common/sources.mk +++ b/bricks/_common/sources.mk @@ -169,6 +169,7 @@ PBIO_SRC_C = $(addprefix lib/pbio/,\ drv/pwm/pwm_core.c \ drv/pwm/pwm_ev3.c \ drv/pwm/pwm_lp50xx_stm32.c \ + drv/pwm/pwm_pico.c \ drv/pwm/pwm_stm32_tim.c \ drv/pwm/pwm_test.c \ drv/pwm/pwm_tlc5955_stm32.c \ diff --git a/lib/pbio/drv/pwm/pwm_core.c b/lib/pbio/drv/pwm/pwm_core.c index cb0da5310..1d9dcd22c 100644 --- a/lib/pbio/drv/pwm/pwm_core.c +++ b/lib/pbio/drv/pwm/pwm_core.c @@ -16,6 +16,7 @@ #include "pwm_lp50xx_stm32.h" #include "pwm_tlc5955_stm32.h" #include "pwm_ev3.h" +#include "pwm_pico.h" #include "pwm.h" @@ -28,6 +29,7 @@ void pbdrv_pwm_init(void) { pbdrv_pwm_stm32_tim_init(pbdrv_pwm_dev); pbdrv_pwm_test_init(pbdrv_pwm_dev); pbdrv_pwm_lp50xx_stm32_init(pbdrv_pwm_dev); + pbdrv_pwm_pico_init(pbdrv_pwm_dev); pbdrv_pwm_tlc5955_stm32_init(pbdrv_pwm_dev); pbdrv_pwm_tiam1808_init(pbdrv_pwm_dev); } diff --git a/lib/pbio/drv/pwm/pwm_pico.c b/lib/pbio/drv/pwm/pwm_pico.c new file mode 100644 index 000000000..3f8fcc617 --- /dev/null +++ b/lib/pbio/drv/pwm/pwm_pico.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2026 The Pybricks Authors + +#include + +#if PBDRV_CONFIG_PWM_PICO + +#include +#include +#include + +#include "../drv/pwm/pwm.h" +#include "../drv/pwm/pwm_pico.h" +#include "../../drv/led/led_pwm.h" + +#include "hardware/gpio.h" +#include "hardware/pwm.h" + +static pbio_error_t pbdrv_pwm_pico_set_duty(pbdrv_pwm_dev_t *dev, uint32_t ch, uint32_t value) { + // Blue not available. + if (ch == PBDRV_LED_PWM_CHANNEL_INVALID) { + return PBIO_SUCCESS; + } + + if (ch >= PBDRV_CONFIG_PWM_PICO_NUM_CHANNELS) { + return PBIO_ERROR_INVALID_ARG; + } + + const pbdrv_pwm_pico_platform_data_t *pdata = dev->pdata; + const pbdrv_pwm_pico_channel_t *channel = &pdata->channels[ch]; + + pwm_set_gpio_level(channel->gpio, value); + + return PBIO_SUCCESS; +} + +static const pbdrv_pwm_driver_funcs_t pbdrv_pwm_pico_funcs = { + .set_duty = pbdrv_pwm_pico_set_duty, +}; + +void pbdrv_pwm_pico_init(pbdrv_pwm_dev_t *devs) { + const pbdrv_pwm_pico_platform_data_t *pdata = &pbdrv_pwm_pico_platform_data; + + devs[pdata->id].funcs = &pbdrv_pwm_pico_funcs; + devs[pdata->id].pdata = pdata; + + for (int i = 0; i < PBDRV_CONFIG_PWM_PICO_NUM_CHANNELS; i++) { + const pbdrv_pwm_pico_channel_t *channel = &pdata->channels[i]; + + // Tell the LED pin that the PWM is in charge of its value. + gpio_set_function(channel->gpio, GPIO_FUNC_PWM); + // Figure out which slice we just connected to the LED pin + uint slice_num = pwm_gpio_to_slice_num(channel->gpio); + + // Get some sensible defaults for the slice configuration. By default, + // the counter is allowed to wrap over its maximum range (0 to 2**16-1). + pwm_config config = pwm_get_default_config(); + // Set divider, reduces counter clock to sysclock/this value. + pwm_config_set_clkdiv(&config, 4.f); + // Load the configuration into our PWM slice, and set it running. + pwm_init(slice_num, &config, true); + } +} + +#endif // PBDRV_CONFIG_PWM_PICO diff --git a/lib/pbio/drv/pwm/pwm_pico.h b/lib/pbio/drv/pwm/pwm_pico.h new file mode 100644 index 000000000..845d656ee --- /dev/null +++ b/lib/pbio/drv/pwm/pwm_pico.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2026 The Pybricks Authors + +// Hooks for unit picos. + +#ifndef _INTERNAL_PBDRV_PWM_PICO_H_ +#define _INTERNAL_PBDRV_PWM_PICO_H_ + +#include + +#if PBDRV_CONFIG_PWM_PICO + +#include + +#include + +/** Platform-specific device information. */ + +typedef struct { + uint8_t gpio; +} pbdrv_pwm_pico_channel_t; + +typedef struct { + uint8_t id; + pbdrv_pwm_pico_channel_t channels[PBDRV_CONFIG_PWM_PICO_NUM_CHANNELS]; +} pbdrv_pwm_pico_platform_data_t; + +// Defined in platform.c +extern const pbdrv_pwm_pico_platform_data_t pbdrv_pwm_pico_platform_data; + +void pbdrv_pwm_pico_init(pbdrv_pwm_dev_t *devs); + +#else // PBDRV_CONFIG_PWM_PICO + +#define pbdrv_pwm_pico_init(dev) + +#endif // PBDRV_CONFIG_PWM_PICO + +#endif // _INTERNAL_PBDRV_PWM_PICO_H_ diff --git a/lib/pbio/platform/build_hat/pbdrvconfig.h b/lib/pbio/platform/build_hat/pbdrvconfig.h index 6895a2242..0d0e5a462 100644 --- a/lib/pbio/platform/build_hat/pbdrvconfig.h +++ b/lib/pbio/platform/build_hat/pbdrvconfig.h @@ -20,14 +20,18 @@ #define PBDRV_CONFIG_IOPORT_HAS_UART (1) // TODO: Implement IOPORT driver for Build HAT -#define PBDRV_CONFIG_LED (0) -// TODO: Implement LED driver for Build HAT (should be similar to EV3) +#define PBDRV_CONFIG_LED (1) +#define PBDRV_CONFIG_LED_NUM_DEV (1) +#define PBDRV_CONFIG_LED_PWM (1) +#define PBDRV_CONFIG_LED_PWM_NUM_DEV (1) #define PBDRV_CONFIG_MOTOR_DRIVER (0) // TODO: Implement motor driver for Build HAT -#define PBDRV_CONFIG_PWM (0) -// TODO: Implement PWM driver for Build HAT +#define PBDRV_CONFIG_PWM (1) +#define PBDRV_CONFIG_PWM_NUM_DEV (1) +#define PBDRV_CONFIG_PWM_PICO (1) +#define PBDRV_CONFIG_PWM_PICO_NUM_CHANNELS (2) #define PBDRV_CONFIG_RANDOM (0) // TODO: Implement RANDOM driver for Build HAT diff --git a/lib/pbio/platform/build_hat/pbioconfig.h b/lib/pbio/platform/build_hat/pbioconfig.h index 420830e8c..0bc36e0d6 100644 --- a/lib/pbio/platform/build_hat/pbioconfig.h +++ b/lib/pbio/platform/build_hat/pbioconfig.h @@ -6,7 +6,7 @@ #define PBIO_CONFIG_DCMOTOR_NUM_DEV (4) #define PBIO_CONFIG_DRIVEBASE_SPIKE (0) #define PBIO_CONFIG_IMU (0) // TODO -#define PBIO_CONFIG_LIGHT (0) // TODO +#define PBIO_CONFIG_LIGHT (1) #define PBIO_CONFIG_LOGGER (1) #define PBIO_CONFIG_MOTOR_PROCESS (1) #define PBIO_CONFIG_PORT (0) // TODO diff --git a/lib/pbio/platform/build_hat/pbsysconfig.h b/lib/pbio/platform/build_hat/pbsysconfig.h index 3c8bb04be..4bc42d625 100644 --- a/lib/pbio/platform/build_hat/pbsysconfig.h +++ b/lib/pbio/platform/build_hat/pbsysconfig.h @@ -18,7 +18,7 @@ #define PBSYS_CONFIG_STORAGE (0) // TODO ? #define PBSYS_CONFIG_STORAGE_NUM_SLOTS (1) #define PBSYS_CONFIG_STORAGE_USER_DATA_SIZE (128) -#define PBSYS_CONFIG_STATUS_LIGHT (0) // TODO +#define PBSYS_CONFIG_STATUS_LIGHT (1) #define PBSYS_CONFIG_STATUS_LIGHT_BATTERY (0) #define PBSYS_CONFIG_STATUS_LIGHT_BLUETOOTH (0) #define PBSYS_CONFIG_STATUS_LIGHT_STATE_ANIMATIONS (1) diff --git a/lib/pbio/platform/build_hat/platform.c b/lib/pbio/platform/build_hat/platform.c index 47a08088e..c41bd567d 100644 --- a/lib/pbio/platform/build_hat/platform.c +++ b/lib/pbio/platform/build_hat/platform.c @@ -1,14 +1,63 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2025 The Pybricks Authors +// Copyright (c) 2025-2026 The Pybricks Authors #include +#include "../../drv/led/led_pwm.h" +#include "../../drv/pwm/pwm_pico.h" + #include "hardware/gpio.h" +enum { + PWM_DEV_0, +}; + +enum { + LED_DEV_0_STATUS, +}; + const pbdrv_gpio_t pbdrv_ioport_platform_data_vcc_pin = { .pin = 17, }; +// LED + +static const pbdrv_led_pwm_platform_color_t pbdrv_led_pwm_color = { + .r_factor = 1000, + .g_factor = 1000, + .b_factor = 0, + // Tuned with scale_factor=17 so pure red/green are as close as possible + // to UINT16_MAX without exceeding it. + .r_brightness = 83, + .g_brightness = 83, + .b_brightness = 0, +}; + +const pbdrv_led_pwm_platform_data_t pbdrv_led_pwm_platform_data[PBDRV_CONFIG_LED_PWM_NUM_DEV] = { + { + .color = &pbdrv_led_pwm_color, + .id = LED_DEV_0_STATUS, + .r_id = PWM_DEV_0, + .r_ch = 0, + .g_id = PWM_DEV_0, + .g_ch = 1, + // Blue not available. + .b_id = PWM_DEV_0, + .b_ch = PBDRV_LED_PWM_CHANNEL_INVALID, + .scale_factor = 17, + }, +}; + +// PWM + +const pbdrv_pwm_pico_platform_data_t pbdrv_pwm_pico_platform_data = { + .id = PWM_DEV_0, + .channels = { + { .gpio = 14 }, // LED0 + { .gpio = 15 }, // LED1 + } +}; + int main(void) { extern void pbsys_main(void); pbsys_main(); diff --git a/pybricks/hubs/pb_type_buildhat.c b/pybricks/hubs/pb_type_buildhat.c index fbb9f0db4..f7e679467 100644 --- a/pybricks/hubs/pb_type_buildhat.c +++ b/pybricks/hubs/pb_type_buildhat.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2025 The Pybricks Authors +// Copyright (c) 2025-2026 The Pybricks Authors #include "py/mpconfig.h" #if PYBRICKS_PY_HUBS && PYBRICKS_HUB_BUILDHAT +#include + #include #include @@ -13,16 +15,19 @@ typedef struct _hubs_BuildHat_obj_t { mp_obj_base_t base; + mp_obj_t light; mp_obj_t system; } hubs_BuildHat_obj_t; static mp_obj_t hubs_BuildHat_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { hubs_BuildHat_obj_t *self = mp_obj_malloc(hubs_BuildHat_obj_t, type); + self->light = common_ColorLight_internal_obj_new(pbsys_status_light_main); self->system = MP_OBJ_FROM_PTR(&pb_type_System); return MP_OBJ_FROM_PTR(self); } static const pb_attr_dict_entry_t hubs_BuildHat_attr_dict[] = { + PB_DEFINE_CONST_ATTR_RO(MP_QSTR_light, hubs_BuildHat_obj_t, light), PB_DEFINE_CONST_ATTR_RO(MP_QSTR_system, hubs_BuildHat_obj_t, system), PB_ATTR_DICT_SENTINEL };