diff --git a/arch/arm/src/samv7/Kconfig b/arch/arm/src/samv7/Kconfig index a467b478493..5e81a095b4f 100644 --- a/arch/arm/src/samv7/Kconfig +++ b/arch/arm/src/samv7/Kconfig @@ -309,6 +309,11 @@ config SAMV7_HAVE_MEDIALB bool default n +config SAMV7_PWM + bool + default n + select ARCH_HAVE_PWM_MULTICHAN + config SAMV7_HAVE_SDRAMC bool default n @@ -593,14 +598,60 @@ config SAMV7_MLB default n depends on SAMV7_HAVE_MEDIALB -config SAMV7_PWM0 +menuconfig SAMV7_PWM0 bool "Pulse Width Modulation Controller 0 (PWM0)" default n + select SAMV7_PWM + ---help--- + Support for PWM0 controller -config SAMV7_PWM1 - bool "Pulse Width Modulation Controller 0 (PWM1)" +if SAMV7_PWM0 + +config SAMV7_PWM0_CH0 + bool "PWM0 Channel 0" default n +config SAMV7_PWM0_CH1 + bool "PWM0 Channel 1" + default n + +config SAMV7_PWM0_CH2 + bool "PWM0 Channel 2" + default n + +config SAMV7_PWM0_CH3 + bool "PWM0 Channel 3" + default n + +endif + +menuconfig SAMV7_PWM1 + bool "Pulse Width Modulation Controller 1 (PWM1)" + default n + select SAMV7_PWM + ---help--- + Support for PWM1 controller + +if SAMV7_PWM1 + +config SAMV7_PWM1_CH0 + bool "PWM1 Channel 0" + default n + +config SAMV7_PWM1_CH1 + bool "PWM1 Channel 1" + default n + +config SAMV7_PWM1_CH2 + bool "PWM1 Channel 2" + default n + +config SAMV7_PWM1_CH3 + bool "PWM1 Channel 3" + default n + +endif + config SAMV7_QSPI bool "Quad SPI (QSPI)" default n diff --git a/arch/arm/src/samv7/Make.defs b/arch/arm/src/samv7/Make.defs index 57532d576df..85a7b59c9b6 100644 --- a/arch/arm/src/samv7/Make.defs +++ b/arch/arm/src/samv7/Make.defs @@ -185,6 +185,10 @@ ifeq ($(CONFIG_SAMV7_PROGMEM),y) CHIP_CSRCS += sam_progmem.c sam_eefc.c endif +ifeq ($(CONFIG_SAMV7_PWM),y) +CHIP_CSRCS += sam_pwm.c +endif + ifeq ($(CONFIG_SAMV7_DAC),y) CHIP_CSRCS += sam_dac.c endif diff --git a/arch/arm/src/samv7/hardware/sam_pwm.h b/arch/arm/src/samv7/hardware/sam_pwm.h new file mode 100644 index 00000000000..fc95e79dfcb --- /dev/null +++ b/arch/arm/src/samv7/hardware/sam_pwm.h @@ -0,0 +1,466 @@ +/**************************************************************************** + * arch/arm/src/samv7/hardware/sam_pwm.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_SAMV7_HARDWARE_SAM_FLEXPWM_H +#define __ARCH_ARM_SRC_SAMV7_HARDWARE_SAM_FLEXPWM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/sam_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define SAMV7_PWM_CLK 0x0000 /* Clock Register */ +#define SAMV7_PWM_ENA 0x0004 /* Enable Register */ +#define SAMV7_PWM_DIS 0x0008 /* Disable register */ +#define SAMV7_PWM_SR 0x000c /* Status Register */ +#define SAMV7_PWM_IER1 0x0010 /* Interrupt Enable Register 1 */ +#define SAMV7_PWM_IDR1 0x0014 /* Interrupt Disable Register 1 */ +#define SAMV7_PWM_IMR1 0x0018 /* Interrupt Mask Register 1 */ +#define SAMV7_PWM_ISR1 0x001c /* Interrupt Status Register 1 */ +#define SAMV7_PWM_SCM 0x0020 /* Sync Channels Mode Register */ +#define SAMV7_PWM_DMAR 0x0024 /* DMA register */ +#define SAMV7_PWM_SCUC 0x0028 /* Sync Channels Update Control Register */ +#define SAMV7_PWM_SCUP 0x002c /* Sync Channels Update Period Register */ +#define SAMV7_PWM_SCUPUPDF 0x0030 /* Sync Channels Update Period Update Register */ +#define SAMV7_PWM_IER2 0x0034 /* Interrupt Enable Register 2 */ +#define SAMV7_PWM_IDR2 0x0038 /* Interrupt Disable Register 2 */ +#define SAMV7_PWM_IMR2 0x003c /* Interrupt Mask Register 2 */ +#define SAMV7_PWM_ISR2 0x0040 /* Interrupt Status Register 2 */ +#define SAMV7_PWM_OOV 0x0044 /* Output Override Value Register */ +#define SAMV7_PWM_OS 0x0048 /* Output Selection Register */ +#define SAMV7_PWM_OSS 0x004c /* Output Selection Set Register */ +#define SAMV7_PWM_OSC 0x0050 /* Output Selection Clear Register */ +#define SAMV7_PWM_OSSUPD 0x0054 /* Output Selection Set Update Register */ +#define SAMV7_PWM_OSCUPD 0x0058 /* Output Selection Clear Update Register */ +#define SAMV7_PWM_FMR 0x005c /* Fault Mode Register */ +#define SAMV7_PWM_FSR 0x0060 /* Fault Status Register */ +#define SAMV7_PWM_FCR 0x0064 /* Fault Clear Register */ +#define SAMV7_PWM_FPV1 0x0068 /* Fault Protection Value Register 1 */ +#define SAMV7_PWM_FPE 0x006c /* Fault Protection Enable Register */ +#define SAMV7_PWM_ELMR1 0x007c /* Event Line 1 Mode Register */ +#define SAMV7_PWM_ELMR2 0x0080 /* Event Line 2 Mode Register */ +#define SAMV7_PWM_SSPR 0x00a0 /* Spread Spectrum Register */ +#define SAMV7_PWM_SSPRUP 0x00a4 /* Spread Spectrum Update Register */ +#define SAMV7_PWM_SMMR 0x00b0 /* Stepper Motor Mode Register */ +#define SAMV7_PWM_FPV2 0x00c0 /* Fault Protection Value Register 2 */ +#define SAMV7_PWM_WPCR 0x00e4 /* Write Protection Control Register */ +#define SAMV7_PWM_WPSR 0x00e8 /* Write Protection Status Register */ +#define SAMV7_PWM_CMPVX 0x0130 /* Comparison x Value Register */ +#define SAMV7_PWM_CMPVUPDX 0x0134 /* Comparison x Value Update Register */ +#define SAMV7_PWM_CMPMX 0x0138 /* Comparison x Mode Register */ +#define SAMV7_PWM_CMPMUPDX 0x013c /* Comparison x Mode Update Register */ +#define SAMV7_PWM_CMRX 0x0200 /* Channel x Mode Register */ +#define SAMV7_PWM_CDTYX 0x0204 /* Channel x Duty Cycle Register */ +#define SAMV7_PWM_CDTYUPDX 0x0208 /* Channel x Duty Cycle Update Register */ +#define SAMV7_PWM_CPRDX 0x020c /* Channel x Period Register */ +#define SAMV7_PWM_CPRDUPDX 0x0210 /* Channel x Period Update Register */ +#define SAMV7_PWM_CCNTX 0x0214 /* Channel x Counter Register */ +#define SAMV7_PWM_DTX 0x0218 /* Channel x Dead Time Register */ +#define SAMV7_PWM_DTUPDX 0x021c /* Channel x Dead Time Update Register */ +#define SAMV7_PWM_CMUPDX 0x0400 /* Channel x Mode Update Register */ +#define SAMV7_PWM_ETRG1 0x042c /* External Trigger 1 Register */ +#define SAMV7_PWM_LEBR1 0x0430 /* Leading-Edge Blanking 1 Register */ +#define SAMV7_PWM_ETRG2 0x044c /* External Trigger 2 Register */ +#define SAMV7_PWM_LEBR2 0x0450 /* Leading-Edge Blanking 2 Register */ + +/* Register Bit Definitions *************************************************/ + +/* Clock Register */ + +#define CLK_DIVA_SHIFT (0) /* Bits: 0-7 CLKA Divide Factor */ +#define CLK_DIVA_MASK (0xff << CLK_DIVA_SHIFT) +# define CLK_DIVA_SEL(n) ((uint32_t)(n) << CLK_DIVA_SHIFT) +# define CLK_DIVA_CLKA_POFF (0 << CLK_DIVA_SHIFT) /* CLKA clock is trned off */ +# define CLK_DIVA_PREA (1 << CLK_DIVA_SHIFT) /* CLKA clock is selected by PREA */ + +#define CLK_PREA_SHIFT (8) /* Bits: 8-11 CLKA Souce Clock Selection */ +#define CLK_PREA_MASK (0x7 << CLK_PREA_SHIFT) +# define CLK_PREA_SEL(n) ((uint32_t)(n) << CLK_PREA_SHIFT) +# define CLK_PREA_CLK (0 << CLK_PREA_SHIFT) /* Peripheral Clock */ +# define CLK_PREA_CLK_DIV2 (1 << CLK_PREA_SHIFT) /* Peripheral Clock/2 */ +# define CLK_PREA_CLK_DIV4 (2 << CLK_PREA_SHIFT) /* Peripheral Clock/4 */ +# define CLK_PREA_CLK_DIV8 (3 << CLK_PREA_SHIFT) /* Peripheral Clock/8 */ +# define CLK_PREA_CLK_DIV16 (4 << CLK_PREA_SHIFT) /* Peripheral Clock/16 */ +# define CLK_PREA_CLK_DIV32 (5 << CLK_PREA_SHIFT) /* Peripheral Clock/32 */ +# define CLK_PREA_CLK_DIV64 (6 << CLK_PREA_SHIFT) /* Peripheral Clock/64 */ +# define CLK_PREA_CLK_DIV128 (7 << CLK_PREA_SHIFT) /* Peripheral Clock/128 */ +# define CLK_PREA_CLK_DIV256 (8 << CLK_PREA_SHIFT) /* Peripheral Clock/256 */ +# define CLK_PREA_CLK_DIV512 (9 << CLK_PREA_SHIFT) /* Peripheral Clock/512 */ +# define CLK_PREA_CLK_DIV1024 (10 << CLK_PREA_SHIFT) /* Peripheral Clock/1024 */ + +#define CLK_DIVB_SHIFT (16) /* Bits: 16-23 CLKB Divide Factor */ +#define CLK_DIVB_MASK (0xff << CLK_DIVB_SHIFT) +# define CLK_DIVB_SEL(n) ((uint32_t)(n) << CLK_DIVB_SHIFT) +# define CLK_DIVB_CLKB_POFF (0 << CLK_DIVB_SHIFT) /* CLKB clock is trned off */ +# define CLK_DIVB_PREB (1 << CLK_DIVB_SHIFT) /* CLKB clock is selected by PREB */ + +#define CLK_PREB_SHIFT (24) /* Bits: 24-27 CLKA Souce Clock Selection */ +#define CLK_PREB_MASK (0x7 << CLK_PREB_SHIFT) +# define CLK_PREB_CLK (0 << CLK_PREB_SHIFT) /* Peripheral Clock */ +# define CLK_PREB_CLK_DIV2 (1 << CLK_PREB_SHIFT) /* Peripheral Clock/2 */ +# define CLK_PREB_CLK_DIV4 (2 << CLK_PREB_SHIFT) /* Peripheral Clock/4 */ +# define CLK_PREB_CLK_DIV8 (3 << CLK_PREB_SHIFT) /* Peripheral Clock/8 */ +# define CLK_PREB_CLK_DIV16 (4 << CLK_PREB_SHIFT) /* Peripheral Clock/16 */ +# define CLK_PREB_CLK_DIV32 (5 << CLK_PREB_SHIFT) /* Peripheral Clock/32 */ +# define CLK_PREB_CLK_DIV64 (6 << CLK_PREB_SHIFT) /* Peripheral Clock/64 */ +# define CLK_PREB_CLK_DIV128 (7 << CLK_PREB_SHIFT) /* Peripheral Clock/128 */ +# define CLK_PREB_CLK_DIV256 (8 << CLK_PREB_SHIFT) /* Peripheral Clock/256 */ +# define CLK_PREB_CLK_DIV512 (9 << CLK_PREB_SHIFT) /* Peripheral Clock/512 */ +# define CLK_PREB_CLK_DIV1024 (10 << CLK_PREB_SHIFT) /* Peripheral Clock/1024 */ + /* Bits: 27-31 Reserver */ + +/* Enable/Disable/Status Register */ + +#define CHID_SHIFT (0) /* Bits: 0-3 Channel ID Enable */ +#define CHID_MASK (0xf << CHID_SHIFT) +# define CHID_SEL(n) ((uint32_t)(n) << CHID_SHIFT) + /* Bits 4-31 Reserved */ + +/* Interrupt Enable/Disable/Mask/Stats Register 1 */ + +#define IR1_CHID_SHIFT (0) /* Bits: 0-3 Counter Event on Channel x */ +#define IR1_CHID_MASK (0xf << IR1_CHID_SHIFT) +# define IR1_CHID_SEL(n) ((uint32_t)(n) << IR1_CHID_SHIFT) + /* Bits 4-15 Reserved */ +#define IR1_FCHID_SHIFT (16) /* Bits: 16-19 Fault Protection Trigger */ +#define IR1_FCHID_MASK (0xf << IR1_FCHID_SHIFT) +# define IR1_FCHID_SEL(n) ((uint32_t)(n) << IR1_FCHID_SHIFT) + /* Bits 20-31 Reserved */ + +/* Sync Channels Mode Register */ + +#define SCM_SYNC_SHIFT (0) /* Bits: 0-3 Synchronous Channel x */ +#define SCM_SYNC_MASK (0xf << SCM_SYNC_SHIFT) +# define SCM_SYNC_SEL(n) ((uint32_t)(n) << SCM_SYNC_SHIFT) + /* Bits 4-15 Reserved */ +#define SCM_UPDM_SHIFT (16) /* Synchronous Channels Update Mode */ +#define SCM_UPDM_MASK (0x3 << SCM_UPDM_SHIFT) +# define SCM_UPDM_SEL(n) ((uint32_t)(n) << SCM_UPDM_SHIFT) +# define SCM_UPDM_MODE0 (0 << SCM_UPDM_SHIFT) +# define SCM_UPDM_MODE1 (1 << SCM_UPDM_SHIFT) +# define SCM_UPDM_MODE2 (2 << SCM_UPDM_SHIFT) +#define SCM_PTRM (1 << 20) /* Bit: 20 DMA Controller Transfer Request Mode */ +#define SCM_PTRCS_SHIFT (21) /* Bits: 21-23 DMA Controller Transfer Request Comp Sel x */ +#define SCM_PTRCS_MASK (0x7 << SCM_PTRCS_SHIFT) +# define SCM_PTRCS_SEL(n) ((uint32_t)(n) << SCM_PTRCS_SHIFT) + +/* DMA Register */ + +#define DMAR_DMADUTY_SHIFT (0) /* Bits: 0-23 Duty Cycle Holding Register */ +#define DMAR_DMADUTY_MAS (0xfffff << DMAR_DMADUTY_SHIFT) +# define DMAR_DMADUTY_SEL(n) ((uint32_t)(n) << DMAR_DMADUTY_SHIFT) + +/* Sync Channels Update Control Register */ + +#define SCUC_UPDULOCK (1 << 0) /* Bit 0: Synchronous Channels Update Unlock */ + +/* Sync Channels Update Period Register */ + +#define SCUP_UPR_SHIFT (0) /* Bits: 0-3 Update Period */ +#define SCUP_UPR_MASK (0xf << SCUP_UPR_SHIFT) +# define SCUP_UPR_SEL(n) ((uint32_t)(n) << SCUP_UPR_SHIFT) +#define SCUP_UPRCNT_SHIFT (4) /* Bits: 4-7 Update Period */ +#define SCUP_UPRCNT_MASK (0xf << SCUP_UPRCNT_SHIFT) +# define SCUP_UPRCNT_SEL(n) ((uint32_t)(n) << SCUP_UPRCNT_SHIFT) + +/* Sync Channels Update Period Update Register */ + +#define SCUPUPD_UPRUPD_SHIFT (0) /* Bits: 0-3 Update Period Update */ +#define SCUPUPD_UPRUPD_MASK (0xf << SCUPUPD_UPRUPD_SHIFT) +# define SCUPUPD_UPRUPD_SEL(n) ((uint32_t)(n) << SCUPUPD_UPRUPD_SHIFT) + +/* Interrupt Enable/Disable/Mask/Status Register 2 */ + +#define IR2_WRDY (1 << 0) /* Bit 0: Write Ready */ +#define IR2_UNRE (1 << 3) /* Bit 3: Underrun Error */ +#define IR2_CMPM_SHIFT (8) /* Bits: 8-15: Comparison x Match */ +#define IR2_CMPM_MASK (0xff << IR2_CMPM_SHIFT) +# define IR2_CMPM_SEL(n) ((uint32_t)(n) << IR2_CMPM_SHIFT) +#define IR2_CMPU_SHIFT (16) /* Bits: 16-23: Comparison x Update */ +#define IR2_CMPU_MASK (0xff << IR2_CMPU_SHIFT) +# define IR2_CMPU_SEL(n) ((uint32_t)(n) << IR2_CMPU_SHIFT) + +/* Output Register */ + +#define OR_OH_SHIFT (0) /* Bits: 0-4 Value for PWMH Output */ +#define OR_OH_MASK (0xf << OR_OH_SHIFT) +# define OR_OH_SEL(n) ((uint32_t)(n) << OR_OH_SHIFT) +#define OR_OL_SHIFT (16) /* Bits: 16-19 Value for PWML Output */ +#define OR_OL_MASK (0xf << OR_OL_SHIFT) +# define OR_OL_SEL(n) ((uint32_t)(n) << OR_OL_SHIFT) + +/* Fault Mode Register */ + +#define FMR_FPOL_SHIFT (0) /* Bits: 0-7 Fault Polarity */ +#define FMR_FPOL_MASK (0xff << FMR_FPOL_SHIFT) +# define FMR_FPOL_SEL(n) ((uint32_t)(n) << FMR_FPOL_SHIFT) +#define FMR_FMOD_SHIFT (8) /* Bits: 8-15 Fault Activation Mode */ +#define FMR_FMOD_MASK (0xff << FMR_FMOD_SHIFT) +# define FMR_FMOD_SEL(n) ((uint32_t)(n) << FMR_FMOD_SHIFT) +#define FMR_FFIL_SHIFT (16) /* Bits: 16-23 Fault Filtering */ +#define FMR_FFIL_MASK (0xff << FMR_FFIL_SHIFT) +# define FMR_FFIL_SEL(n) ((uint32_t)(n) << FMR_FFIL_SHIFT) + +/* Fault Status Register */ + +#define FSR_FIV_SHIFT (0) /* Bits: 0-7 Fault Input Value */ +#define FSR_FIV_MASK (0xff << FSR_FIV_SHIFT) +# define FSR_FIV_SEL(n) ((uint32_t)(n) << FSR_FIV_SHIFT) +#define FSR_FS_SHIFT (8) /* Bits: 8-15 Fault Status */ +#define FSR_FS_MASK (0xff << FSR_FS_SHIFT) +# define FSR_FS_SEL(n) ((uint32_t)(n) << FSR_FS_SHIFT) + +/* Fault Clear Register */ + +#define FCR_FCLR_SHIFT (0) /* Bits: 0-7 Fault Clear */ +#define FCR_FCLR_MASK (0xff << FCR_FCLR_SHIFT) +# define FCR_FCLR_SEL(n) ((uint32_t)(n) << FCR_FCLR_SHIFT) + +/* Fault Protection Value Register 1 */ + +#define FPV1_FPVH_SHIFT (0) /* Bits: 0-3 Fault Protection for PWMH */ +#define FPV1_FPVH_MASK (0xf << FPV1_FPVH_SHIFT) +# define FPV1_FPVH_SEL(n) ((uint32_t)(n) << FPV1_FPVH_SHIFT) +#define FPV1_FPVL_SHIFT (16) /* Bits: 16-20 Fault Protection for PWML */ +#define FPV1_FPVL_MASK (0xf << FPV1_FPVL_SHIFT) +# define FPV1_FPVL_SEL(n) ((uint32_t)(n) << FPV1_FPVL_SHIFT) + +/* Fault Protection Enable Register */ + +#define FPE_FPE0_SHIFT (0) /* Bits: 0-7 Fault Protection for channel 0 */ +#define FPE_FPE0_MASK (0xff << FPE_FPE0_SHIFT) +# define FPE_FPE0_SEL(n) ((uint32_t)(n) << FPE_FPE0_SHIFT) +#define FPE_FPE1_SHIFT (8) /* Bits: 8-15 Fault Protection for channel 1 */ +#define FPE_FPE1_MASK (0xff << FPE_FPE1_SHIFT) +# define FPE_FPE1_SEL(n) ((uint32_t)(n) << FPE_FPE1_SHIFT) +#define FPE_FPE2_SHIFT (16) /* Bits: 16-23 Fault Protection for channel 2 */ +#define FPE_FPE2_MASK (0xff << FPE_FPE2_SHIFT) +# define FPE_FPE2_SEL(n) ((uint32_t)(n) << FPE_FPE2_SHIFT) +#define FPE_FPE3_SHIFT (24) /* Bits: 24-31 Fault Protection for channel 3 */ +#define FPE_FPE3_MASK (0xff << FPE_FPE3_SHIFT) +# define FPE_FPE3_SEL(n) ((uint32_t)(n) << FPE_FPE3_SHIFT) + +/* Event Line Mode Register */ + +#define ELMR_CSEL_SHIFT (0) /* Bits: 0-7 Comparision Selecrion */ +#define ELMR_CSEL_MASK (0xff << ELMR_CSEL_SHIFT) +# define ELMR_CSEL_SEL(n) ((uint32_t)(n) << ELMR_CSEL_SHIFT) + +/* Spread Spectrum Register */ + +#define SSPR_SPRD_SHIFT (0) /* Bits: 0-23 Spread Spectrum Limit Value */ +#define SSPR_SPRD_MASK (0xffff << SSPR_SPRD_SHIFT) +# define SSPR_SPRD_SEL(n) ((uint32_t)(n) << SSPR_SPRD_SHIFT) +#define SSPR_SPRDM (1 << 24) /* Bit 24: Spread Spectrum Counter Mode */ + +/* Spread Spectrum Update Register */ + +#define SSPUP_SPRDUP_SHIFT (0) /* Bits: 0-23 Spread Spectrum Limit Value Update */ +#define SSPUP_SPRDUP_MASK (0xffff << SSPUP_SPRDUP_SHIFT) +# define SSPUP_SPRDUP_SEL(n) ((uint32_t)(n) << SSPUP_SPRDUP_SHIFT) + +/* Stepper Motor Mode Register */ + +#define SMMR_GCEN0 (1 << 0) /* Bit 0: Enable gray count generation */ +#define SMMR_GCEN1 (1 << 1) /* Bit 1: Enable gray count generation */ +#define SMMR_DOWN0 (1 << 16) /* Bit 16: Down counter */ +#define SMMR_DOWN1 (1 << 17) /* Bit 17: Down counter */ + +/* Fault Protection Value Register 2 */ + +#define FPV2_FPZH_SHIFT (0) /* Bits: 0-3 Fault Protection for PWMH */ +#define FPV2_FPZH_MASK (0xf << FPV2_FPZH_SHIFT) +# define FPV2_FPZH_SEL(n) ((uint32_t)(n) << FPV2_FPZH_SHIFT) +#define FPV2_FPZL_SHIFT (16) /* Bits: 16-20 Fault Protection for PWML */ +#define FPV2_FPZL_MASK (0xf << FPV2_FPZL_SHIFT) +# define FPV2_FPZL_SEL(n) ((uint32_t)(n) << FPV2_FPZL_SHIFT) + +/* Write Protection Control Register */ + +#define WPCR_WPRCMD_SHIFT (0) /* Bits 0-1: Write Protection Command */ +#define WPCR_WPRCMD_MASK (0x3 << WPCR_WPRCMD_SHIFT) +# define WPCR_WPRCMD_SEL(n) ((uint32_t)(n) << WPCR_WPRCMD_SHIFT) +#define WPCR_WPRG_SHIFT (2) /* Bits 2-7: Write Protection Register Group */ +#define WPCR_WPRG_MASK (0x3f << WPCR_WPRG_SHIFT) +# define WPCR_WPRG_SEL(n) ((uint32_t)(n) << WPCR_WPRG_SHIFT) +#define WPCR_WPKEY_SHIFT (8) /* Bits 8-31: Write Protection Key */ +#define WPCR_WPKEY_MASK (0xfff << WPCR_WPKEY_SHIFT) +# define WPCR_WPKEY_SEL(n) ((uint32_t)(n) << WPCR_WPKEY_SHIFT) + +/* Write Protection Status Register */ + +#define WPSR_WPSWS_SHIFT (0) /* Bits 0-5: Write Protection SW status */ +#define WPSR_WPSWS_MASK (0x3f << WPSR_WPSWS_SHIFT) +# define WPSR_WPSWS_SEL(n) ((uint32_t)(n) << WPSR_WPSWS_SHIFT) +#define WPSR_WPVS (1 << 7) /* Bit 7: Write Protection Violation Status */ +#define WPSR_WPHWS_SHIFT (8) /* Bits 8-13: Write Protection HW status */ +#define WPSR_WPHWS_MASK (0x3f << WPSR_WPHWS_SHIFT) +# define WPSR_WPHWS_SEL(n) ((uint32_t)(n) << WPSR_WPHWS_SHIFT) +#define WPSR_WPVSRC_SHIFT (16) /* Bits 16-31: Write Violation Source */ +#define WPSR_WPVSRC_MASK (0x3f << WPSR_WPVSRC_SHIFT) +# define WPSR_WPVSRC_SEL(n) ((uint32_t)(n) << WPSR_WPVSRC_SHIFT) + +/* Comparison Value Register */ + +#define CMPV_CV_SHIFT (0) /* Bits 0-23: Comparison Value */ +#define CMPV_CV_MASK (0xfff << CMPV_CV_SHIFT) +# define CMPV_CV_SEL(n) ((uint32_t)(n) << CMPV_CV_SHIFT) +#define CMPV_CVM (1 << 24) /* Bit 24: Comparison Value Mode */ + +/* Comparison Value Update Register */ + +#define CMPVUPD_CVUPD_SHIFT (0) /* Bits 0-23: Comparison Value Update */ +#define CMPVUPD_CVUPD_MASK (0xfff << CMPVUPD_CVUPD_SHIFT) +# define CMPVUPD_CV_SEL(n) ((uint32_t)(n) << CMPVUPD_CVUPD_SHIFT) +#define CMPVUPD_CVMUPD (1 << 24) /* Bit 24: Comparison Value Mode Update */ + +/* Comparison Mode Register */ + +#define CMPM_CEN (1 << 0) /* Bit 0: Comparison Enable */ +#define CMPM_CTR_SHIFT (4) /* Bits 4-7: Comparison Trigger */ +#define CMPM_CTR_MASK (0xf << CMPM_CTR_SHIFT) +# define CMPM_CTR_SEL(n) ((uint32_t)(n) << CMPM_CTR_SHIFT) +#define CMPM_CPR_SHIFT (8) /* Bits 8-11: Comparison Period */ +#define CMPM_CPR_MASK (0xf << CMPM_CPR_SHIFT) +# define CMPM_CPR_SEL(n) ((uint32_t)(n) << CMPM_CPR_SHIFT) +#define CMPM_CPRCNT_SHIFT (12) /* Bits 12-15: Comparison Period Counter*/ +#define CMPM_CPRCNT_MASK (0xf << CMPM_CPRCNT_SHIFT) +# define CMPM_CPRCNT_SEL(n) ((uint32_t)(n) << CMPM_CPRCNT_SHIFT) +#define CMPM_CUPR_SHIFT (16) /* Bits 16-19: Comparison Update Period */ +#define CMPM_CUPR_MASK (0xf << CMPM_CUPR_SHIFT) +# define CMPM_CUPR_SEL(n) ((uint32_t)(n) << CMPM_CUPR_SHIFT) +#define CMPM_CUPRCNT_SHIFT (20) /* Bits 20-23: Comparison Update Period Counter */ +#define CMPM_CUPRCNT_MASK (0xf << CMPM_CUPRCNT_SHIFT) +# define CMPM_CUPRCNT_SEL(n) ((uint32_t)(n) << CMPM_CUPRCNT_SHIFT) + +/* Comparison Mode Update Register */ + +#define CMPM_CENUPD (1 << 0) /* Bit 0: Comparison Enable Unable */ +#define CMPM_CTRUPD_SHIFT (4) /* Bits 4-7: Comparison Trigger Update */ +#define CMPM_CTRUPD_MASK (0xf << CMPM_CTRUPD_SHIFT) +# define CMPM_CTRUPD_SEL(n) ((uint32_t)(n) << CMPM_CTRUPD_SHIFT) +#define CMPM_CPRUPD_SHIFT (8) /* Bits 8-11: Comparison Period Update */ +#define CMPM_CPRUPD_MASK (0xf << CMPM_CPRUPD_SHIFT) +# define CMPM_CPRUPD_SEL(n) ((uint32_t)(n) << CMPM_CPRUPD_SHIFT) +#define CMPM_CUPRUPD_SHIFT (16) /* Bits 16-19: Comparison Update Period Update */ +#define CMPM_CUPRUPD_MASK (0xf << CMPM_CUPRUPD_SHIFT) +# define CMPM_CUPRUPD_SEL(n) ((uint32_t)(n) << CMPM_CUPRUPD_SHIFT) + +/* Channel Mode Register */ + +#define CMR_CPRE_SHIFT (0) /* Bits 0-3: Channel Prescaler */ +#define CMR_CPRE_MASK (0xf << CMR_CPRE_SHIFT) +# define CMR_CPRE_SEL(n) ((uint32_t)(n) << CMR_CPRE_SHIFT) +#define CMR_CALG (1 << 8) /* Bit 8: Channel Alignment */ +#define CMR_CPOL (1 << 9) /* Bit 9: Channel Polarity */ +#define CMR_CES (1 << 10) /* Bit 10: Counter Event Selection */ +#define CMR_UPDS (1 << 11) /* Bit 11: Update Selection */ +#define CMR_DPOLI (1 << 12) /* Bit 12: Disable Polarity Inverted */ +#define CMR_TCTS (1 << 13) /* Bit 13: Timer Counter Trigger Selection */ +#define CMR_DTE (1 << 16) /* Bit 16: Dead Time Generaton Enable */ +#define CMR_DTHI (1 << 17) /* Bit 17: Dead Time PWMH output Inverted */ +#define CMR_DTLI (1 << 18) /* Bit 18: Dead Time PWML output Inverted */ +#define CMR_PPM (1 << 19) /* Bit 19: Push Pull Mode */ + +/* Channel Duty Cycle Register */ + +#define CDTY_CDTY_SHIFT (0) /* Bits: 0-23 Duty Cycle */ +#define CDTY_CDTY_MASK (0xffff << CDTY_CDTY_SHIFT) +# define CDTY_CDTY_SEL(n) ((uint32_t)(n) << CDTY_CDTY_SHIFT) + +/* Channel Duty Cycle Update Register */ + +#define CDTYUPD_CDTYUPD_SHIFT (0) /* Bits: 0-23 Duty Cycle Update */ +#define CDTYUPD_CDTYUPD_MASK (0xffff << CDTYUPD_CDTYUPD_SHIFT) +# define CDTYUPD_CDTYUPD_SEL(n) ((uint32_t)(n) << CDTYUPD_CDTYUPD_SHIFT) + +/* Channel Period Register */ + +#define CPRD_CPRD_SHIFT (0) /* Bits: 0-23 Channel Period */ +#define CPRD_CPRD_MASK (0xffff << CPRD_CPRD_SHIFT) +# define CPRD_CPRD_SEL(n) ((uint32_t)(n) << CPRD_CPRD_SHIFT) + +/* Channel Period Update Register */ + +#define CPRDUPD_CPRDUPD_SHIFT (0) /* Bits: 0-23 Channel Period Update */ +#define CPRDUPD_CPRDUPD_MASK (0xffff << CPRDUPD_CPRDUPD_SHIFT) +# define CPRDUPD_CPRDUPD_SEL(n) ((uint32_t)(n) << CPRDUPD_CPRDUPD_SHIFT) + +/* Channel Counter Register */ + +#define CCNT_CNT_SHIFT (0) /* Bits: 0-23 Channel Counter */ +#define CCNT_CNT_MASK (0xffff << CCNT_CNT_SHIFT) +# define CCNT_CNT_SEL(n) ((uint32_t)(n) << CCNT_CNT_SHIFT) + +/* Channel Dead Time Register */ + +#define DT_DTH_SHIFT (0) /* Bits: 0-15 Dead Time for PWMH */ +#define DT_DTH_MASK (0xff << DT_DTH_SHIFT) +# define DT_DTH_SEL(n) ((uint32_t)(n) << DT_DTH_SHIFT) +#define DT_DTL_SHIFT (16) /* Bits: 16-31 Dead Time for PWML */ +#define DT_DTL_MASK (0xff << DT_DTL_SHIFT) +# define DT_DTL_SEL(n) ((uint32_t)(n) << DT_DTL_SHIFT) + +/* Channel Dead Time Update Register */ + +#define DTUPD_DTHUPD_SHIFT (0) /* Bits: 0-15 Dead Time Update for PWMH */ +#define DTUPD_DTHUPD_MASK (0xff << DTUPD_DTHUPD_SHIFT) +# define DTUPD_DTHUPD_SEL(n) ((uint32_t)(n) << DTUPD_DTHUPD_SHIFT) +#define DTUPD_DTLUPD_SHIFT (16) /* Bits: 16-31 Dead Time Update for PWML */ +#define DTUPD_DTLUPD_MASK (0xff << DTUPD_DTLUPD_SHIFT) +# define DTUPD_DTLUPD_SEL(n) ((uint32_t)(n) << DTUPD_DTLUPD_SHIFT) + +/* Channel Mode Update Register */ + +#define CMUPD_CPOLUP (1 << 9) /* Bit 9: Channel Polarity Update */ +#define CMUPD_CPOLINVUP (1 << 13) /* Bit 9: Channel Polarity Inversion Update */ + +/* External Trigger Register */ + +#define ETRG_MAXCNT_SHIFT (0) /* Bits: 0-23 Maximum Counter Value */ +#define ETRG_MAXCNT_MASK (0xffff << ETRG_MAXCNT_SHIFT) +# define ETRG_MAXCNT_SEL(n) ((uint32_t)(n) << ETRG_MAXCNT_SHIFT) +#define ETRG_TRGMODE_SHIFT (24) /* Bits: 24-25 External Trigger Mode */ +#define ETRG_TRGMODE_MASK (0xffff << ETRG_TRGMODE_SHIFT) +# define ETRG_TRGMODE_SEL(n) ((uint32_t)(n) << ETRG_TRGMODE_SHIFT) +#define ETRG_TRGEDGE (1 << 28) /* Bit 28: Edge Selection */ +#define ETRG_TRGFILT (1 << 29) /* Bit 29: Filtered Input */ +#define ETRG_TRGSRC (1 << 30) /* Bit 30: Trigger Source */ +#define ETRG_RFEN (1 << 31) /* Bit 31: Recoverable Fault Update */ + +/* Leading Edge Blanking Register */ + +#define LEBR_LEBDELAY_SHIFT (0) /* Bits 0-6: Leading Edge Blanking Delay */ +#define LEBR_LEBDELAY_MASK (0x3f << LEBR_LEBDELAY_SHIFT) +# define LEBR_LEBDELAY_SEL(n) ((uint32_t)(n) << LEBR_LEBDELAY_SHIFT) +#define LEBR_PWMLFEN (1 << 16) /* Bit 16: PWML Falling Edge Enable */ +#define LEBR_PWMLREN (1 << 17) /* Bit 18: PWML Rising Edge Enable */ +#define LEBR_PWMHFEN (1 << 18) /* Bit 17: PWMH Falling Edge Enable */ +#define LEBR_PWMHREN (1 << 19) /* Bit 18: PWMH Rising Edge Enable */ + +#endif /* CONFIG_SAMV7_PWM */ diff --git a/arch/arm/src/samv7/sam_pwm.c b/arch/arm/src/samv7/sam_pwm.c new file mode 100644 index 00000000000..b3608d62c43 --- /dev/null +++ b/arch/arm/src/samv7/sam_pwm.c @@ -0,0 +1,683 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "arm_arch.h" +#include "chip.h" +#include "sam_config.h" +#include "sam_pwm.h" +#include "sam_periphclks.h" +#include "sam_gpio.h" +#include "hardware/sam_pwm.h" +#include "hardware/sam_pinmap.h" +#include "hardware/sam_pio.h" + +#include + +#include + +#ifdef CONFIG_SAMV7_PWM + +#ifdef CONFIG_PWM_NCHANNELS +# define PWM_NCHANNELS CONFIG_PWM_NCHANNELS +#else +# define PWM_NCHANNELS 1 +#endif + +#define CHANNEL_OFFSET 0x20 +#define CLK_FREQ BOARD_MCK_FREQUENCY +#define PWM_RES 65535 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sam_pwm_channel_s +{ + uint8_t channel; /* Number of PWM module */ + bool used; /* True if the module is used */ + uint32_t pin; /* PWM output pin */ +}; + +struct sam_pwm_s +{ + const struct pwm_ops_s *ops; /* PWM operations */ + FAR const struct sam_pwm_channel_s *channels; + uint8_t channels_num; /* Number of channels */ + uint32_t frequency; /* PWM frequency */ + uint32_t base; /* Base address of peripheral register */ +}; + +/* PWM driver methods */ + +static int pwm_setup(FAR struct pwm_lowerhalf_s *dev); +static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev); +static int pwm_start(FAR struct pwm_lowerhalf_s *dev, + FAR const struct pwm_info_s *info); +static int pwm_stop(FAR struct pwm_lowerhalf_s *dev); +static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, + int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +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_SAMV7_PWM0 + +static struct sam_pwm_channel_s g_pwm0_channels[] = +{ +#ifdef CONFIG_SAMV7_PWM0_CH0 + { + .channel = 0, + .used = true, + .pin = GPIO_PWMC0_H0, + }, +#endif +#ifdef CONFIG_SAMV7_PWM0_CH1 + { + .channel = 1, + .used = true, + .pin = GPIO_PWMC0_H1, + }, +#endif +#ifdef CONFIG_SAMV7_PWM0_CH2 + { + .channel = 2, + .used = true, + .pin = GPIO_PWMC0_H2, + }, +#endif +#ifdef CONFIG_SAMV7_PWM0_CH3 + { + .channel = 3, + .used = true, + .pin = GPIO_PWMC0_H3, + }, +#endif +}; + +static struct sam_pwm_s g_pwm0 = +{ + .ops = &g_pwmops, + .channels = g_pwm0_channels, + .channels_num = 4, + .frequency = 0, + .base = SAM_PWM0_BASE, +}; +#endif /* CONFIG_SAMV7_PWM0 */ + +#ifdef CONFIG_SAMV7_PWM1 + +static struct sam_pwm_channel_s g_pwm1_channels[] = +{ +#ifdef CONFIG_SAMV7_PWM1_CH0 + { + .channel = 0, + .used = true, + .pin = GPIO_PWMC1_H0 + }, +#endif +#ifdef CONFIG_SAMV7_PWM1_CH1 + { + .channel = 1, + .used = true, + .pin = GPIO_PWMC1_H1 + }, +#endif +#ifdef CONFIG_SAMV7_PWM1_CH2 + { + .channel = 2, + .used = true, + .pin = GPIO_PWMC1_H2 + }, +#endif +#ifdef CONFIG_SAMV7_PWM1_CH3 + { + .channel = 3, + .used = true, + .pin = GPIO_PWMC1_H3 + }, +#endif +}; /* CONFIG_SAMV7_PWM1 */ + +static struct sam_pwm_s g_pwm1 = +{ + .ops = &g_pwmops, + .channels = g_pwm1_channels, + .channels_num = 4, + .frequency = 0, + .base = SAM_PWM1_BASE, +}; + +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static void pwm_putreg(FAR struct sam_pwm_s *priv, uint32_t offset, + uint32_t value); +static uint32_t pwm_getreg(FAR struct sam_pwm_s *priv, uint32_t offset); + +/* Helper functions */ + +static int pwm_set_output(FAR struct pwm_lowerhalf_s *dev, uint8_t channel, + ub16_t duty); +static int pwm_change_freq(FAR struct pwm_lowerhalf_s *dev, + FAR const struct pwm_info_s *info, uint8_t channel); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void pwm_putreg(FAR struct sam_pwm_s *priv, uint32_t offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +static uint32_t pwm_getreg(FAR struct sam_pwm_s *priv, uint32_t offset) +{ + return getreg32(priv->base + offset); +} + +/**************************************************************************** + * Name: pwm_change_freq + * + * Description: + * Set timer frequency and change registers value to respect that + * frequency. + * + * 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_change_freq(FAR struct pwm_lowerhalf_s *dev, + FAR const struct pwm_info_s *info, uint8_t channel) +{ + FAR struct sam_pwm_s *priv = (FAR struct sam_pwm_s *)dev; +#ifdef CONFIG_PWM_MULTICHAN + uint8_t shift = info->channels[channel].channel - 1; +#else + uint8_t shift = priv->channels[0].channel; +#endif + uint32_t regval; + uint32_t olddiv = pwm_getreg(priv, SAMV7_PWM_CPRDX + + (shift * CHANNEL_OFFSET)); + uint32_t newdiv = (uint32_t)((float)CLK_FREQ / info->frequency + 0.5f); + uint32_t prescale = 0; + + while (newdiv > PWM_RES && prescale < 11) + { + newdiv = newdiv >> 1; + prescale = prescale + 1; + } + + if (newdiv > PWM_RES) + { + newdiv = PWM_RES; + } + else if (newdiv < 2) + { + newdiv = 2; + } + + regval = pwm_getreg(priv, SAMV7_PWM_CMRX + (shift * CHANNEL_OFFSET)); + regval |= CMR_CPRE_SEL(prescale); + pwm_putreg(priv, SAMV7_PWM_CMRX + (shift * CHANNEL_OFFSET), regval); + + pwm_putreg(priv, SAMV7_PWM_CPRDUPDX + (shift * CHANNEL_OFFSET), + newdiv - 1); + + regval = pwm_getreg(priv, SAMV7_PWM_CDTYX + (shift * CHANNEL_OFFSET)); + regval = regval * newdiv / olddiv; + pwm_putreg(priv, SAMV7_PWM_CDTYUPDX + (shift * CHANNEL_OFFSET), + regval); + + return OK; +} + +/**************************************************************************** + * Name: pwm_set_output + * + * Description: + * Set duty cycle and enable PWM output. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * channel - Channel to by updated + * duty - New duty + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_set_output(FAR struct pwm_lowerhalf_s *dev, uint8_t channel, + ub16_t duty) +{ + FAR struct sam_pwm_s *priv = (FAR struct sam_pwm_s *)dev; + uint16_t period; + uint16_t width; + uint16_t regval; + double duty_pct; + uint8_t shift = channel; /* Shift submodle offset addresses */ + + /* Get the period value */ + + period = pwm_getreg(priv, SAMV7_PWM_CPRDX + (shift * CHANNEL_OFFSET)); + + /* Compute PWM width (count value to set PWM low) */ + + duty_pct = (duty / 65536.0) * 100; + width = (uint16_t)(((uint16_t)duty_pct * period) / 100); + + /* Update duty cycle */ + + pwm_putreg(priv, SAMV7_PWM_CDTYUPDX + (shift * CHANNEL_OFFSET), width); + + regval = CHID_SEL(1 << shift); + pwm_putreg(priv, SAMV7_PWM_ENA, regval); + + return OK; +} + +/**************************************************************************** + * 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(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct sam_pwm_s *priv = (FAR struct sam_pwm_s *)dev; + uint32_t pin = 0; + uint32_t regval; + + /* Unlock User Interface */ + + regval = WPCR_WPRCMD_SEL(0) | WPCR_WPRG_MASK | WPCR_WPKEY_SEL(0x50574d); + pwm_putreg(priv, SAMV7_PWM_WPCR, regval); + + /* Disable all channels */ + + regval = CHID_SEL(CHID_MASK); + pwm_putreg(priv, SAMV7_PWM_DIS, regval); + + for (int i = 0; i < priv->channels_num; i++) + { + /* Configure the channel only if is set to be used */ + + if (priv->channels[i].used != 1) + { + continue; + } + + pin = priv->channels[i].pin; + + if (pin != 0) + { + sam_configgpio(pin); + } + + sam_configgpio(pin); + + regval = CMR_CPOL | CMR_DPOLI; + pwm_putreg(priv, SAMV7_PWM_CMRX + (i * CHANNEL_OFFSET), regval); + + /* Set duty cycle register */ + + pwm_putreg(priv, SAMV7_PWM_CDTYX + (i * CHANNEL_OFFSET), 0); + + /* Set period register with default period */ + + regval = 0x82b8; + pwm_putreg(priv, SAMV7_PWM_CPRDX + (i * CHANNEL_OFFSET), regval); + + /* Reset Dead Time Register */ + + pwm_putreg(priv, SAMV7_PWM_DTX + (i * CHANNEL_OFFSET), 0); + + /* Fault protection registers */ + + pwm_putreg(priv, SAMV7_PWM_FPV1, 0); + pwm_putreg(priv, SAMV7_PWM_FPV2, 0); + pwm_putreg(priv, SAMV7_PWM_FPE, 0); + + /* Enable the channel */ + + regval = CHID_SEL(1 << i); + pwm_putreg(priv, SAMV7_PWM_ENA, regval); + + /* Set synchronous output */ + + regval = SCM_SYNC_SEL(1 << i); + pwm_putreg(priv, SAMV7_PWM_SCM, regval); + } + + 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(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct sam_pwm_s *priv = (FAR struct sam_pwm_s *)dev; + uint32_t regval; + + /* Disable all channels and interrupts */ + + regval = CHID_SEL(CHID_MASK); + pwm_putreg(priv, SAMV7_PWM_DIS, regval); + + regval = IR1_CHID_SEL(CHID_MASK); + pwm_putreg(priv, SAMV7_PWM_IDR1, regval); + + for (int i = 0; i < priv->channels_num; i++) + { + /* Skip modules that are not used */ + + if (priv->channels[i].used != 1) + { + continue; + } + + /* Reset period register */ + + pwm_putreg(priv, SAMV7_PWM_CPRDX + (i * CHANNEL_OFFSET), 0); + + /* Reset duty cycle register */ + + pwm_putreg(priv, SAMV7_PWM_CDTYX + (i * CHANNEL_OFFSET), 0); + + /* Reset Dead Time Register */ + + pwm_putreg(priv, SAMV7_PWM_DTX + (i * CHANNEL_OFFSET), 0); + } + + return OK; +} + +/**************************************************************************** + * Name: pwm_start + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * 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(FAR struct pwm_lowerhalf_s *dev, + FAR const struct pwm_info_s *info) +{ + FAR struct sam_pwm_s *priv = (FAR struct sam_pwm_s *)dev; + int ret = OK; + + /* Change frequency only if it is needed */ + + if (info->frequency != priv->frequency) + { + for (int i = 0; i < PWM_NCHANNELS; i++) + { +#ifdef CONFIG_PWM_MULTICHAN + /* Break the loop if all following channels are not configured */ + + if (info->channels[i].channel == -1) + { + break; + } + + /* Configure the module freq only if is set to be used */ + + if (info->channels[i].channel != 0) + { + ret = pwm_change_freq(dev, info, i); + } +#else + ret = pwm_change_freq(dev, info, i); +#endif + } + + /* Save current frequency */ + + if (ret == OK) + { + priv->frequency = info->frequency; + } + } + +#ifdef CONFIG_PWM_MULTICHAN + for (int i = 0; ret == OK && i < PWM_NCHANNELS; i++) + { + /* Break the loop if all following channels are not configured */ + + if (info->channels[i].channel == -1) + { + break; + } + + /* Enable PWM output for each channel */ + + if (info->channels[i].channel != 0) + { + ret = pwm_set_output(dev, info->channels[i].channel - 1, + info->channels[i].duty); + } + } +#else + /* Enable PWM output just for first channel */ + + ret = pwm_set_output(dev, priv->channels[0].channel, info->duty); + +#endif /* CONFIG_PWM_MULTICHAN */ + + /* Set sychnronous outputs */ + + pwm_putreg(priv, SAMV7_PWM_SCUC, SCUC_UPDULOCK); + + return ret; +} + +/**************************************************************************** + * Name: pwm_stop + * + * Description: + * Stop the pulsed output and reset the timer resources + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * This function is called to stop the pulsed output at anytime. This + * method is also called from the timer interrupt handler when a repetition + * count expires... automatically stopping the timer. + * + ****************************************************************************/ + +static int pwm_stop(FAR struct pwm_lowerhalf_s *dev) +{ + FAR struct sam_pwm_s *priv = (FAR struct sam_pwm_s *)dev; + uint8_t shift; + uint32_t regval; + +#ifdef CONFIG_PWM_MULTICHAN + for (int i = 0; i < priv->channels_num; i++) + { + /* Skip settings if channel is not configured */ + + if (!priv->channels[i].used) + { + continue; + } + + shift = priv->channels[i].channel - 1; + + regval = CHID_SEL(1 << shift); + pwm_putreg(priv, SAMV7_PWM_DIS, regval); + } + +#else + shift = priv->channels[0].channel; + + regval = CHID_SEL(1 << shift); + pwm_putreg(priv, SAMV7_PWM_DIS, regval); + +#endif /* CONFIG_PWM_MULTICHAN */ + + 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(FAR struct pwm_lowerhalf_s *dev, int cmd, + unsigned long arg) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: sam_pwminitialize + * + * Description: + * Initialize the PWM channel for use with the upper level PWM driver. + * + * Input Parameters: + * channel - a number identifying the PWM channel. + * + * Returned Value: + * A pointer to the lower half PWM driver is returned on success, + * NULL on failure. + * + ****************************************************************************/ + +FAR struct pwm_lowerhalf_s *sam_pwminitialize(int pwm) +{ + FAR struct sam_pwm_s *priv; + + pwminfo("Initializing pwm %d\n", pwm); + + switch (pwm) + { +#ifdef CONFIG_SAMV7_PWM0 + case 0: + sam_pwm0_enableclk(); + priv = &g_pwm0; + break; +#endif +#ifdef CONFIG_SAMV7_PWM1 + case 1: + sam_pwm1_enableclk(); + priv = &g_pwm1; + break; +#endif + default: + pwmerr("ERROR: PWM number invalid or not configured %d\n", pwm); + return NULL; + } + + return (FAR struct pwm_lowerhalf_s *)priv; +} +#endif /* CONFIG_SAMV7_PWM */ diff --git a/arch/arm/src/samv7/sam_pwm.h b/arch/arm/src/samv7/sam_pwm.h new file mode 100644 index 00000000000..fba09be7728 --- /dev/null +++ b/arch/arm/src/samv7/sam_pwm.h @@ -0,0 +1,78 @@ +/**************************************************************************** + * arch/arm/src/samv7/sam_pwm.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_SAMV7_SAM_PWM_H +#define __ARCH_ARM_SRC_SAMV7_SAM_PWM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "hardware/sam_pwm.h" + +#ifdef CONFIG_SAMV7_PWM + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Function: sam_pwminitialize + * + * Description: + * Initialize the PWM module for use with the upper level PWM driver. + * + * Input Parameters: + * pwm - a number identifying the PWM driver. + * + * Returned Value: + * A pointer to the lower half PWM driver is returned on success, + * NULL on failure. + * + ****************************************************************************/ + +FAR struct pwm_lowerhalf_s *sam_pwminitialize(int pwm); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_SAMV7_PWM */ +#endif /* __ARCH_ARM_SRC_SAMV7_SAM_PWM_H */