From 75facdee728967824472901504a61aba8fa347cb Mon Sep 17 00:00:00 2001 From: curuvar <58759586+curuvar@users.noreply.github.com> Date: Wed, 22 Jun 2022 20:23:07 -0400 Subject: [PATCH] Added PWM support for rp2040 --- .gitignore | 4 + arch/arm/Kconfig | 1 + arch/arm/src/rp2040/Kconfig | 76 +++++ arch/arm/src/rp2040/Make.defs | 4 + boards/arm/rp2040/common/src/Make.defs | 4 + boards/arm/rp2040/pimoroni-tiny2040/Kconfig | 266 +++++++++++++++ .../arm/rp2040/pimoroni-tiny2040/README.txt | 1 + .../pimoroni-tiny2040/src/rp2040_bringup.c | 279 ++++++++++++++++ boards/arm/rp2040/raspberrypi-pico/Kconfig | 304 ++++++++++++++++++ boards/arm/rp2040/raspberrypi-pico/README.txt | 1 + .../raspberrypi-pico/src/rp2040_bringup.c | 279 ++++++++++++++++ 11 files changed, 1219 insertions(+) diff --git a/.gitignore b/.gitignore index b632f78ca3..658e3c09b5 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ .depend /.config /.config.old +/.config\ * /.cproject /.gdbinit /.project @@ -50,5 +51,8 @@ uImage /external # $(TOPDIR)/Makefile.[unix|win]::$(CONTEXTDIRS_DEPS) .context +.context\ * # $(TOPDIR)/Makefile.[unix|win]::$(DIRLINKS_EXTERNAL_DIRS) .dirlinks +.vscode +.DS_Store diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 8061da504c..da54cacfa5 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -235,6 +235,7 @@ config ARCH_CHIP_RP2040 select ARCH_HAVE_I2CRESET select ARM_HAVE_WFE_SEV select LIBC_ARCH_ATOMIC + select ARCH_HAVE_PWM_MULTICHAN ---help--- Raspberry Pi RP2040 architectures (ARM dual Cortex-M0+). diff --git a/arch/arm/src/rp2040/Kconfig b/arch/arm/src/rp2040/Kconfig index cd0c35cf59..79913bb041 100644 --- a/arch/arm/src/rp2040/Kconfig +++ b/arch/arm/src/rp2040/Kconfig @@ -141,6 +141,82 @@ config RP2040_I2C_DRIVER endif +config RP2040_PWM + bool "PWM" + select PWM + ---help--- + After enabling PWM support here, configure the GPIO pins to use + under the Board Selection menu. + +if RP2040_PWM + +config PWM_MULTICHAN + bool "Support Multi-Channel PWM" + default y + ---help--- + If support for multi-channel PWM is disabled, the generated code + will only support the A channel of the PWM slices. + + if PWM_MULTICHAN + config PWM_NCHANNELS + int "Number of channels" + default 2 + ---help--- + If the number of channels is set to 1, the generated code will + only support the A channel of the PWM slices. This is functionally + identical to disabling multi-channel PWM support. + endif + + config RP2040_PWM0 + bool "PWM0" + ---help--- + Drives GPIO pin 0 or 16 with the A channel, and + drives GPIO pin 1 or 17 with the B channel. + + config RP2040_PWM1 + bool "PWM1" + ---help--- + Drives GPIO pin 2 or 18 with the A channel, and + drives GPIO pin 3 or 19 with the B channel. + + config RP2040_PWM2 + bool "PWM2" + ---help--- + Drives GPIO pin 4 or 20 with the A channel, and + drives GPIO pin 5 or 21 with the B channel. + + config RP2040_PWM3 + bool "PWM3" + ---help--- + Drives GPIO pin 6 or 22 with the A channel, and + drives GPIO pin 7 or 23 with the B channel. + + config RP2040_PWM4 + bool "PWM4" + ---help--- + Drives GPIO pin 8 or 24 with the A channel, and + drives GPIO pin 9 or 25 with the B channel. + + config RP2040_PWM5 + bool "PWM5" + ---help--- + Drives GPIO pin 10 or 26 with the A channel, and + drives GPIO pin 11 or 27 with the B channel. + + config RP2040_PWM6 + bool "PWM6" + ---help--- + Drives GPIO pin 12 or 28 with the A channel, and + drives GPIO pin 13 or 29 with the B channel. + + config RP2040_PWM7 + bool "PWM7 (Pin 14 and 15)" + ---help--- + Drives GPIO pin 14 with the A channel, and + drives GPIO pin 15 with the B channel. + +endif + config RP2040_I2S bool "I2S" select I2S diff --git a/arch/arm/src/rp2040/Make.defs b/arch/arm/src/rp2040/Make.defs index 95fe8d1d24..d9819d9a67 100644 --- a/arch/arm/src/rp2040/Make.defs +++ b/arch/arm/src/rp2040/Make.defs @@ -49,6 +49,10 @@ ifeq ($(CONFIG_RP2040_SPI),y) CHIP_CSRCS += rp2040_spi.c endif +ifeq ($(CONFIG_RP2040_PWM),y) +CHIP_CSRCS += rp2040_pwm.c +endif + ifeq ($(CONFIG_RP2040_I2C),y) CHIP_CSRCS += rp2040_i2c.c endif diff --git a/boards/arm/rp2040/common/src/Make.defs b/boards/arm/rp2040/common/src/Make.defs index 1fa5ecb93a..0f6c36cfec 100644 --- a/boards/arm/rp2040/common/src/Make.defs +++ b/boards/arm/rp2040/common/src/Make.defs @@ -24,6 +24,10 @@ ifeq ($(CONFIG_RP2040_I2C_DRIVER),y) CSRCS += rp2040_i2cdev.c endif +ifeq ($(CONFIG_RP2040_PWM),y) +CSRCS += rp2040_pwmdev.c +endif + ifeq ($(CONFIG_RP2040_SPI_DRIVER),y) CSRCS += rp2040_spidev.c endif diff --git a/boards/arm/rp2040/pimoroni-tiny2040/Kconfig b/boards/arm/rp2040/pimoroni-tiny2040/Kconfig index 5c8bab8ca5..a021973340 100644 --- a/boards/arm/rp2040/pimoroni-tiny2040/Kconfig +++ b/boards/arm/rp2040/pimoroni-tiny2040/Kconfig @@ -50,6 +50,272 @@ config RP2040_I2C1_GPIO range -1 29 depends on RP2040_I2C1 +if RP2040_PWM0 + config RP2040_PWM0A_GPIO + int "PWM0 channel 1 GPIO pin assign (0 or -1:no assign)" + default 0 + range -1 16 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 0, any other value disables the output. + + config RP2040_PWM0A_INVERT + bool "PWM0 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM0B_GPIO + int "PWM0 channel 2 GPIO pin assign (1 or -1:no assign)" + default 1 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 1, any other value disables the output. + + config RP2040_PWM0B_INVERT + bool "PWM0 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM0_PHASE_CORRECT + bool "PWM0 phase correct" + default n +endif + +if RP2040_PWM1 + config RP2040_PWM1A_GPIO + int "PWM1 channel 1 GPIO pin assign (2, 18 or -1:no assign)" + default 2 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 2 or 18, any other value disables the output. + + config RP2040_PWM1A_INVERT + bool "PWM1 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM1B_GPIO + int "PWM1 channel 2 GPIO pin assign (3, 19 or -1:no assign)" + default 3 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 3 or 19, any other value disables the output. + + config RP2040_PWM1B_INVERT + bool "PWM1 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM1_PHASE_CORRECT + bool "PWM1 phase correct" + default n +endif + +if RP2040_PWM2 + config RP2040_PWM2A_GPIO + int "PWM2 channel 1 GPIO pin assign (4, 20 or -1:no assign)" + default 4 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 4 or 20, any other value disables the output. + + config RP2040_PWM2A_INVERT + bool "PWM2 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM2B_GPIO + int "PWM2 channel 2 GPIO pin assign (5, 21 or -1:no assign)" + default 5 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 5 or 21, any other value disables the output. + + config RP2040_PWM2B_INVERT + bool "PWM2 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM2_PHASE_CORRECT + bool "PWM2 phase correct" + default n +endif + +if RP2040_PWM3 + config RP2040_PWM3A_GPIO + int "PWM3 channel 1 GPIO pin assign (6 or -1:no assign)" + default 6 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 6, any other value disables the output. + + config RP2040_PWM3A_INVERT + bool "PWM3 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM3B_GPIO + int "PWM3 channel 2 GPIO pin assign (7 or -1:no assign)" + default 7 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 7, any other value disables the output. + + config RP2040_PWM3B_INVERT + bool "PWM3 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM3_PHASE_CORRECT + bool "PWM3 phase correct" + default n +endif + +if RP2040_PWM5 + config RP2040_PWM5A_GPIO + int "PWM5 channel 1 GPIO pin assign (26 or -1:no assign)" + default 26 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 26, any other value disables the output. + + config RP2040_PWM5A_INVERT + bool "PWM5 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM5B_GPIO + int "PWM5 channel 2 GPIO pin assign (27 or -1:no assign)" + default 27 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 27, any other value disables the output. + + config RP2040_PWM5B_INVERT + bool "PWM5 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM5_PHASE_CORRECT + bool "PWM5 phase correct" + default n +endif + +if RP2040_PWM6 + config RP2040_PWM6A_GPIO + int "PWM6 channel 1 GPIO pin assign (28 or -1:no assign)" + default 28 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 28, any other value disables the output. + + config RP2040_PWM6A_INVERT + bool "PWM6 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM6B_GPIO + int "PWM6 channel 2 GPIO pin assign (29 or -1:no assign)" + default 29 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 29, any other value disables the output. + + config RP2040_PWM6B_INVERT + bool "PWM6 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM6_PHASE_CORRECT + bool "PWM6 phase correct" + default n +endif + +if RP2040_PWM7 + config RP2040_PWM7A_GPIO + int "PWM7 channel 1 GPIO pin assign (14 or -1:no assign)" + default 14 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 14, any other value disables the output. + + config RP2040_PWM7A_INVERT + bool "PWM7 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM7B_GPIO + int "PWM7 channel 2 GPIO pin assign (15 or -1:no assign)" + default 15 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 15, any other value disables the output. + + config RP2040_PWM7B_INVERT + bool "PWM7 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM7_PHASE_CORRECT + bool "PWM7 phase correct" + default n +endif + config RP2040_SPI0_GPIO int "SPI0 GPIO pin assign (0,4,16,20 or -1:no assign)" default -1 diff --git a/boards/arm/rp2040/pimoroni-tiny2040/README.txt b/boards/arm/rp2040/pimoroni-tiny2040/README.txt index 04ce9d17b5..c742f8c037 100644 --- a/boards/arm/rp2040/pimoroni-tiny2040/README.txt +++ b/boards/arm/rp2040/pimoroni-tiny2040/README.txt @@ -16,6 +16,7 @@ Currently only the following devices are supported. - I2C (not tested on Tiny 2040) - SPI - DMAC + - PWM - USB device - MSC, CDC/ACM serial and these composite device are supported. - CDC/ACM serial device can be used for the console. diff --git a/boards/arm/rp2040/pimoroni-tiny2040/src/rp2040_bringup.c b/boards/arm/rp2040/pimoroni-tiny2040/src/rp2040_bringup.c index 755dfb9241..99e8657d82 100644 --- a/boards/arm/rp2040/pimoroni-tiny2040/src/rp2040_bringup.c +++ b/boards/arm/rp2040/pimoroni-tiny2040/src/rp2040_bringup.c @@ -33,6 +33,11 @@ #include "rp2040_tiny2040.h" +#ifdef CONFIG_RP2040_PWM +#include "rp2040_pwm.h" +#include "rp2040_pwmdev.h" +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -119,5 +124,279 @@ int rp2040_bringup(void) } #endif +#ifdef CONFIG_RP2040_PWM +# ifdef CONFIG_RP2040_PWM0 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(0, + CONFIG_RP2040_PWM0A_GPIO, + CONFIG_RP2040_PWM0B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM0A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM0B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM0_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(0, + CONFIG_RP2040_PWM0A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM0A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM0_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM0.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM1 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(1, + CONFIG_RP2040_PWM1A_GPIO, + CONFIG_RP2040_PWM1B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM1A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM1B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM1_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(1, + CONFIG_RP2040_PWM1A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM1A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM1_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM1.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM2 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(2, + CONFIG_RP2040_PWM2A_GPIO, + CONFIG_RP2040_PWM2B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM2A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM2B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM2_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(2, + CONFIG_RP2040_PWM2A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM2A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM2_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM2.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM3 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(3, + CONFIG_RP2040_PWM3A_GPIO, + CONFIG_RP2040_PWM3B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM3A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM3B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM3_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(3, + CONFIG_RP2040_PWM3A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM3A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM3_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM3.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM4 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(4, + CONFIG_RP2040_PWM4A_GPIO, + CONFIG_RP2040_PWM4B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM4A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM4B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM4_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(4, + CONFIG_RP2040_PWM4A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM4A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM4_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM4.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM5 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(5, + CONFIG_RP2040_PWM5A_GPIO, + CONFIG_RP2040_PWM5B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM5A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM5B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM5_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(5, + CONFIG_RP2040_PWM5A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM5A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM5_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM5.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM6 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(6, + CONFIG_RP2040_PWM6A_GPIO, + CONFIG_RP2040_PWM6B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM6A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM6B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM6_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(6, + CONFIG_RP2040_PWM6A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM6A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM6_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM6.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM7 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(7, + CONFIG_RP2040_PWM7A_GPIO, + CONFIG_RP2040_PWM7B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM7A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM7B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM7_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(7, + CONFIG_RP2040_PWM7A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM7A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM7_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM7.\n"); + } +# endif +#endif + return ret; } diff --git a/boards/arm/rp2040/raspberrypi-pico/Kconfig b/boards/arm/rp2040/raspberrypi-pico/Kconfig index 871e53b8ac..a2bf69e6af 100644 --- a/boards/arm/rp2040/raspberrypi-pico/Kconfig +++ b/boards/arm/rp2040/raspberrypi-pico/Kconfig @@ -50,6 +50,310 @@ config RP2040_I2C1_GPIO range -1 29 depends on RP2040_I2C1 +if RP2040_PWM0 + config RP2040_PWM0A_GPIO + int "PWM0 channel 1 GPIO pin assign (0, 16 or -1:no assign)" + default 0 + range -1 16 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 0 or 16, any other value disables the output. + + config RP2040_PWM0A_INVERT + bool "PWM0 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM0B_GPIO + int "PWM0 channel 2 GPIO pin assign (1, 17 or -1:no assign)" + default 1 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 1 or 17, any other value disables the output. + + config RP2040_PWM0B_INVERT + bool "PWM0 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM0_PHASE_CORRECT + bool "PWM0 phase correct" + default n +endif + +if RP2040_PWM1 + config RP2040_PWM1A_GPIO + int "PWM1 channel 1 GPIO pin assign (2, 18 or -1:no assign)" + default 2 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 2 or 18, any other value disables the output. + + config RP2040_PWM1A_INVERT + bool "PWM1 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM1B_GPIO + int "PWM1 channel 2 GPIO pin assign (3, 19 or -1:no assign)" + default 3 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 3 or 19, any other value disables the output. + + config RP2040_PWM1B_INVERT + bool "PWM1 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM1_PHASE_CORRECT + bool "PWM1 phase correct" + default n +endif + +if RP2040_PWM2 + config RP2040_PWM2A_GPIO + int "PWM2 channel 1 GPIO pin assign (4, 20 or -1:no assign)" + default 4 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 4 or 20, any other value disables the output. + + config RP2040_PWM2A_INVERT + bool "PWM2 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM2B_GPIO + int "PWM2 channel 2 GPIO pin assign (5, 21 or -1:no assign)" + default 5 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 5 or 21, any other value disables the output. + + config RP2040_PWM2B_INVERT + bool "PWM2 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM2_PHASE_CORRECT + bool "PWM2 phase correct" + default n +endif + +if RP2040_PWM3 + config RP2040_PWM3A_GPIO + int "PWM3 channel 1 GPIO pin assign (6, 22 or -1:no assign)" + default 6 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 6 or 22, any other value disables the output. + + config RP2040_PWM3A_INVERT + bool "PWM3 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM3B_GPIO + int "PWM3 channel 2 GPIO pin assign (7, 23 or -1:no assign)" + default 7 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 7 or 23, any other value disables the output. + + config RP2040_PWM3B_INVERT + bool "PWM3 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM3_PHASE_CORRECT + bool "PWM3 phase correct" + default n +endif + +if RP2040_PWM4 + config RP2040_PWM4A_GPIO + int "PWM4 channel 1 GPIO pin assign (8, 24 or -1:no assign)" + default 8 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 8 or 24, any other value disables the output. + + config RP2040_PWM4A_INVERT + bool "PWM4 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM4B_GPIO + int "PWM4 channel 2 GPIO pin assign (9, 25 or -1:no assign)" + default 9 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 9 or 25, any other value disables the output. + + config RP2040_PWM4B_INVERT + bool "PWM4 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM4_PHASE_CORRECT + bool "PWM4 phase correct" + default n +endif + +if RP2040_PWM5 + config RP2040_PWM5A_GPIO + int "PWM5 channel 1 GPIO pin assign (10, 26 or -1:no assign)" + default 10 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 10 or 26, any other value disables the output. + + config RP2040_PWM5A_INVERT + bool "PWM5 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM5B_GPIO + int "PWM5 channel 2 GPIO pin assign (11, 27 or -1:no assign)" + default 11 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 11 or 27, any other value disables the output. + + config RP2040_PWM5B_INVERT + bool "PWM5 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM5_PHASE_CORRECT + bool "PWM5 phase correct" + default n +endif + +if RP2040_PWM6 + config RP2040_PWM6A_GPIO + int "PWM6 channel 1 GPIO pin assign (12, 28 or -1:no assign)" + default 12 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 12 or 28, any other value disables the output. + + config RP2040_PWM6A_INVERT + bool "PWM6 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM6B_GPIO + int "PWM6 channel 2 GPIO pin assign (13, 29 or -1:no assign)" + default 13 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 13 or 29, any other value disables the output. + + config RP2040_PWM6B_INVERT + bool "PWM6 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM6_PHASE_CORRECT + bool "PWM6 phase correct" + default n +endif + +if RP2040_PWM7 + config RP2040_PWM7A_GPIO + int "PWM7 channel 1 GPIO pin assign (14 or -1:no assign)" + default 14 + range -1 29 + ---help--- + This sets the GPIO pin to use for the A channel it must be + either 14, any other value disables the output. + + config RP2040_PWM7A_INVERT + bool "PWM7 channel 1 invert" + default n + ---help--- + If invert is enabled, the PWM on the A pin will idle high + with the pulse going low. + + if PWM_MULTICHAN && PWM_NCHANNELS > 1 + config RP2040_PWM7B_GPIO + int "PWM7 channel 2 GPIO pin assign (15 or -1:no assign)" + default 15 + range -1 29 + ---help--- + This sets the GPIO pin to use for the B channel it must be + either 15, any other value disables the output. + + config RP2040_PWM7B_INVERT + bool "PWM7 channel 2 invert" + default n + ---help--- + If invert is enabled, the PWM on the B pin will idle high + with the pulse going low. + endif + + config RP2040_PWM7_PHASE_CORRECT + bool "PWM7 phase correct" + default n +endif + config RP2040_SPI0_GPIO int "SPI0 GPIO pin assign (0,4,16,20 or -1:no assign)" default -1 diff --git a/boards/arm/rp2040/raspberrypi-pico/README.txt b/boards/arm/rp2040/raspberrypi-pico/README.txt index 392335525d..ed799eadd3 100644 --- a/boards/arm/rp2040/raspberrypi-pico/README.txt +++ b/boards/arm/rp2040/raspberrypi-pico/README.txt @@ -13,6 +13,7 @@ Currently only the following devices are supported. - I2C - SPI - DMAC + - PWM - USB device - MSC, CDC/ACM serial and these composite device are supported. - CDC/ACM serial device can be used for the console. diff --git a/boards/arm/rp2040/raspberrypi-pico/src/rp2040_bringup.c b/boards/arm/rp2040/raspberrypi-pico/src/rp2040_bringup.c index 750a93b1e5..76ff7058c2 100644 --- a/boards/arm/rp2040/raspberrypi-pico/src/rp2040_bringup.c +++ b/boards/arm/rp2040/raspberrypi-pico/src/rp2040_bringup.c @@ -59,6 +59,11 @@ #include "rp2040_bmp180.h" #endif +#ifdef CONFIG_RP2040_PWM +#include "rp2040_pwm.h" +#include "rp2040_pwmdev.h" +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -107,6 +112,280 @@ int rp2040_bringup(void) #endif #endif +#ifdef CONFIG_RP2040_PWM +# ifdef CONFIG_RP2040_PWM0 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(0, + CONFIG_RP2040_PWM0A_GPIO, + CONFIG_RP2040_PWM0B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM0A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM0B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM0_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(0, + CONFIG_RP2040_PWM0A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM0A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM0_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM0.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM1 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(1, + CONFIG_RP2040_PWM1A_GPIO, + CONFIG_RP2040_PWM1B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM1A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM1B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM1_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(1, + CONFIG_RP2040_PWM1A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM1A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM1_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM1.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM2 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(2, + CONFIG_RP2040_PWM2A_GPIO, + CONFIG_RP2040_PWM2B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM2A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM2B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM2_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(2, + CONFIG_RP2040_PWM2A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM2A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM2_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM2.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM3 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(3, + CONFIG_RP2040_PWM3A_GPIO, + CONFIG_RP2040_PWM3B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM3A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM3B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM3_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(3, + CONFIG_RP2040_PWM3A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM3A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM3_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM3.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM4 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(4, + CONFIG_RP2040_PWM4A_GPIO, + CONFIG_RP2040_PWM4B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM4A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM4B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM4_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(4, + CONFIG_RP2040_PWM4A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM4A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM4_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM4.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM5 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(5, + CONFIG_RP2040_PWM5A_GPIO, + CONFIG_RP2040_PWM5B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM5A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM5B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM5_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(5, + CONFIG_RP2040_PWM5A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM5A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM5_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM5.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM6 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(6, + CONFIG_RP2040_PWM6A_GPIO, + CONFIG_RP2040_PWM6B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM6A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM6B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM6_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(6, + CONFIG_RP2040_PWM6A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM6A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM6_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM6.\n"); + } +# endif + +# ifdef CONFIG_RP2040_PWM7 +# if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS == 2 + ret = rp2040_pwmdev_initialize(7, + CONFIG_RP2040_PWM7A_GPIO, + CONFIG_RP2040_PWM7B_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM7A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM7B_INVERT + | RP2040_PWM_CSR_B_INV +# endif +# ifdef CONFIG_RP2040_PWM7_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# else + ret = rp2040_pwmdev_initialize(7, + CONFIG_RP2040_PWM7A_GPIO, + (0 +# ifdef CONFIG_RP2040_PWM7A_INVERT + | RP2040_PWM_CSR_A_INV +# endif +# ifdef CONFIG_RP2040_PWM7_PHASE_CORRECT + | RP2040_PWM_CSR_PH_CORRECT +# endif + )); +# endif + if (ret < 0) + { + _err("ERROR: Failed to initialize PWM7.\n"); + } +# endif +#endif + #ifdef CONFIG_RP2040_SPISD /* Mount the SPI-based MMC/SD block driver */