This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 2667f51c821914f3f6bc664000bad036d0650e83 Author: leocafonso <[email protected]> AuthorDate: Sun Nov 16 12:20:56 2025 -0800 arch/ra4: Add PWM driver support for RA4M1 - Added PWM driver support for the RA4M1 microcontroller using the GPT timer. - This driver supports Saw-wave mode and one of the two output channels (A or B). - Added necessary configurations in CMakeLists.txt, Kconfig, and Make.defs. - Created new header file for GPT. Signed-off-by: leocafonso <[email protected]> --- arch/arm/src/ra4/CMakeLists.txt | 3 +- arch/arm/src/ra4/Kconfig | 386 ++++++++++++++++ arch/arm/src/ra4/Make.defs | 1 + arch/arm/src/ra4/hardware/ra4m1_mstp.h | 4 +- arch/arm/src/ra4/hardware/ra4m1_pinmap.h | 73 ++- arch/arm/src/ra4/hardware/ra_gpio.h | 2 + arch/arm/src/ra4/hardware/ra_gpt.h | 224 +++++++++ arch/arm/src/ra4/ra_pwm.c | 751 +++++++++++++++++++++++++++++++ arch/arm/src/ra4/ra_pwm.h | 129 ++++++ 9 files changed, 1569 insertions(+), 4 deletions(-) diff --git a/arch/arm/src/ra4/CMakeLists.txt b/arch/arm/src/ra4/CMakeLists.txt index 40fb63b3051..e36d05279e2 100644 --- a/arch/arm/src/ra4/CMakeLists.txt +++ b/arch/arm/src/ra4/CMakeLists.txt @@ -27,6 +27,7 @@ set(SRCS ra_lowputc.c ra_icu.c ra_gpio.c - ra_allocateheap.c) + ra_allocateheap.c + ra_pwm.c) target_sources(arch PRIVATE ${SRCS}) diff --git a/arch/arm/src/ra4/Kconfig b/arch/arm/src/ra4/Kconfig index 0c539252229..a28f1927788 100644 --- a/arch/arm/src/ra4/Kconfig +++ b/arch/arm/src/ra4/Kconfig @@ -16,6 +16,14 @@ config ARCH_CHIP_R7FA4M1ABxxFP select RA_HAVE_SCI1_UART select RA_HAVE_SCI2_UART select RA_HAVE_SCI9_UART + select RA_HAVE_GPT0 + select RA_HAVE_GPT1 + select RA_HAVE_GPT2 + select RA_HAVE_GPT3 + select RA_HAVE_GPT4 + select RA_HAVE_GPT5 + select RA_HAVE_GPT6 + select RA_HAVE_GPT7 select RA4M1_FAMILY config ARCH_CHIP_R7FA4M1ABxxFM @@ -24,6 +32,12 @@ config ARCH_CHIP_R7FA4M1ABxxFM select RA_HAVE_SCI1_UART select RA_HAVE_SCI2_UART select RA_HAVE_SCI9_UART + select RA_HAVE_GPT0 + select RA_HAVE_GPT1 + select RA_HAVE_GPT2 + select RA_HAVE_GPT3 + select RA_HAVE_GPT4 + select RA_HAVE_GPT5 select RA4M1_FAMILY config ARCH_CHIP_R7FA4M1ABxxFL @@ -32,6 +46,12 @@ config ARCH_CHIP_R7FA4M1ABxxFL select RA_HAVE_SCI1_UART select RA_HAVE_SCI2_UART select RA_HAVE_SCI9_UART + select RA_HAVE_GPT0 + select RA_HAVE_GPT1 + select RA_HAVE_GPT2 + select RA_HAVE_GPT3 + select RA_HAVE_GPT4 + select RA_HAVE_GPT5 select RA4M1_FAMILY endchoice # RA4 Chip Selection @@ -59,6 +79,42 @@ config RA_HAVE_SCI9_UART bool default n +config RA_HAVE_GPT0 + bool + default n + +config RA_HAVE_GPT1 + bool + default n + +config RA_HAVE_GPT2 + bool + default n + +config RA_HAVE_GPT3 + bool + default n + +config RA_HAVE_GPT4 + bool + default n + +config RA_HAVE_GPT5 + bool + default n + +config RA_HAVE_GPT6 + bool + default n + +config RA_HAVE_GPT7 + bool + default n + +config RA_GPT + bool + default n + config RA_SCI0_UART bool "UART 0" default n @@ -83,4 +139,334 @@ config RA_SCI9_UART depends on RA_HAVE_SCI9_UART select SCI9_SERIALDRIVER +config RA_GPT0 + bool "GPT 0" + default n + depends on RA_HAVE_GPT0 + select RA_GPT + +config RA_GPT1 + bool "GPT 1" + default n + depends on RA_HAVE_GPT1 + select RA_GPT + +config RA_GPT2 + bool "GPT 2" + default n + depends on RA_HAVE_GPT2 + select RA_GPT + +config RA_GPT3 + bool "GPT 3" + default n + depends on RA_HAVE_GPT3 + select RA_GPT + +config RA_GPT4 + bool "GPT 4" + default n + depends on RA_HAVE_GPT4 + select RA_GPT + +config RA_GPT5 + bool "GPT 5" + default n + depends on RA_HAVE_GPT5 + select RA_GPT + +config RA_GPT6 + bool "GPT 6" + default n + depends on RA_HAVE_GPT6 + select RA_GPT + +config RA_GPT7 + bool "GPT 7" + default n + depends on RA_HAVE_GPT7 + select RA_GPT + +config RA_PWM + bool + default n + select PWM + +menu "Timer Configuration" + depends on RA_GPT + +config RA_GPT0_PWM + bool "GPT0 PWM" + default n + depends on RA_GPT0 + select RA_PWM + ---help--- + Reserve GPT 0 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If RA_GPT0 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +config RA_GPT0_OUTPUTA + bool "GPT0 OUTPUTA" + depends on RA_GPT0 + default n + +config RA_GPT0_OUTPUTB + bool "GPT0 OUTPUTB" + depends on RA_GPT0 + default n + +if RA_GPT0_PWM + +config RA_GPT0_MODE + int "GPT0 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +endif # RA_GPT0_PWM + +config RA_GPT1_PWM + bool "GPT1 PWM" + default n + depends on RA_GPT1 + select RA_PWM + ---help--- + Reserve GPT 1 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If RA_GPT1 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +config RA_GPT1_OUTPUTA + bool "GPT1 OUTPUTA" + depends on RA_GPT1 + default n + +config RA_GPT1_OUTPUTB + bool "GPT1 OUTPUTB" + depends on RA_GPT1 + default n + +if RA_GPT1_PWM + +config RA_GPT1_MODE + int "GPT1 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +endif # RA_GPT1_PWM + +config RA_GPT2_PWM + bool "GPT2 PWM" + default n + depends on RA_GPT2 + select RA_PWM + ---help--- + Reserve GPT 2 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If RA_GPT2 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +config RA_GPT2_OUTPUTA + bool "GPT2 OUTPUTA" + depends on RA_GPT2 + default n + +config RA_GPT2_OUTPUTB + bool "GPT2 OUTPUTB" + depends on RA_GPT2 + default n + +if RA_GPT2_PWM + +config RA_GPT2_MODE + int "GPT2 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +endif # RA_GPT2_PWM + +config RA_GPT3_PWM + bool "GPT3 PWM" + default n + depends on RA_GPT3 + select RA_PWM + ---help--- + Reserve GPT 3 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If RA_GPT3 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +config RA_GPT3_OUTPUTA + bool "GPT3 OUTPUTA" + depends on RA_GPT3 + default n + +config RA_GPT3_OUTPUTB + bool "GPT3 OUTPUTB" + depends on RA_GPT3 + default n + +if RA_GPT3_PWM + +config RA_GPT3_MODE + int "GPT3 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +endif # RA_GPT3_PWM + +config RA_GPT4_PWM + bool "GPT4 PWM" + default n + depends on RA_GPT4 + select RA_PWM + ---help--- + Reserve GPT 4 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If RA_GPT4 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +config RA_GPT4_OUTPUTA + bool "GPT4 OUTPUTA" + depends on RA_GPT4 + default n + +config RA_GPT4_OUTPUTB + bool "GPT4 OUTPUTB" + depends on RA_GPT4 + default n + +if RA_GPT4_PWM + +config RA_GPT4_MODE + int "GPT4 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +endif # RA_GPT4_PWM + +config RA_GPT5_PWM + bool "GPT5 PWM" + default n + depends on RA_GPT5 + select RA_PWM + ---help--- + Reserve GPT 5 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If RA_GPT5 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +config RA_GPT5_OUTPUTA + bool "GPT5 OUTPUTA" + depends on RA_GPT5 + default n + +config RA_GPT5_OUTPUTB + bool "GPT5 OUTPUTB" + depends on RA_GPT5 + default n + +if RA_GPT5_PWM + +config RA_GPT5_MODE + int "GPT5 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +endif # RA_GPT5_PWM + +config RA_GPT6_PWM + bool "GPT6 PWM" + default n + depends on RA_GPT6 + select RA_PWM + ---help--- + Reserve GPT 6 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If RA_GPT6 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +config RA_GPT6_OUTPUTA + bool "GPT6 OUTPUTA" + depends on RA_GPT6 + default n + +config RA_GPT6_OUTPUTB + bool "GPT6 OUTPUTB" + depends on RA_GPT6 + default n + +if RA_GPT6_PWM + +config RA_GPT6_MODE + int "GPT6 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +endif # RA_GPT6_PWM + +config RA_GPT7_PWM + bool "GPT7 PWM" + default n + depends on RA_GPT7 + select RA_PWM + ---help--- + Reserve GPT 7 for use by PWM + + Timer devices may be used for different purposes. One special purpose is + to generate modulated outputs for such things as motor control. If RA_GPT7 + is defined then THIS following may also be defined to indicate that + the timer is intended to be used for pulsed output modulation. + +config RA_GPT7_OUTPUTA + bool "GPT7 OUTPUTA" + depends on RA_GPT7 + default n + +config RA_GPT7_OUTPUTB + bool "GPT7 OUTPUTB" + depends on RA_GPT7 + default n + +if RA_GPT7_PWM + +config RA_GPT7_MODE + int "GPT7 Mode" + default 0 + range 0 4 + ---help--- + Specifies the timer mode. + +endif # RA_GPT7_PWM + +endmenu # Timer Configuration + endmenu # RA4M1 Peripheral Support diff --git a/arch/arm/src/ra4/Make.defs b/arch/arm/src/ra4/Make.defs index 346211b8ffd..992f031bcf0 100644 --- a/arch/arm/src/ra4/Make.defs +++ b/arch/arm/src/ra4/Make.defs @@ -35,3 +35,4 @@ CHIP_CSRCS += ra_serial.c CHIP_CSRCS += ra_lowputc.c CHIP_CSRCS += ra_allocateheap.c CHIP_CSRCS += ra_timerisr.c +CHIP_CSRCS += ra_pwm.c diff --git a/arch/arm/src/ra4/hardware/ra4m1_mstp.h b/arch/arm/src/ra4/hardware/ra4m1_mstp.h index e81ef7fee0a..0e42e07daa7 100644 --- a/arch/arm/src/ra4/hardware/ra4m1_mstp.h +++ b/arch/arm/src/ra4/hardware/ra4m1_mstp.h @@ -74,8 +74,8 @@ #define R_MSTP_MSTPCRD_DAC8 (1 << 19) /* 80000: 8-bit D/A Converter Module Stop */ #define R_MSTP_MSTPCRD_ADC14 (1 << 16) /* 10000: 14-Bit A/D Converter Module Stop */ #define R_MSTP_MSTPCRD_POEG (1 << 14) /* 4000: Port Output Enable for GPT Module Stop */ -#define R_MSTP_MSTPCRD_GPT_1 (1 << 6) /* 40: General PWM Timer 169 to 164 Module Stop */ -#define R_MSTP_MSTPCRD_GPT_2 (1 << 5) /* 20: General PWM Timer 323 to 320 Module Stop */ +#define R_MSTP_MSTPCRD_GPT_16 (1 << 6) /* 40: General PWM Timer 167 to 162 Module Stop */ +#define R_MSTP_MSTPCRD_GPT_32 (1 << 5) /* 20: General PWM Timer 321 to 320 Module Stop */ #define R_MSTP_MSTPCRD_AGT0 (1 << 3) /* 08: Asynchronous General Purpose Timer 0 Module Stop */ #define R_MSTP_MSTPCRD_AGT1 (1 << 2) /* 04: Asynchronous General Purpose Timer 1 Module Stop */ diff --git a/arch/arm/src/ra4/hardware/ra4m1_pinmap.h b/arch/arm/src/ra4/hardware/ra4m1_pinmap.h index 3bfe48256dc..eb7698e8582 100644 --- a/arch/arm/src/ra4/hardware/ra4m1_pinmap.h +++ b/arch/arm/src/ra4/hardware/ra4m1_pinmap.h @@ -71,7 +71,7 @@ #define PFS_PSEL_HIZ (0x00 << R_PFS_PSEL_SHIFT) #define PFS_PSEL_AGT (0x01 << R_PFS_PSEL_SHIFT) #define PFS_PSEL_GPT (0x02 << R_PFS_PSEL_SHIFT) -#define PFS_PSEL_AGT1 (0x03 << R_PFS_PSEL_SHIFT) +#define PFS_PSEL_GPT1 (0x03 << R_PFS_PSEL_SHIFT) #define PFS_PSEL_SCI (0x04 << R_PFS_PSEL_SHIFT) #define PFS_PSEL_SCI1 (0x05 << R_PFS_PSEL_SHIFT) #define PFS_PSEL_SPI (0x06 << R_PFS_PSEL_SHIFT) @@ -113,6 +113,75 @@ #define GPIO_RXD9_MISO9_SCL9_4 (gpio_pinset_t){ PORT6,PIN1, (PFS_PSEL_SCI1 | R_PFS_PMR)} #define GPIO_TXD9_MOSI9_SDA9_4 (gpio_pinset_t){ PORT6,PIN2, (PFS_PSEL_SCI1 | R_PFS_PMR)} +/* GTP Alternative */ + +/* GPT Channel 0 (GTIOC0A / GTIOC0B) */ + +#define GPIO_GPT_GTIOC0A_P107 (gpio_pinset_t){ PORT1,PIN7, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P107 [1] +#define GPIO_GPT_GTIOC0A_P213 (gpio_pinset_t){ PORT2,PIN13, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P213 [4] +#define GPIO_GPT_GTIOC0A_P415 (gpio_pinset_t){ PORT4,PIN15, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P415 [7] +#define GPIO_GPT_GTIOC0B_P106 (gpio_pinset_t){ PORT1,PIN6, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P106 [1] +#define GPIO_GPT_GTIOC0B_P212 (gpio_pinset_t){ PORT2,PIN12, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P212 [4] +#define GPIO_GPT_GTIOC0B_P414 (gpio_pinset_t){ PORT4,PIN14, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P414 [7] + +/* GPT Channel 1 (GTIOC1A / GTIOC1B) */ + +#define GPIO_GPT_GTIOC1A_P105 (gpio_pinset_t){ PORT1,PIN5, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P105 [1] +#define GPIO_GPT_GTIOC1A_P109 (gpio_pinset_t){ PORT1,PIN9, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P109 [6] +#define GPIO_GPT_GTIOC1A_P405 (gpio_pinset_t){ PORT4,PIN5, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P405 [6] +#define GPIO_GPT_GTIOC1B_P104 (gpio_pinset_t){ PORT1,PIN4, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P104 [1] +#define GPIO_GPT_GTIOC1B_P406 (gpio_pinset_t){ PORT4,PIN6, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P406 [6] + +/* GPT Channel 2 (GTIOC2A / GTIOC2B) */ + +#define GPIO_GPT_GTIOC2A_P103 (gpio_pinset_t){ PORT1,PIN3, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P103 [1] +#define GPIO_GPT_GTIOC2A_P113 (gpio_pinset_t){ PORT1,PIN13, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P113 [2] +#define GPIO_GPT_GTIOC2B_P102 (gpio_pinset_t){ PORT1,PIN2, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P102 [1] +#define GPIO_GPT_GTIOC2B_P114 (gpio_pinset_t){ PORT1,PIN14, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P114 [2] + +/* GPT Channel 3 (GTIOC3A / GTIOC3B) */ + +#define GPIO_GPT_GTIOC3A_P403 (gpio_pinset_t){ PORT4,PIN3, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P403 [6] +#define GPIO_GPT_GTIOC3A_P111 (gpio_pinset_t){ PORT1,PIN11, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P111 [2] +#define GPIO_GPT_GTIOC3B_P404 (gpio_pinset_t){ PORT4,PIN4, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P404 [6] +#define GPIO_GPT_GTIOC3B_P112 (gpio_pinset_t){ PORT1,PIN12, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P112 [2] + +/* GPT Channel 4 (GTIOC4A / GTIOC4B) */ + +#define GPIO_GPT_GTIOC4A_P205 (gpio_pinset_t){ PORT2,PIN5, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P205 [3] +#define GPIO_GPT_GTIOC4A_P302 (gpio_pinset_t){ PORT3,PIN2, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P302 [5] +#define GPIO_GPT_GTIOC4A_P115 (gpio_pinset_t){ PORT1,PIN15, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P115 [2] +#define GPIO_GPT_GTIOC4B_P204 (gpio_pinset_t){ PORT2,PIN4, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P204 [3] +#define GPIO_GPT_GTIOC4B_P301 (gpio_pinset_t){ PORT3,PIN1, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P301 [5] +#define GPIO_GPT_GTIOC4B_P608 (gpio_pinset_t){ PORT6,PIN8, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P608 [8] + +/* GPT Channel 5 (GTIOC5A / GTIOC5B) */ + +#define GPIO_GPT_GTIOC5A_P101 (gpio_pinset_t){ PORT1,PIN1, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P101 [1] +#define GPIO_GPT_GTIOC5A_P203 (gpio_pinset_t){ PORT2,PIN3, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P203 [3] +#define GPIO_GPT_GTIOC5A_P409 (gpio_pinset_t){ PORT4,PIN9, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P409 [7] +#define GPIO_GPT_GTIOC5A_P609 (gpio_pinset_t){ PORT6,PIN9, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P609 [8] +#define GPIO_GPT_GTIOC5B_P100 (gpio_pinset_t){ PORT1,PIN0, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P100 [1] +#define GPIO_GPT_GTIOC5B_P202 (gpio_pinset_t){ PORT2,PIN2, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P202 [3] +#define GPIO_GPT_GTIOC5B_P408 (gpio_pinset_t){ PORT4,PIN8, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P408 [7] +#define GPIO_GPT_GTIOC5B_P610 (gpio_pinset_t){ PORT6,PIN10, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P610 [8] + +/* GPT Channel 6 (GTIOC6A / GTIOC6B) */ + +#define GPIO_GPT_GTIOC6A_P400 (gpio_pinset_t){ PORT4,PIN0, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P400 [6] +#define GPIO_GPT_GTIOC6A_P411 (gpio_pinset_t){ PORT4,PIN11, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P411 [7] +#define GPIO_GPT_GTIOC6A_P601 (gpio_pinset_t){ PORT6,PIN1, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P601 [8] +#define GPIO_GPT_GTIOC6B_P401 (gpio_pinset_t){ PORT4,PIN1, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P401 [6] +#define GPIO_GPT_GTIOC6B_P410 (gpio_pinset_t){ PORT4,PIN10, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P410 [7] +#define GPIO_GPT_GTIOC6B_P600 (gpio_pinset_t){ PORT6,PIN0, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P600 [8] + +/* GPT Channel 7 (GTIOC7A / GTIOC7B) */ + +#define GPIO_GPT_GTIOC7A_P304 (gpio_pinset_t){ PORT3,PIN4, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P304 [5] +#define GPIO_GPT_GTIOC7A_P603 (gpio_pinset_t){ PORT6,PIN3, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P603 [8] +#define GPIO_GPT_GTIOC7B_P303 (gpio_pinset_t){ PORT3,PIN3, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P303 [5] +#define GPIO_GPT_GTIOC7B_P602 (gpio_pinset_t){ PORT6,PIN2, (PFS_PSEL_GPT1 | R_PFS_PMR)} // P602 [8] + /* GPIO Configuration */ #define GPIO_OUPUT R_PFS_PDR @@ -124,6 +193,8 @@ #define GPIO_OUTPUT_HIGH R_PFS_PODR #define GPIO_OUTPUT_LOW ~(R_PFS_PODR | 0xFFFFFFFF) +#define GPIO_PIN_INVALID (gpio_pinset_t){ PORT_INVALID, PIN_INVALID, 0xFFFFFFFF } + /**************************************************************************** * Public Types ****************************************************************************/ diff --git a/arch/arm/src/ra4/hardware/ra_gpio.h b/arch/arm/src/ra4/hardware/ra_gpio.h index 25e49d4e093..fa1b8782466 100644 --- a/arch/arm/src/ra4/hardware/ra_gpio.h +++ b/arch/arm/src/ra4/hardware/ra_gpio.h @@ -63,6 +63,7 @@ #define PORT7 (7) #define PORT8 (8) #define PORT9 (9) +#define PORT_INVALID (0xFF) #define PIN0 (0) #define PIN1 (1) @@ -80,6 +81,7 @@ #define PIN13 (13) #define PIN14 (14) #define PIN15 (15) +#define PIN_INVALID (0xFF) /* Relative PORT Registers */ diff --git a/arch/arm/src/ra4/hardware/ra_gpt.h b/arch/arm/src/ra4/hardware/ra_gpt.h new file mode 100644 index 00000000000..878d05c6f67 --- /dev/null +++ b/arch/arm/src/ra4/hardware/ra_gpt.h @@ -0,0 +1,224 @@ +/**************************************************************************** + * arch/arm/src/ra4/hardware/ra_gpt.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_RA4_HARDWARE_RA_GPT_H +#define __ARCH_ARM_SRC_RA4_HARDWARE_RA_GPT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include "hardware/ra_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +/* Register Offsets *********************************************************/ + +#define R_GPT_GTWP_OFFSET 0x0000 /* Write Protection Register */ +#define R_GPT_GTSTR_OFFSET 0x0004 /* Software Start Register */ +#define R_GPT_GTSTP_OFFSET 0x0008 /* Software Stop Register */ +#define R_GPT_GTCLR_OFFSET 0x000C /* Software Clear Register */ +#define R_GPT_GTSSR_OFFSET 0x0010 /* Start Source Select Register */ +#define R_GPT_GTPSR_OFFSET 0x0014 /* Stop Source Select Register */ +#define R_GPT_GTCSR_OFFSET 0x0018 /* Clear Source Select Register */ +#define R_GPT_GTUPSR_OFFSET 0x001C /* Up Count Source Select Register */ +#define R_GPT_GTDNSR_OFFSET 0x0020 /* Down Count Source Select Register */ +#define R_GPT_GTICASR_OFFSET 0x0024 /* Input Capture Source Select Register A */ +#define R_GPT_GTICBSR_OFFSET 0x0028 /* Input Capture Source Select Register B */ +#define R_GPT_GTCR_OFFSET 0x002C /* Control Register */ +#define R_GPT_GTUDDTYC_OFFSET 0x0030 /* Count Direction and Duty Setting Register */ +#define R_GPT_GTIOR_OFFSET 0x0034 /* I/O Control Register */ +#define R_GPT_GTINTAD_OFFSET 0x0038 /* Interrupt Output Setting Register */ +#define R_GPT_GTST_OFFSET 0x003C /* Status Register (alias: GTSR) */ +#define R_GPT_GTBER_OFFSET 0x0040 /* Buffer Enable Register */ +#define R_GPT_GTCNT_OFFSET 0x0048 /* Counter Register */ +#define R_GPT_GTCCRA_OFFSET 0x004C /* Compare Capture Register A */ +#define R_GPT_GTCCRB_OFFSET 0x0050 /* Compare Capture Register B */ +#define R_GPT_GTCCRC_OFFSET 0x0054 /* Compare Capture Register C */ +#define R_GPT_GTCCRE_OFFSET 0x0058 /* Compare Capture Register E */ +#define R_GPT_GTCCRD_OFFSET 0x005C /* Compare Capture Register D */ +#define R_GPT_GTCCRF_OFFSET 0x0060 /* Compare Capture Register F */ +#define R_GPT_GTPR_OFFSET 0x0064 /* Cycle Setting Register */ +#define R_GPT_GTPBR_OFFSET 0x0068 /* Cycle Setting Buffer Register */ +#define R_GPT_GTDTCR_OFFSET 0x0088 /* Dead Time Control Register */ +#define R_GPT_GTDVU_OFFSET 0x008C /* Dead Time Value Register U */ + +/* Register Bitfield Definitions ********************************************/ + +/* General PWM Timer Write-Protection Register (GTWP) */ + +#define R_GPT_GTWP_WP (1 << 0) /* Register Write Disable (b0) */ +#define R_GPT_GTWP_PRKEY_SHIFT (8) +#define R_GPT_GTWP_PRKEY_MASK (0xFF << R_GPT_GTWP_PRKEY_SHIFT) /* GTWP Key Code (b15:b8) */ +# define R_GPT_GTWP_PRKEY (0 << 0xA5) /* Key code to enable write access */ + +/* General PWM Timer Software Start Register (GTSTR) */ + +#define R_GPT_GTSTR_CSTRT0 (1 << 0) +#define R_GPT_GTSTR_CSTRT7 (1 << 7) + +/* General PWM Timer Software Stop Register (GTSTP) */ + +#define R_GPT_GTSTP_CSTOP0 (1 << 0) +#define R_GPT_GTSTP_CSTOP7 (1 << 7) + +/* General PWM Timer Software Clear Register (GTCLR) */ + +#define R_GPT_GTCLR_CCLR0 (1 << 0) +#define R_GPT_GTCLR_CCLR7 (1 << 7) + +/* General PWM Timer Count Direction and Duty Setting Register (GTUDDTYC) */ + +#define R_GPT_GTUDDTYC_UD (1 << 0) /* Count Direction Setting (b0) */ +#define R_GPT_GTUDDTYC_UDF (1 << 1) /* Forcible Count Direction Setting (b1) */ +#define R_GPT_GTUDDTYC_OADTY_SHIFT (16) +#define R_GPT_GTUDDTYC_OADTY_MASK (0x3 << R_GPT_GTUDDTYC_OADTY_SHIFT) /* GTIOCA Output Duty Setting (b17:b16) */ +# define R_GPT_GTUDDTYC_OADTY_SET0 (0 << R_GPT_GTUDDTYC_OADTY_SHIFT) /* GTIOCA pin duty depends on compare match */ +# define R_GPT_GTUDDTYC_OADTY_SET2 (2 << R_GPT_GTUDDTYC_OADTY_SHIFT) /* GTIOCA pin duty 0% */ +# define R_GPT_GTUDDTYC_OADTY_SET3 (3 << R_GPT_GTUDDTYC_OADTY_SHIFT) /* GTIOCA pin duty 100% */ +#define R_GPT_GTUDDTYC_OADTYF (1 << 18) +#define R_GPT_GTUDDTYC_OADTYR (1 << 19) +#define R_GPT_GTUDDTYC_OBDTY_SHIFT (24) +#define R_GPT_GTUDDTYC_OBDTY_MASK (0x3 << R_GPT_GTUDDTYC_OBDTY_SHIFT) /* GTIOCB Output Duty Setting (b25:b24) */ +# define R_GPT_GTUDDTYC_OBDTY_SET0 (0 << R_GPT_GTUDDTYC_OBDTY_SHIFT) /* GTIOCB pin duty depends on compare match */ +# define R_GPT_GTUDDTYC_OBDTY_SET2 (2 << R_GPT_GTUDDTYC_OBDTY_SHIFT) /* GTIOCB pin duty 0% */ +# define R_GPT_GTUDDTYC_OBDTY_SET3 (3 << R_GPT_GTUDDTYC_OBDTY_SHIFT) /* GTIOCB pin duty 100% */ +#define R_GPT_GTUDDTYC_OBDTYF (1 << 26) +#define R_GPT_GTUDDTYC_OBDTYR (1 << 27) + +/* General PWM Timer I/O Control Register (GTIOR) */ + +#define R_GPT_GTIOR_GTIOA_SHIFT (0) +#define R_GPT_GTIOR_GTIOA_MASK (0x1F << R_GPT_GTIOR_GTIOA_SHIFT) /* GTIOCA Pin Function Select (b4:b0) */ +# define R_GPT_GTIOR_GTIOA_SET6 (0x06 << R_GPT_GTIOR_GTIOA_SHIFT) /* Initial out: L; cycle end: L; compare match: H */ +# define R_GPT_GTIOR_GTIOA_SET25 (0x19 << R_GPT_GTIOR_GTIOA_SHIFT) /* Initial out: H; cycle end: H; compare match: L */ +#define R_GPT_GTIOR_OADFLT (1 << 6) /* Output value at count stop */ +#define R_GPT_GTIOR_OAHLD (1 << 7) /* Output value hold enable */ +#define R_GPT_GTIOR_OAE (1 << 8) /* GTIOCA Output Enable */ +#define R_GPT_GTIOR_OADF_SHIFT (9) +#define R_GPT_GTIOR_OADF_MASK (0x3 << R_GPT_GTIOR_OADF_SHIFT) /* Output disable source select */ +#define R_GPT_GTIOR_NFAEN (1 << 12) /* Noise filter enable */ +#define R_GPT_GTIOR_NFCSA_SHIFT (13) +#define R_GPT_GTIOR_NFCSA_MASK (0x3 << R_GPT_GTIOR_NFCSA_SHIFT) /* Noise filter clock select */ +#define R_GPT_GTIOR_GTIOB_SHIFT (16) +#define R_GPT_GTIOR_GTIOB_MASK (0x1F << R_GPT_GTIOR_GTIOB_SHIFT) +# define R_GPT_GTIOR_GTIOB_SET6 (0x06 << R_GPT_GTIOR_GTIOB_SHIFT) /* Initial out: L; cycle end: L; compare match: H */ +# define R_GPT_GTIOR_GTIOB_SET25 (0x19 << R_GPT_GTIOR_GTIOB_SHIFT) /* Initial out: H; cycle end: H; compare match: L */ +#define R_GPT_GTIOR_OBDFLT (1 << 22) +#define R_GPT_GTIOR_OBHLD (1 << 23) +#define R_GPT_GTIOR_OBE (1 << 24) +#define R_GPT_GTIOR_OBDF_SHIFT (25) +#define R_GPT_GTIOR_OBDF_MASK (0x3 << R_GPT_GTIOR_OBDF_SHIFT) +#define R_GPT_GTIOR_NFBEN (1 << 28) +#define R_GPT_GTIOR_NFCSB_SHIFT (29) +#define R_GPT_GTIOR_NFCSB_MASK (0x3 << R_GPT_GTIOR_NFCSB_SHIFT) + +/* General PWM Timer Status Register (GTST / GTSR) */ + +#define R_GPT_GTST_TCFA_SHIFT (0) +#define R_GPT_GTST_TCFA (1 << R_GPT_GTST_TCFA_SHIFT) /* Match Flag A */ + +#define R_GPT_GTST_TCFB_SHIFT (1) +#define R_GPT_GTST_TCFB (1 << R_GPT_GTST_TCFB_SHIFT) /* Match Flag B */ + +#define R_GPT_GTST_TCFC_SHIFT (2) +#define R_GPT_GTST_TCFC (1 << R_GPT_GTST_TCFC_SHIFT) /* Match Flag C */ + +#define R_GPT_GTST_TCFD_SHIFT (3) +#define R_GPT_GTST_TCFD (1 << R_GPT_GTST_TCFD_SHIFT) /* Match Flag D */ + +#define R_GPT_GTST_TCFE_SHIFT (4) +#define R_GPT_GTST_TCFE (1 << R_GPT_GTST_TCFE_SHIFT) /* Match Flag E */ + +#define R_GPT_GTST_TCFF_SHIFT (5) +#define R_GPT_GTST_TCFF (1 << R_GPT_GTST_TCFF_SHIFT) /* Match Flag F */ + +#define R_GPT_GTST_TCFPO_SHIFT (6) +#define R_GPT_GTST_TCFPO (1 << R_GPT_GTST_TCFPO_SHIFT) /* Overflow Flag */ + +#define R_GPT_GTST_TCFPU_SHIFT (7) +#define R_GPT_GTST_TCFPU (1 << R_GPT_GTST_TCFPU_SHIFT) /* Underflow Flag */ + +#define R_GPT_GTST_TUCF_SHIFT (15) +#define R_GPT_GTST_TUCF (1 << R_GPT_GTST_TUCF_SHIFT) /* Count Direction Flag */ + +#define R_GPT_GTST_ODF_SHIFT (24) +#define R_GPT_GTST_ODF (1 << R_GPT_GTST_ODF_SHIFT) /* Output Disable Flag */ + +#define R_GPT_GTST_OABHF_SHIFT (29) +#define R_GPT_GTST_OABHF (1 << R_GPT_GTST_OABHF_SHIFT) /* Output High Flag */ + +#define R_GPT_GTST_OABLF_SHIFT (30) +#define R_GPT_GTST_OABLF (1 << R_GPT_GTST_OABLF_SHIFT) /* Output Low Flag */ + +/* General PWM Timer Buffer Enable Register (GTBER) */ + +#define R_GPT_GTBER_BD0_SHIFT (0) +#define R_GPT_GTBER_BD0 (1 << R_GPT_GTBER_BD0_SHIFT) /* GTCCR Buffer Disable */ + +#define R_GPT_GTBER_BD1_SHIFT (1) +#define R_GPT_GTBER_BD1 (1 << R_GPT_GTBER_BD1_SHIFT) /* GTPR Buffer Disable */ + +#define R_GPT_GTBER_CCRA_SHIFT (16) +#define R_GPT_GTBER_CCRA_MASK (0x3 << R_GPT_GTBER_CCRA_SHIFT) + +#define R_GPT_GTBER_CCRB_SHIFT (18) +#define R_GPT_GTBER_CCRB_MASK (0x3 << R_GPT_GTBER_CCRB_SHIFT) + +#define R_GPT_GTBER_PR_SHIFT (20) +#define R_GPT_GTBER_PR_MASK (0x3 << R_GPT_GTBER_PR_SHIFT) + +#define R_GPT_GTBER_CCRSWT_SHIFT (22) +#define R_GPT_GTBER_CCRSWT (1 << R_GPT_GTBER_CCRSWT_SHIFT) + +/* General PWM Timer Control Register (GTCR) */ + +#define R_GPT_GTCR_CST (1u << 0) /* Count Start (b0) */ +#define R_GPT_GTCR_MD_SHIFT (16) +#define R_GPT_GTCR_MD_MASK (0x7u << R_GPT_GTCR_MD_SHIFT) +# define R_GPT_GTCR_MD_MOD0 (0 << R_GPT_GTCR_MD_SHIFT) /* Saw-wave PWM mode (single buffer or double buffer possible) */ +# define R_GPT_GTCR_MD_MOD1 (1 << R_GPT_GTCR_MD_SHIFT) /* Saw-wave one-shot pulse mode (fixed buffer operation) */ +#define R_GPT_GTCR_TPCS_SHIFT (24) +#define R_GPT_GTCR_TPCS_MASK (0x7u << R_GPT_GTCR_TPCS_SHIFT) +# define R_GPT_GTCR_TPCS_DIV1 (0 << R_GPT_GTCR_TPCS_SHIFT) /* PCLKD/1 */ +# define R_GPT_GTCR_TPCS_DIV4 (1 << R_GPT_GTCR_TPCS_SHIFT) /* PCLKD/4 */ +# define R_GPT_GTCR_TPCS_DIV16 (2 << R_GPT_GTCR_TPCS_SHIFT) /* PCLKD/16 */ +# define R_GPT_GTCR_TPCS_DIV64 (3 << R_GPT_GTCR_TPCS_SHIFT) /* PCLKD/64 */ +# define R_GPT_GTCR_TPCS_DIV256 (4 << R_GPT_GTCR_TPCS_SHIFT) /* PCLKD/256 */ +# define R_GPT_GTCR_TPCS_DIV1024 (5 << R_GPT_GTCR_TPCS_SHIFT) /* PCLKD/1024 */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_RA4_HARDWARE_RA_GPT_H */ diff --git a/arch/arm/src/ra4/ra_pwm.c b/arch/arm/src/ra4/ra_pwm.c new file mode 100644 index 00000000000..dce119fadbc --- /dev/null +++ b/arch/arm/src/ra4/ra_pwm.c @@ -0,0 +1,751 @@ +/**************************************************************************** + * arch/arm/src/ra4/ra_pwm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/timers/pwm.h> +#include <arch/board/board.h> + +#include "arm_internal.h" +#include "chip.h" +#include "ra_gpio.h" +#include "ra_pwm.h" +#include "hardware/ra_gpt.h" +#include "hardware/ra_mstp.h" +#include "hardware/ra_system.h" + +#ifdef CONFIG_RA_PWM + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* PWM output frequency */ +#define RA_PWM_CLOCK_FREQ RA_PCKA_FREQUENCY + +/* Number of GPT channels available on RA4M1 */ +#define RA_PWM_NUM_CHANNELS 8 + +typedef enum +{ + R_GPT16 = 0, + R_GPT32, +} ra_gpt_type_t; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure represents the state of one PWM timer */ + +struct ra_pwmtimer_s +{ + const struct pwm_ops_s *ops; /* PWM operations */ + uint8_t channel; /* Timer channel: 0-7 */ + ra_gpt_type_t gtp; /* GPT type */ + uint32_t base; /* Base address of GPT registers */ + uint32_t mstp; /* Module stop bit */ + uint32_t pclk; /* Input clock frequency */ + uint32_t frequency; /* Current frequency setting */ + uint32_t duty; /* Current duty cycle setting */ + gpio_pinset_t gtioa; /* GPIO pin configuration for GTIOA */ + gpio_pinset_t gtiob; /* GPIO pin configuration for GTIOB */ +}; + +/**************************************************************************** + * Static Function Prototypes + ****************************************************************************/ + +/* PWM driver methods */ + +static int pwm_setup(struct pwm_lowerhalf_s *dev); +static int pwm_shutdown(struct pwm_lowerhalf_s *dev); +static int pwm_start(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info); +static int pwm_stop(struct pwm_lowerhalf_s *dev); +static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd, + unsigned long arg); +#ifdef CONFIG_DEBUG_PWM_INFO +static void pwm_dumpregs(struct pwm_lowerhalf_s *dev, + const char *msg); +#else +# define pwm_dumpregs(priv,msg) +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* PWM operations */ + +static const struct pwm_ops_s g_pwmops = +{ + .setup = pwm_setup, + .shutdown = pwm_shutdown, + .start = pwm_start, + .stop = pwm_stop, + .ioctl = pwm_ioctl +}; + +#ifdef CONFIG_RA_GPT0_PWM +static struct ra_pwmtimer_s g_pwm0dev = +{ + .ops = &g_pwmops, + .channel = 0, + .gtp = R_GPT32, + .base = R_GPT0_BASE, + .mstp = R_MSTP_MSTPCRD_GPT_32, + .pclk = RA_PWM_CLOCK_FREQ, + #ifdef CONFIG_RA_GPT0_OUTPUTA + .gtioa = GPIO_GPT0_GTIOCA, + #else + .gtioa = GPIO_PIN_INVALID, + #endif + #ifdef CONFIG_RA_GPT0_OUTPUTB + .gtiob = GPIO_GPT0_GTIOCB, + #else + .gtiob = GPIO_PIN_INVALID, + #endif +}; +#endif + +#ifdef CONFIG_RA_GPT1_PWM +static struct ra_pwmtimer_s g_pwm1dev = +{ + .ops = &g_pwmops, + .channel = 1, + .gtp = R_GPT32, + .base = R_GPT1_BASE, + .mstp = R_MSTP_MSTPCRD_GPT_32, + .pclk = RA_PWM_CLOCK_FREQ, + #ifdef CONFIG_RA_GPT1_OUTPUTA + .gtioa = GPIO_GPT1_GTIOCA, + #else + .gtiob = GPIO_PIN_INVALID, + #endif + #ifdef CONFIG_RA_GPT1_OUTPUTB + .gtiob = GPIO_GPT1_GTIOCB, + #else + .gtiob = GPIO_PIN_INVALID, + #endif +}; +#endif + +#ifdef CONFIG_RA_GPT2_PWM +static struct ra_pwmtimer_s g_pwm2dev = +{ + .ops = &g_pwmops, + .channel = 2, + .gtp = R_GPT16, + .base = R_GPT2_BASE, + .mstp = R_MSTP_MSTPCRD_GPT_16, + .pclk = RA_PWM_CLOCK_FREQ, + #ifdef CONFIG_RA_GPT2_OUTPUTA + .gtioa = GPIO_GPT2_GTIOCA, + #endif + #ifdef CONFIG_RA_GPT2_OUTPUTB + .gtiob = GPIO_GPT2_GTIOCB, + #endif +}; +#endif + +#ifdef CONFIG_RA_GPT3_PWM +static struct ra_pwmtimer_s g_pwm3dev = +{ + .ops = &g_pwmops, + .channel = 3, + .gtp = R_GPT16, + .base = R_GPT3_BASE, + .mstp = R_MSTP_MSTPCRD_GPT_16, + .pclk = RA_PWM_CLOCK_FREQ, + #ifdef CONFIG_RA_GPT3_OUTPUTA + .gtioa = GPIO_GPT3_GTIOCA, + #endif + #ifdef CONFIG_RA_GPT3_OUTPUTB + .gtiob = GPIO_GPT3_GTIOCB, + #endif +}; +#endif + +#ifdef CONFIG_RA_GPT4_PWM +static struct ra_pwmtimer_s g_pwm4dev = +{ + .ops = &g_pwmops, + .channel = 4, + .gtp = R_GPT16, + .base = R_GPT4_BASE, + .mstp = R_MSTP_MSTPCRD_GPT_16, + .pclk = RA_PWM_CLOCK_FREQ, + #ifdef CONFIG_RA_GPT4_OUTPUTA + .gtioa = GPIO_GPT4_GTIOCA, + #endif + #ifdef CONFIG_RA_GPT4_OUTPUTB + .gtiob = GPIO_GPT4_GTIOCB, + #endif +}; +#endif + +#ifdef CONFIG_RA_GPT5_PWM +static struct ra_pwmtimer_s g_pwm5dev = +{ + .ops = &g_pwmops, + .channel = 5, + .gtp = R_GPT16, + .base = R_GPT5_BASE, + .mstp = R_MSTP_MSTPCRD_GPT_16, + .pclk = RA_PWM_CLOCK_FREQ, + #ifdef CONFIG_RA_GPT5_OUTPUTA + .gtioa = GPIO_GPT5_GTIOCA, + #endif + #ifdef CONFIG_RA_GPT5_OUTPUTB + .gtiob = GPIO_GPT5_GTIOCB, + #endif +}; +#endif + +#ifdef CONFIG_RA_GPT6_PWM +static struct ra_pwmtimer_s g_pwm6dev = +{ + .ops = &g_pwmops, + .channel = 6, + .gtp = R_GPT16, + .base = R_GPT6_BASE, + .mstp = R_MSTP_MSTPCRD_GPT_16, + .pclk = RA_PWM_CLOCK_FREQ, + #ifdef CONFIG_RA_GPT6_OUTPUTA + .gtioa = GPIO_GPT6_GTIOCA, + #endif + #ifdef CONFIG_RA_GPT6_OUTPUTB + .gtiob = GPIO_GPT6_GTIOCB, + #endif +}; +#endif + +#ifdef CONFIG_RA_GPT7_PWM +static struct ra_pwmtimer_s g_pwm7dev = +{ + .ops = &g_pwmops, + .channel = 7, + .base = R_GPT7_BASE, + .gtp = R_GPT16, + .mstp = R_MSTP_MSTPCRD_GPT_16, + .pclk = RA_PWM_CLOCK_FREQ, + #ifdef CONFIG_RA_GPT7_OUTPUTA + .gtioa = GPIO_GPT7_GTIOCA, + #endif + #ifdef CONFIG_RA_GPT7_OUTPUTB + .gtiob = GPIO_GPT7_GTIOCB, + #endif +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pwm_getreg + * + * Description: + * Read the value of a PWM timer register + * + * Input Parameters: + * priv - A reference to the PWM timer state structure + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ****************************************************************************/ + +static uint32_t pwm_getreg(struct ra_pwmtimer_s *priv, uint32_t offset) +{ + return getreg32(priv->base + offset); +} + +/**************************************************************************** + * Name: pwm_putreg + * + * Description: + * Write a value to a PWM timer register + * + * Input Parameters: + * priv - A reference to the PWM timer state structure + * offset - The offset to the register to write + * value - The value to write to the register + * + ****************************************************************************/ + +static void pwm_putreg(struct ra_pwmtimer_s *priv, uint32_t offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +/**************************************************************************** + * Name: pwm_dumpregs + * + * Description: + * Dump all timer registers. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_PWM_INFO +static void pwm_dumpregs(struct pwm_lowerhalf_s *dev, const char *msg) +{ + struct ra_pwmtimer_s *priv = (struct ra_pwmtimer_s *)dev; + + pwminfo("PWM: %s\n", msg); + pwminfo(" GTCR: %08x \n", + pwm_getreg(priv, R_GPT_GTCR_OFFSET)); + pwminfo(" GTIOR: %08x \n", + pwm_getreg(priv, R_GPT_GTIOR_OFFSET)); + pwminfo(" GTPR: %08x \n", + pwm_getreg(priv, R_GPT_GTPR_OFFSET)); + pwminfo(" GTCCRA: %08x \n", + pwm_getreg(priv, R_GPT_GTCCRA_OFFSET)); + pwminfo(" GTCCRB: %08x \n", + pwm_getreg(priv, R_GPT_GTCCRB_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: pwm_setup + * + * Description: + * This method is called when the driver is opened. The lower half driver + * should configure and initialize the device so that it is ready for use. + * It should not, however, output pulses until the start method is called. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_setup(struct pwm_lowerhalf_s *dev) +{ + struct ra_pwmtimer_s *priv = (struct ra_pwmtimer_s *)dev; + uint32_t regval = 0; + + /* Enable clock to the GPT module */ + + putreg16((R_SYSTEM_PRCR_PRKEY_VALUE | R_SYSTEM_PRCR_PRC1), R_SYSTEM_PRCR); + modifyreg32(R_MSTP_MSTPCRD, priv->mstp, 0); + putreg16(R_SYSTEM_PRCR_PRKEY_VALUE, R_SYSTEM_PRCR); + + /* Reset the timer */ + + pwm_putreg(priv, R_GPT_GTCR_OFFSET, 0); + + /* Configure the timer for PWM mode */ + + regval &= ~R_GPT_GTCR_CST; + regval |= R_GPT_GTCR_MD_MOD0; + pwm_putreg(priv, R_GPT_GTCR_OFFSET, regval); + + /* Set default frequency and duty cycle */ + + priv->frequency = 0; + priv->duty = 0; + + /* Configure selected PWM pins */ + + regval = pwm_getreg(priv, R_GPT_GTIOR_OFFSET); + if (priv->gtioa.port != PORT_INVALID) + { + regval &= ~R_GPT_GTIOR_GTIOA_MASK; + regval |= (R_GPT_GTIOR_GTIOA_SET25 | R_GPT_GTIOR_OAE); + ra_configgpio(priv->gtioa); + } + + if (priv->gtiob.port != PORT_INVALID) + { + regval &= ~R_GPT_GTIOR_GTIOB_MASK; + regval |= (R_GPT_GTIOR_GTIOB_SET25 | R_GPT_GTIOR_OBE); + ra_configgpio(priv->gtiob); + } + + pwm_putreg(priv, R_GPT_GTIOR_OFFSET, regval); + + pwm_dumpregs(dev, "After setup"); + return OK; +} + +/**************************************************************************** + * Name: pwm_shutdown + * + * Description: + * This method is called when the driver is closed. The lower half driver + * stop pulsed output, free any resources, disable the timer hardware, and + * put the system into the lowest possible power usage state + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_shutdown(struct pwm_lowerhalf_s *dev) +{ + struct ra_pwmtimer_s *priv = (struct ra_pwmtimer_s *)dev; + + /* Stop the timer */ + + pwm_putreg(priv, R_GPT_GTCR_OFFSET, 0); + + /* Disable the output */ + + pwm_putreg(priv, R_GPT_GTIOR_OFFSET, 0); + + /* Disable clock to the GPT module */ + + putreg16((R_SYSTEM_PRCR_PRKEY_VALUE | R_SYSTEM_PRCR_PRC1), R_SYSTEM_PRCR); + modifyreg32(R_MSTP_MSTPCRD, 0, priv->mstp); + putreg16(R_SYSTEM_PRCR_PRKEY_VALUE, R_SYSTEM_PRCR); + pwm_dumpregs(dev, "After shutdown"); + return OK; +} + +/**************************************************************************** + * Name: pwm_start + * + * Description: + * Start the pulsed output with the given frequency and duty cycle. This + * method is called after setup() when the PWM device is opened. This + * method is called after stop() when a new pulse train is started. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_start(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info) +{ + struct ra_pwmtimer_s *priv = (struct ra_pwmtimer_s *)dev; + uint32_t period; + uint32_t duty; + uint32_t regval; + uint32_t hi; + uint32_t lo; + uint32_t duty16; + + /* Calculate the period and duty cycle register values */ + + if (info->frequency == 0) + { + return -EINVAL; + } + + /* Calculate the period register value */ + + period = priv->pclk / info->frequency; + if (period < 2 || period > UINT32_MAX) + { + return -EINVAL; + } + + if (period > UINT16_MAX && priv->gtp == R_GPT16) + { + uint8_t prescaler = 0; + + /* Try to find a suitable prescaler */ + + while (prescaler < 6) + { + prescaler++; + switch (prescaler) + { + case 1: + period = priv->pclk / 4 / info->frequency; + break; + case 2: + period = priv->pclk / 16 / info->frequency; + break; + case 3: + period = priv->pclk / 64 / info->frequency; + break; + case 4: + period = priv->pclk / 256 / info->frequency; + break; + case 5: + period = priv->pclk / 1024 / info->frequency; + break; + } + + if (period <= UINT16_MAX) + { + break; + } + } + + if (prescaler == 6) + { + return -EINVAL; + } + + /* Set the prescaler */ + + regval = pwm_getreg(priv, R_GPT_GTCR_OFFSET); + regval &= ~R_GPT_GTCR_TPCS_MASK; + switch (prescaler) + { + case 1: + regval |= R_GPT_GTCR_TPCS_DIV4; + break; + case 2: + regval |= R_GPT_GTCR_TPCS_DIV16; + break; + case 3: + regval |= R_GPT_GTCR_TPCS_DIV64; + break; + case 4: + regval |= R_GPT_GTCR_TPCS_DIV256; + break; + case 5: + regval |= R_GPT_GTCR_TPCS_DIV1024; + break; + } + + pwminfo("prescaler=%" PRIu32 "\n", + regval); + pwm_putreg(priv, R_GPT_GTCR_OFFSET, regval); + } + + /* Calculate the duty cycle register value. + * info->duty is a 16-bit value (0..65535). To avoid 64-bit math we + * can split the 32-bit period into high and low 16-bit parts + */ + + hi = period >> 16; + lo = period & 0xffff; + duty16 = (uint32_t)info->duty; + + duty = hi * duty16; + + /* Add the scaled low part. Use truncating shift; add (1<<15) to round. */ + + duty += ((lo * duty16) >> 16); + + if (duty >= period) + { + duty = period - 1; + } + + /* Save the frequency and duty cycle settings */ + + priv->frequency = info->frequency; + priv->duty = info->duty; + + /* Stop the timer */ + + regval = pwm_getreg(priv, R_GPT_GTCR_OFFSET); + regval &= ~R_GPT_GTCR_CST; + pwm_putreg(priv, R_GPT_GTCR_OFFSET, regval); + + /* Set the period and duty cycle */ + + pwm_putreg(priv, R_GPT_GTPR_OFFSET, period); + regval = pwm_getreg(priv, R_GPT_GTIOR_OFFSET); + if (regval & R_GPT_GTIOR_OAE) + { + pwm_putreg(priv, R_GPT_GTCCRA_OFFSET, duty - 1); + } + + if (regval & R_GPT_GTIOR_OBE) + { + pwm_putreg(priv, R_GPT_GTCCRB_OFFSET, duty - 1); + } + + /* Start the timer */ + + regval = pwm_getreg(priv, R_GPT_GTCR_OFFSET); + regval |= R_GPT_GTCR_CST; + pwm_putreg(priv, R_GPT_GTCR_OFFSET, regval); + pwm_dumpregs(dev, "After start"); + return OK; +} + +/**************************************************************************** + * Name: pwm_stop + * + * Description: + * Stop the pulsed output and reset the timer resources. This method is + * called when the PWM device is closed. This method is also called when a + * new PWM output is started to stop the previous output before starting + * the new one. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_stop(struct pwm_lowerhalf_s *dev) +{ + struct ra_pwmtimer_s *priv = (struct ra_pwmtimer_s *)dev; + uint32_t regval; + + /* Stop the timer */ + + regval = pwm_getreg(priv, R_GPT_GTCR_OFFSET); + regval &= ~R_GPT_GTCR_CST; + pwm_putreg(priv, R_GPT_GTCR_OFFSET, regval); + pwm_dumpregs(dev, "After stop"); + return OK; +} + +/**************************************************************************** + * Name: pwm_ioctl + * + * Description: + * Lower-half logic may support platform-specific ioctl commands + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * cmd - The ioctl command + * arg - The argument accompanying the ioctl command + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd, + unsigned long arg) +{ + /* No ioctl commands supported */ + + pwm_dumpregs(dev, "After ioctl"); + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ra_pwminitialize + * + * Description: + * Initialize one PWM channel for use with the upper_level PWM driver. + * + * Input Parameters: + * channel - A number identifying the PWM channel use. + * + * Returned Value: + * On success, a pointer to the RA PWM lower half driver is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +struct pwm_lowerhalf_s *ra_pwminitialize(int channel) +{ + struct ra_pwmtimer_s *lower; + + /* Find the requested channel */ + + printf("pwminitialize passed\n"); + switch (channel) + { +#ifdef CONFIG_RA_GPT0_PWM + case 0: + lower = &g_pwm0dev; + break; +#endif + +#ifdef CONFIG_RA_GPT1_PWM + case 1: + lower = &g_pwm1dev; + break; +#endif + +#ifdef CONFIG_RA_GPT2_PWM + case 2: + lower = &g_pwm2dev; + break; +#endif + +#ifdef CONFIG_RA_GPT3_PWM + case 3: + lower = &g_pwm3dev; + break; +#endif + +#ifdef CONFIG_RA_GPT4_PWM + case 4: + lower = &g_pwm4dev; + break; +#endif + +#ifdef CONFIG_RA_GPT5_PWM + case 5: + lower = &g_pwm5dev; + break; +#endif + +#ifdef CONFIG_RA_GPT6_PWM + case 6: + lower = &g_pwm6dev; + break; +#endif + +#ifdef CONFIG_RA_GPT7_PWM + case 7: + lower = &g_pwm7dev; + break; +#endif + + default: + pwmerr("ERROR: No such PWM channel: %d\n", channel); + return NULL; + } + + return (struct pwm_lowerhalf_s *)lower; +} +#endif /* CONFIG_RA_PWM */ diff --git a/arch/arm/src/ra4/ra_pwm.h b/arch/arm/src/ra4/ra_pwm.h new file mode 100644 index 00000000000..789108263dc --- /dev/null +++ b/arch/arm/src/ra4/ra_pwm.h @@ -0,0 +1,129 @@ +/**************************************************************************** + * arch/arm/src/ra4/ra_pwm.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_RA4_RA_PWM_H +#define __ARCH_ARM_SRC_RA4_RA_PWM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include "hardware/ra_gpt.h" +#include "nuttx/timers/pwm.h" +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* This structure represents the state of one PWM timer */ + +struct ra_pwm_lowerhalf_s +{ + const struct pwm_ops_s * ops; /* PWM operations */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: ra_pwm_initialize + * + * Description: + * Initialize the selected PWM port. And return a unique instance of struct + * struct ra_pwm_lowerhalf_s. This function may be called to obtain + * multiple instances of the interface, each of which may be set up with a + * different frequency and address. + * + * Input Parameters: + * Port number (for hardware that has multiple PWM interfaces) + * GPIO pin number for pin A + * GPIO pin number for pin B (CONFIG_PWM_NCHANNELS == 2) + * + * Returned Value: + * Valid PWM device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +#if defined(CONFIG_PWM_NCHANNELS) && (CONFIG_PWM_NCHANNELS == 2) +struct ra_pwm_lowerhalf_s *ra_pwm_initialize(int port, + int pin_a, + int pin_b, + uint32_t flags); +#else +struct ra_pwm_lowerhalf_s *ra_pwm_initialize(int port, + int pin, + uint32_t flags); +#endif + +/**************************************************************************** + * Name: ra_pwmdev_uninitialize + * + * Description: + * De-initialize the selected pwm port, and power down the device. + * + * Input Parameter: + * Device structure as returned by the ra_pwmdev_initialize() + * + * Returned Value: + * OK on success, ERROR when internal reference count mismatch or dev + * points to invalid hardware device. + * + ****************************************************************************/ + +int ra_pwm_uninitialize(struct pwm_lowerhalf_s *dev); + +/**************************************************************************** + * Name: ra_pwminitialize + * + * Description: + * Initialize one PWM channel for use with the upper_level PWM driver. + * + * Input Parameters: + * channel - A number identifying the PWM channel use. + * + * Returned Value: + * On success, a pointer to the RA PWM lower half driver is returned. + * NULL is returned on any failure. + * + ****************************************************************************/ + +struct pwm_lowerhalf_s *ra_pwminitialize(int channel); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_RA4_RA_PWM_H */
