diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index cbee77c520..7876660f02 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -1590,6 +1590,7 @@ config STM32_STM32F207 config STM32_STM32F30XX bool default n + select STM32_HAVE_ADC1_DMA select STM32_HAVE_CAN1 select STM32_HAVE_DAC1 select STM32_HAVE_TIM1 @@ -1604,6 +1605,8 @@ config STM32_STM32F30XX config STM32_STM32F302 bool default n + select STM32_HAVE_ADC2 + select STM32_HAVE_ADC2_DMA select STM32_HAVE_I2C2 select STM32_HAVE_SPI2 select STM32_HAVE_SPI3 @@ -1614,6 +1617,7 @@ config STM32_STM32F303 bool default n select STM32_HAVE_ADC2 + select STM32_HAVE_ADC2_DMA select STM32_HAVE_CCM select STM32_HAVE_DAC2 select STM32_HAVE_TIM7 @@ -6949,6 +6953,12 @@ config STM32_HRTIM_DISABLE_CHARDRV In most cases we do not need HRTIM Character Driver, so we can disable it and save some memory. +config STM32_HRTIM_NO_ENABLE_TIMERS + bool "Do not enable HRTIM timers at startup" + default n + ---help--- + Do not enable HRTIM timers at startup + menuconfig STM32_HRTIM_ADC bool "HRTIM ADC Triggering" default n @@ -7558,15 +7568,20 @@ config STM32_ADC_NO_STARTUP_CONV config STM32_ADC_NOIRQ bool "Do not use default ADC interrupts" - depends on STM32_STM32F33XX default n ---help--- Do not use default ADC interrupts handlers. - Only for STM32_STM32F33XX at this moment. + +config STM32_ADC_LL_OPS + bool "ADC low-level operations" + default n + ---help--- + Enable low-level ADC ops. config STM32_ADC_CHANGE_SAMPLETIME bool "ADC sample time configuration" default n + depends on STM32_ADC_LL_OPS ---help--- Enable ADC sample time configuration (SMPRx registers). @@ -7579,6 +7594,14 @@ config STM32_ADC1_DMA DMA transfer, which is necessary if multiple channels are read or if very high trigger frequencies are used. +config STM32_ADC1_DMA_CFG + int "ADC1 DMA configuration" + depends on STM32_ADC1_DMA + range 0 1 + default 0 + ---help--- + 0 - ADC1 DMA in One Shot Mode, 1 - ADC1 DMA in Circular Mode + config STM32_ADC2_DMA bool "ADC2 DMA" depends on STM32_ADC2 && STM32_HAVE_ADC2_DMA @@ -7588,6 +7611,14 @@ config STM32_ADC2_DMA DMA transfer, which is necessary if multiple channels are read or if very high trigger frequencies are used. +config STM32_ADC2_DMA_CFG + int "ADC2 DMA configuration" + depends on STM32_ADC2_DMA + range 0 1 + default 0 + ---help--- + 0 - ADC2 DMA in One Shot Mode, 1 - ADC2 DMA in Circular Mode + config STM32_ADC3_DMA bool "ADC3 DMA" depends on STM32_ADC3 && STM32_HAVE_ADC3_DMA @@ -7597,6 +7628,14 @@ config STM32_ADC3_DMA DMA transfer, which is necessary if multiple channels are read or if very high trigger frequencies are used. +config STM32_ADC3_DMA_CFG + int "ADC3 DMA configuration" + depends on STM32_ADC3_DMA + range 0 1 + default 0 + ---help--- + 0 - ADC3 DMA in One Shot Mode, 1 - ADC3 DMA in Circular Mode + config STM32_ADC4_DMA bool "ADC4 DMA" depends on STM32_ADC4 && STM32_HAVE_ADC4_DMA @@ -7606,21 +7645,45 @@ config STM32_ADC4_DMA DMA transfer, which is necessary if multiple channels are read or if very high trigger frequencies are used. -config STM32_ADC1_INJECTED - bool "ADC1 INJECTED" - depends on STM32_ADC1 && STM32_STM32F33XX - default n +config STM32_ADC4_DMA_CFG + int "ADC4 DMA configuration" + depends on STM32_ADC4_DMA + range 0 1 + default 0 + ---help--- + 0 - ADC4 DMA in One Shot Mode, 1 - ADC4 DMA in Circular Mode + +config STM32_ADC1_INJECTED_CHAN + int "ADC1 injected channels" + depends on STM32_ADC1 + range 0 4 + default 0 ---help--- Support for ADC1 injected channels. - Only for STM32_STM32F33XX at this moment. -config STM32_ADC2_INJECTED - bool "ADC2 INJECTED" - depends on STM32_ADC2 && STM32_STM32F33XX - default n +config STM32_ADC2_INJECTED_CHAN + int "ADC2 injected channels" + depends on STM32_ADC2 + range 0 4 + default 0 ---help--- Support for ADC2 injected channels. - Only for STM32_STM32F33XX at this moment. + +config STM32_ADC3_INJECTED_CHAN + int "ADC3 injected channels" + depends on STM32_ADC3 + range 0 4 + default 0 + ---help--- + Support for ADC3 injected channels. + +config STM32_ADC4_INJECTED_CHAN + int "ADC4 injected channels" + depends on STM32_ADC4 + range 0 4 + default 0 + ---help--- + Support for ADC4 injected channels. endmenu diff --git a/arch/arm/src/stm32/Make.defs b/arch/arm/src/stm32/Make.defs index 7c8b4cb8c3..8f981ec5b7 100644 --- a/arch/arm/src/stm32/Make.defs +++ b/arch/arm/src/stm32/Make.defs @@ -192,12 +192,8 @@ endif endif ifeq ($(CONFIG_STM32_ADC),y) -ifeq ($(CONFIG_STM32_STM32F33XX),y) -CHIP_CSRCS += stm32f33xxx_adc.c -else CHIP_CSRCS += stm32_adc.c endif -endif ifeq ($(CONFIG_STM32_SDADC),y) CHIP_CSRCS += stm32_sdadc.c diff --git a/arch/arm/src/stm32/chip/stm32_adc_v1.h b/arch/arm/src/stm32/chip/stm32_adc_v1.h index 75113a4f36..27b3acbb66 100644 --- a/arch/arm/src/stm32/chip/stm32_adc_v1.h +++ b/arch/arm/src/stm32/chip/stm32_adc_v1.h @@ -520,8 +520,10 @@ #define ADC_JSQR_JSQ3_MASK (0x1f << ADC_JSQR_JSQ3_SHIFT) #define ADC_JSQR_JSQ4_SHIFT (15) /* Bits 19-15: 4th conversion in injected sequence */ #define ADC_JSQR_JSQ4_MASK (0x1f << ADC_JSQR_JSQ4_SHIFT) +#define ADC_JSQR_JSQ_SHIFT (5) /* Shift between JSQx bits */ #define ADC_JSQR_JL_SHIFT (20) /* Bits 21-20: Injected Sequence length */ #define ADC_JSQR_JL_MASK (3 << ADC_JSQR_JL_SHIFT) +# define ADC_JSQR_JL(n) (((n)-1) << ADC_JSQR_JL_SHIFT) /* n=1..4 */ /* ADC injected data register 1-4 */ diff --git a/arch/arm/src/stm32/chip/stm32_adc_v1l1.h b/arch/arm/src/stm32/chip/stm32_adc_v1l1.h index 2e7790f7ad..b35716efab 100644 --- a/arch/arm/src/stm32/chip/stm32_adc_v1l1.h +++ b/arch/arm/src/stm32/chip/stm32_adc_v1l1.h @@ -509,8 +509,10 @@ #define ADC_JSQR_JSQ3_MASK (0x1f << ADC_JSQR_JSQ3_SHIFT) #define ADC_JSQR_JSQ4_SHIFT (15) /* Bits 19-15: 4th conversion in injected sequence */ #define ADC_JSQR_JSQ4_MASK (0x1f << ADC_JSQR_JSQ4_SHIFT) +#define ADC_JSQR_JSQ_SHIFT (5) /* Shift between JSQx bits */ #define ADC_JSQR_JL_SHIFT (20) /* Bits 21-20: Injected Sequence length */ #define ADC_JSQR_JL_MASK (3 << ADC_JSQR_JL_SHIFT) +# define ADC_JSQR_JL(n) (((n)-1) << ADC_JSQR_JL_SHIFT) /* n=1..4 */ /* ADC injected data register 1-4 */ diff --git a/arch/arm/src/stm32/chip/stm32_adc_v2.h b/arch/arm/src/stm32/chip/stm32_adc_v2.h index 4d4248af95..72dc056d76 100644 --- a/arch/arm/src/stm32/chip/stm32_adc_v2.h +++ b/arch/arm/src/stm32/chip/stm32_adc_v2.h @@ -615,6 +615,7 @@ #define ADC_JSQR_JSQ4_SHIFT (26) /* Bits 26-30: 4th conversion in injected sequence */ #define ADC_JSQR_JSQ4_MASK (0x1f << ADC_JSQR_JSQ4_SHIFT) # define ADC_JSQR_JSQ4(ch) ((ch) << ADC_JSQR_JSQ4_SHIFT) /* Channel number 1..18 */ +#define ADC_JSQR_JSQ_SHIFT (6) /* Shift between JSQx bits */ /* ADC offset register 1 and 2 */ diff --git a/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h b/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h index a9e36c5797..5f1ca17821 100644 --- a/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h +++ b/arch/arm/src/stm32/chip/stm32f33xxx_hrtim.h @@ -183,6 +183,7 @@ # define HRTIM_MCR_SYNCSRC_MCMP1 (1 << HRTIM_MCR_SYNCSRC_SHIFT) /* 01: Master timer Compare 1 Event */ # define HRTIM_MCR_SYNCSRC_TASTRT (2 << HRTIM_MCR_SYNCSRC_SHIFT) /* 10: Timer A start/reset */ # define HRTIM_MCR_SYNCSRC_TACMP1 (3 << HRTIM_MCR_SYNCSRC_SHIFT) /* 11: Timer A Compare 1 Event */ +#define HRTIM_MCR_TCEN_SHIFT (16) #define HRTIM_MCR_MCEN (1 << 16) /* Bit 16: Master timer counter enable */ #define HRTIM_MCR_TACEN (1 << 17) /* Bit 17: Timer A counter enable */ #define HRTIM_MCR_TBCEN (1 << 18) /* Bit 18: Timer B counter enable */ diff --git a/arch/arm/src/stm32/stm32_adc.c b/arch/arm/src/stm32/stm32_adc.c index be75506a38..fd9b247dd3 100644 --- a/arch/arm/src/stm32/stm32_adc.c +++ b/arch/arm/src/stm32/stm32_adc.c @@ -69,6 +69,21 @@ #include "stm32_dma.h" #include "stm32_adc.h" +/* The STM32 ADC lower-half driver functionality overview: + * - one lower-half driver for all STM32 ADC IP cores, + * - general lower-half logic for the Nuttx upper-half ADC driver, + * - lower-half ADC driver can be used not only with the upper-half ADC driver, + * but also in the lower-half logic for special-case custom drivers + * (eg. power-control, custom sensors), + * - ADC can be used in time-critical operations (eg. control loop for + * converters or motor drivers) therfore it is necessary to support the high + * performence, zero latency ADC interrupts, + * - ADC triggering from different sources (EXTSEL and JEXTSEL), + * - regular sequence conversion (supported in upper-half ADC driver) + * - injected sequence conversion (not supported in upper-half ADC driver) + * + */ + /* ADC "upper half" support must be enabled */ #ifdef CONFIG_STM32_ADC @@ -120,7 +135,7 @@ #if defined(HAVE_ADC_CLOCK_HSI) && \ (STM32_CFGR_PLLSRC != 0 || STM32_SYSCLK_SW != RCC_CFGR_SW_HSI) - # define HAVE_HSI_CONTROL +# define HAVE_HSI_CONTROL #endif /**************************************************************************** @@ -130,74 +145,59 @@ #if defined(HAVE_IP_ADC_V1) # ifdef HAVE_BASIC_ADC -# define STM32_RCC_RSTR STM32_RCC_APB2RSTR -# define RCC_RSTR_ADC1RST RCC_APB2RSTR_ADC1RST -# define RCC_RSTR_ADC2RST RCC_APB2RSTR_ADC2RST -# define RCC_RSTR_ADC3RST RCC_APB2RSTR_ADC3RST +# define STM32_RCC_RSTR STM32_RCC_APB2RSTR +# define RCC_RSTR_ADC1RST RCC_APB2RSTR_ADC1RST +# define RCC_RSTR_ADC2RST RCC_APB2RSTR_ADC2RST +# define RCC_RSTR_ADC3RST RCC_APB2RSTR_ADC3RST # else -# define STM32_RCC_RSTR STM32_RCC_APB2RSTR -# define RCC_RSTR_ADC1RST RCC_APB2RSTR_ADCRST -# define RCC_RSTR_ADC2RST RCC_APB2RSTR_ADCRST -# define RCC_RSTR_ADC3RST RCC_APB2RSTR_ADCRST +# define STM32_RCC_RSTR STM32_RCC_APB2RSTR +# define RCC_RSTR_ADC123RST RCC_APB2RSTR_ADCRST # endif #elif defined(HAVE_IP_ADC_V2) -# define STM32_RCC_RSTR STM32_RCC_AHBRSTR -# define RCC_RSTR_ADC1RST RCC_AHBRSTR_ADC12RST -# define RCC_RSTR_ADC2RST RCC_AHBRSTR_ADC12RST -# define RCC_RSTR_ADC3RST RCC_AHBRSTR_ADC34RST -# define RCC_RSTR_ADC4RST RCC_AHBRSTR_ADC34RST +# define STM32_RCC_RSTR STM32_RCC_AHBRSTR +# define RCC_RSTR_ADC12RST RCC_AHBRSTR_ADC12RST +# define RCC_RSTR_ADC34RST RCC_AHBRSTR_ADC34RST #endif /* ADC interrupts ***********************************************************/ #if defined(HAVE_IP_ADC_V1) -# define STM32_ADC_DMAREG_OFFSET STM32_ADC_CR2_OFFSET -# define ADC_DMAREG_DMA ADC_CR2_DMA -# define STM32_ADC_EXTREG_OFFSET STM32_ADC_CR2_OFFSET -# define ADC_EXTREG_EXTSEL_MASK ADC_CR2_EXTSEL_MASK -# define STM32_ADC_ISR_OFFSET STM32_ADC_SR_OFFSET -# define STM32_ADC_IER_OFFSET STM32_ADC_CR1_OFFSET -# define ADC_ISR_EOC ADC_SR_EOC -# define ADC_IER_EOC ADC_CR1_EOCIE -# define ADC_ISR_AWD ADC_SR_AWD -# define ADC_IER_AWD ADC_CR1_AWDIE -# define ADC_ISR_JEOC ADC_SR_JEOC -# define ADC_IER_JEOC ADC_CR1_JEOCIE +# define STM32_ADC_DMAREG_OFFSET STM32_ADC_CR2_OFFSET +# define ADC_DMAREG_DMA ADC_CR2_DMA +# define STM32_ADC_EXTREG_OFFSET STM32_ADC_CR2_OFFSET +# define ADC_EXTREG_EXTSEL_MASK ADC_CR2_EXTSEL_MASK +# define STM32_ADC_JEXTREG_OFFSET STM32_ADC_CR2_OFFSET +# define ADC_JEXTREG_JEXTSEL_MASK ADC_CR2_JEXTSEL_MASK +# define STM32_ADC_ISR_OFFSET STM32_ADC_SR_OFFSET +# define STM32_ADC_IER_OFFSET STM32_ADC_CR1_OFFSET # ifdef HAVE_BASIC_ADC -# define ADC_EXTREG_EXTEN_MASK ADC_CR2_EXTTRIG -# define ADC_EXTREG_EXTEN_NONE 0 -# define ADC_EXTREG_EXTEN_DEFAULT ADC_CR2_EXTTRIG -# define ADC_ISR_OVR 0 -# define ADC_IER_OVR 0 +# define ADC_EXTREG_EXTEN_MASK ADC_CR2_EXTTRIG +# define ADC_EXTREG_EXTEN_NONE 0 +# define ADC_EXTREG_EXTEN_DEFAULT ADC_CR2_EXTTRIG +# define ADC_JEXTREG_JEXTEN_MASK ADC_CR2_JEXTTRIG +# define ADC_JEXTREG_JEXTEN_NONE 0 +# define ADC_JEXTREG_JEXTEN_DEFAULT ADC_CR2_JEXTTRIG # else -# define ADC_EXTREG_EXTEN_MASK ADC_CR2_EXTEN_MASK -# define ADC_EXTREG_EXTEN_NONE ADC_CR2_EXTEN_NONE -# define ADC_EXTREG_EXTEN_DEFAULT ADC_CR2_EXTEN_RISING -# define ADC_ISR_OVR ADC_SR_OVR -# define ADC_IER_OVR ADC_CR1_OVRIE +# define ADC_EXTREG_EXTEN_MASK ADC_CR2_EXTEN_MASK +# define ADC_EXTREG_EXTEN_NONE ADC_CR2_EXTEN_NONE +# define ADC_EXTREG_EXTEN_DEFAULT ADC_CR2_EXTEN_RISING +# define ADC_JEXTREG_JEXTEN_MASK ADC_CR2_JEXTEN_MASK +# define ADC_JEXTREG_JEXTEN_NONE ADC_CR2_JEXTEN_NONE +# define ADC_JEXTREG_JEXTEN_DEFAULT ADC_CR2_JEXTEN_RISING # endif #elif defined(HAVE_IP_ADC_V2) -# define STM32_ADC_DMAREG_OFFSET STM32_ADC_CFGR1_OFFSET -# define ADC_DMAREG_DMA ADC_CFGR1_DMAEN -# define STM32_ADC_EXTREG_OFFSET STM32_ADC_CFGR1_OFFSET -# define ADC_EXTREG_EXTSEL_MASK ADC_CFGR1_EXTSEL_MASK -# define ADC_EXTREG_EXTEN_MASK ADC_CFGR1_EXTEN_MASK -# define ADC_EXTREG_EXTEN_DEFAULT ADC_CFGR1_EXTEN_RISING -# define ADC_ISR_EOC ADC_INT_EOC -# define ADC_IER_EOC ADC_INT_EOC -# define ADC_ISR_AWD ADC_INT_AWD1 -# define ADC_IER_AWD ADC_INT_AWD1 -# define ADC_ISR_JEOC ADC_INT_JEOC -# define ADC_IER_JEOC ADC_INT_JEOC -# define ADC_ISR_OVR ADC_INT_OVR -# define ADC_IER_OVR ADC_INT_OVR +# define STM32_ADC_DMAREG_OFFSET STM32_ADC_CFGR1_OFFSET +# define ADC_DMAREG_DMA ADC_CFGR1_DMAEN +# define STM32_ADC_EXTREG_OFFSET STM32_ADC_CFGR1_OFFSET +# define ADC_EXTREG_EXTSEL_MASK ADC_CFGR1_EXTSEL_MASK +# define ADC_EXTREG_EXTEN_MASK ADC_CFGR1_EXTEN_MASK +# define ADC_EXTREG_EXTEN_DEFAULT ADC_CFGR1_EXTEN_RISING +# define STM32_ADC_JEXTREG_OFFSET STM32_ADC_JSQR_OFFSET +# define ADC_JEXTREG_JEXTSEL_MASK ADC_JSQR_JEXTSEL_MASK +# define ADC_JEXTREG_JEXTEN_MASK ADC_JSQR_JEXTEN_MASK +# define ADC_JEXTREG_JEXTEN_DEFAULT ADC_JSQR_JEXTEN_RISING #endif -#define ADC_ISR_ALLINTS (ADC_ISR_EOC | ADC_ISR_AWD | ADC_ISR_JEOC | \ - ADC_ISR_OVR) -#define ADC_IER_ALLINTS (ADC_IER_EOC | ADC_IER_AWD | ADC_IER_JEOC | \ - ADC_IER_OVR) - /* ADC Channels/DMA ********************************************************/ /* The maximum number of channels that can be sampled. If DMA support is * not enabled, then only a single channel can be sampled. Otherwise, @@ -210,7 +210,7 @@ #ifdef ADC_HAVE_DMA # define ADC_MAX_SAMPLES ADC_MAX_CHANNELS_DMA #else -# if defined(CONFIG_STM32_STM32F30XX) +# if defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F33XX) # define ADC_MAX_SAMPLES ADC_MAX_CHANNELS_DMA /* Works without DMA should sampling frequency be reduced */ # elif defined(CONFIG_STM32_STM32L15XX) # define ADC_MAX_SAMPLES ADC_MAX_CHANNELS_DMA /* Works without DMA as IO_START_CONV can switch channels on the fly */ @@ -236,7 +236,7 @@ /* Sample time default configuration * - * REVISIT: simplify this, use adc_write_sample_time_registers() function. + * REVISIT: simplify this, use adc_sampletime_write() function. * REVISIT: default SMPR configurable from Kconfig */ @@ -260,7 +260,7 @@ (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP7_SHIFT) | \ (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP8_SHIFT) | \ (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP9_SHIFT)) -#elif defined(CONFIG_STM32_STM32F30XX) +#elif defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F33XX) # if defined(ADC_HAVE_DMA) || (ADC_MAX_SAMPLES == 1) # define ADC_SMPR_DEFAULT ADC_SMPR_61p5 # else /* Slow down sampling frequency */ @@ -375,36 +375,125 @@ # undef HAVE_ADC_RESOLUTION #endif -/* ADCs have common registers */ +/* ADC have common registers for all cores except basic ADC IPv1 (F1, F37x) */ -#ifndef CONFIG_STM32_HAVE_IP_ADC_V1_BASIC +#ifdef CONFIG_STM32_HAVE_IP_ADC_V1_BASIC # undef HAVE_ADC_CMN_REGS #else # define HAVE_ADC_CMN_REGS #endif +#if defined(HAVE_ADC_CMN_REGS) && STM32_NADC > 1 +# define HAVE_ADC_CMN_DATA +#else +# undef HAVE_ADC_CMN_DATA +#endif + +/* ADCx_EXTSEL_VALUE can be set by this driver (look at stm32_adc.h) or + * by board specific logic in board.h file. + */ + +#ifdef ADC1_EXTSEL_VALUE +# define ADC1_HAVE_EXTCFG 1 +# define ADC1_EXTCFG_VALUE (ADC1_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT) +#else +# undef ADC1_HAVE_EXTCFG +#endif +#ifdef ADC2_EXTSEL_VALUE +# define ADC2_HAVE_EXTCFG 1 +# define ADC2_EXTCFG_VALUE (ADC2_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT) +#else +# undef ADC2_HAVE_EXTCFG +#endif +#ifdef ADC3_EXTSEL_VALUE +# define ADC3_HAVE_EXTCFG 1 +# define ADC3_EXTCFG_VALUE (ADC3_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT) +#else +# undef ADC3_HAVE_EXTCFG +#endif +#ifdef ADC4_EXTSEL_VALUE +# define ADC4_HAVE_EXTCFG 1 +# define ADC4_EXTCFG_VALUE (ADC4_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT) +#else +# undef ADC4_HAVE_EXTCFG +#endif + +#if defined(ADC1_HAVE_EXTCFG) || defined(ADC2_HAVE_EXTCFG) || \ + defined(ADC3_HAVE_EXTCFG) || defined(ADC3_HAVE_EXTCFG) +# define ADC_HAVE_EXTCFG +#endif + +/* Injected channels external trigger support */ + +#ifdef ADC1_JEXTSEL_VALUE +# define ADC1_HAVE_JEXTCFG 1 +# define ADC1_JEXTCFG_VALUE (ADC1_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT) +#endif +#ifdef ADC2_JEXTSEL_VALUE +# define ADC2_HAVE_JEXTCFG 1 +# define ADC2_JEXTCFG_VALUE (ADC2_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT) +#endif +#ifdef ADC3_JEXTSEL_VALUE +# define ADC3_HAVE_JEXTCFG 1 +# define ADC3_JEXTCFG_VALUE (ADC3_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT) +#endif +#ifdef ADC4_JEXTSEL_VALUE +# define ADC4_HAVE_JEXTCFG 1 +# define ADC4_JEXTCFG_VALUE (ADC4_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT) +#endif + +#if defined(ADC1_HAVE_JEXTCFG) || defined(ADC2_HAVE_JEXTCFG) || \ + defined(ADC3_HAVE_JEXTCFG) || defined(ADC4_HAVE_JEXTCFG) +# define ADC_HAVE_JEXTCFG +#endif + +/* Max 4 injected channels */ + +#define ADC_INJ_MAX_SAMPLES 4 /**************************************************************************** * Private Types ****************************************************************************/ +/* Data common to all ADC instances */ + +#ifdef HAVE_ADC_CMN_DATA +struct adccmn_data_s +{ + uint8_t initialized; /* How many ADC instances are currently in use */ + sem_t lock; /* Exclusive access to common ADC data */ +}; +#endif + /* This structure describes the state of one ADC block * REVISIT: save some space with bit fields. */ struct stm32_dev_s { +#ifdef CONFIG_STM32_ADC_LL_OPS + FAR const struct stm32_adc_ops_s *llops; /* Low-level ADC ops */ +#endif +#ifndef CONFIG_STM32_ADC_NOIRQ FAR const struct adc_callback_s *cb; - uint8_t irq; /* Interrupt generated by this ADC block */ - uint8_t nchannels; /* Number of channels */ - uint8_t cchannels; /* Number of configured channels */ - uint8_t intf; /* ADC interface number */ - uint8_t current; /* Current ADC channel being converted */ + uint8_t irq; /* Interrupt generated by this ADC block */ +#endif +#ifdef HAVE_ADC_CMN_DATA + struct adccmn_data_s *cmn; /* Common ADC data */ +#endif + uint8_t rnchannels; /* Number of regular channels */ + uint8_t cr_channels; /* Number of configured regular channels */ +#ifdef ADC_HAVE_INJECTED + uint8_t cj_channels; /* Number of configured injected channels */ +#endif + uint8_t intf; /* ADC interface number */ + uint8_t current; /* Current ADC channel being converted */ #ifdef HAVE_ADC_RESOLUTION - uint8_t resolution; /* ADC resolution (0-3) */ + uint8_t resolution; /* ADC resolution (0-3) */ #endif #ifdef ADC_HAVE_DMA - uint8_t dmachan; /* DMA channel needed by this ADC */ - bool hasdma; /* True: This channel supports DMA */ + uint8_t dmachan; /* DMA channel needed by this ADC */ + uint8_t dmacfg; /* DMA channel configuration, only for ADC IPv2 */ + bool hasdma; /* True: This channel supports DMA */ #endif #ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME /* Sample time selection. These bits must be written only when ADON=0. @@ -412,32 +501,43 @@ struct stm32_dev_s */ uint8_t sample_rate[ADC_CHANNELS_NUMBER]; - uint8_t adc_channels; /* ADC channels number */ + uint8_t adc_channels; /* ADC channels number */ #endif #ifdef ADC_HAVE_TIMER - uint8_t trigger; /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3, - * 3=CC4, 4=TRGO */ + uint8_t trigger; /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3, + * 3=CC4, 4=TRGO */ +#endif + xcpt_t isr; /* Interrupt handler for this ADC block */ + uint32_t base; /* Base address of registers unique to this ADC + * block */ +#ifdef ADC_HAVE_EXTCFG + uint32_t extcfg; /* External event configuration for regular group */ +#endif +#ifdef ADC_HAVE_JEXTCFG + uint32_t jextcfg; /* External event configuration for injected group */ #endif - xcpt_t isr; /* Interrupt handler for this ADC block */ - uint32_t base; /* Base address of registers unique to this ADC - * block */ #ifdef ADC_HAVE_TIMER - uint32_t tbase; /* Base address of timer used by this ADC block */ - uint32_t extsel; /* EXTSEL value used by this ADC block */ - uint32_t pclck; /* The PCLK frequency that drives this timer */ - uint32_t freq; /* The desired frequency of conversions */ + uint32_t tbase; /* Base address of timer used by this ADC block */ + uint32_t pclck; /* The PCLK frequency that drives this timer */ + uint32_t freq; /* The desired frequency of conversions */ #endif #ifdef ADC_HAVE_DMA - DMA_HANDLE dma; /* Allocated DMA channel */ + DMA_HANDLE dma; /* Allocated DMA channel */ /* DMA transfer buffer */ - uint16_t dmabuffer[ADC_MAX_SAMPLES]; + uint16_t r_dmabuffer[ADC_MAX_SAMPLES]; #endif /* List of selected ADC channels to sample */ - uint8_t chanlist[ADC_MAX_SAMPLES]; + uint8_t r_chanlist[ADC_MAX_SAMPLES]; + +#ifdef ADC_HAVE_INJECTED + /* List of selected ADC injected channels to sample */ + + uint8_t j_chanlist[ADC_INJ_MAX_SAMPLES]; +#endif }; /**************************************************************************** @@ -455,7 +555,7 @@ static void adc_putreg(FAR struct stm32_dev_s *priv, int offset, uint32_t value); static void adc_modifyreg(FAR struct stm32_dev_s *priv, int offset, uint32_t clrbits, uint32_t setbits); -#ifndef HAVE_ADC_CMN_REGS +#ifdef HAVE_ADC_CMN_REGS static uint32_t adccmn_base_get(FAR struct stm32_dev_s *priv); static void adccmn_modifyreg(FAR struct stm32_dev_s *priv, uint32_t offset, uint32_t clrbits, uint32_t setbits); @@ -473,27 +573,33 @@ static void tim_dumpregs(FAR struct stm32_dev_s *priv, FAR const char *msg); #endif +#ifdef HAVE_ADC_CMN_DATA +static int adccmn_lock(FAR struct stm32_dev_s *priv, bool lock); +#endif + static void adc_rccreset(FAR struct stm32_dev_s *priv, bool reset); /* ADC Interrupt Handler */ +#ifndef CONFIG_STM32_ADC_NOIRQ static int adc_interrupt(FAR struct adc_dev_s *dev); -#if defined(STM32_IRQ_ADC1) && defined(CONFIG_STM32_ADC1) +# if defined(STM32_IRQ_ADC1) && defined(CONFIG_STM32_ADC1) static int adc1_interrupt(int irq, FAR void *context, FAR void *arg); -#endif -#if defined(STM32_IRQ_ADC12) && (defined(CONFIG_STM32_ADC1) || \ +# endif +# if defined(STM32_IRQ_ADC12) && (defined(CONFIG_STM32_ADC1) || \ defined(CONFIG_STM32_ADC2)) static int adc12_interrupt(int irq, FAR void *context, FAR void *arg); -#endif -#if (defined(STM32_IRQ_ADC3) && defined(CONFIG_STM32_ADC3)) +# endif +# if (defined(STM32_IRQ_ADC3) && defined(CONFIG_STM32_ADC3)) static int adc3_interrupt(int irq, FAR void *context, FAR void *arg); -#endif -#if defined(STM32_IRQ_ADC4) && defined(CONFIG_STM32_ADC4) +# endif +# if defined(STM32_IRQ_ADC4) && defined(CONFIG_STM32_ADC4) static int adc4_interrupt(int irq, FAR void *context, FAR void *arg); -#endif -#if defined(STM32_IRQ_ADC) +# endif +# if defined(STM32_IRQ_ADC) static int adc123_interrupt(int irq, FAR void *context, FAR void *arg); -#endif +# endif +#endif /* CONFIG_STM32_ADC_NOIRQ */ /* ADC Driver Methods */ @@ -545,12 +651,48 @@ static void adc_timstart(FAR struct stm32_dev_s *priv, bool enable); static int adc_timinit(FAR struct stm32_dev_s *priv); #endif -#ifdef ADC_HAVE_DMA +#if defined(ADC_HAVE_DMA) && !defined(CONFIG_STM32_ADC_NOIRQ) static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg); #endif -static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable); +static void adc_reg_startconv(FAR struct stm32_dev_s *priv, bool enable); +#ifdef ADC_HAVE_INJECTED +static void adc_inj_startconv(FAR struct stm32_dev_s *priv, bool enable); +static int adc_inj_set_ch(FAR struct adc_dev_s *dev, uint8_t ch); +#endif + +#ifdef ADC_HAVE_EXTCFG +static int adc_extcfg_set(FAR struct adc_dev_s *dev, uint32_t extcfg); +#endif +#ifdef ADC_HAVE_JEXTCFG +static int adc_jextcfg_set(FAR struct adc_dev_s *dev, uint32_t jextcfg); +#endif + +static void adc_dumpregs(FAR struct stm32_dev_s *priv); + +#ifdef CONFIG_STM32_ADC_LL_OPS +static void adc_intack(FAR struct stm32_adc_dev_s *dev, uint32_t source); +static void adc_inten(FAR struct stm32_adc_dev_s *dev, uint32_t source); +static void adc_intdis(FAR struct stm32_adc_dev_s *dev, uint32_t source); +static uint32_t adc_intget(FAR struct stm32_adc_dev_s *dev); +static uint32_t adc_regget(FAR struct stm32_adc_dev_s *dev); +static void adc_llops_reg_startconv(FAR struct stm32_adc_dev_s *dev, bool enable); +# ifdef ADC_HAVE_DMA +static int adc_regbufregister(FAR struct stm32_adc_dev_s *dev, uint16_t *buffer, + uint8_t len); +# endif +# ifdef ADC_HAVE_INJECTED +static uint32_t adc_injget(FAR struct stm32_adc_dev_s *dev, uint8_t chan); +static void adc_llops_inj_startconv(FAR struct stm32_adc_dev_s *dev, bool enable); +# endif +# ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME +static void adc_sampletime_set(FAR struct stm32_adc_dev_s *dev, + FAR struct adc_sample_time_s *time_samples); +static void adc_sampletime_write(FAR struct stm32_adc_dev_s *dev); +# endif +static void adc_llops_dumpregs(FAR struct stm32_adc_dev_s *dev); +#endif /**************************************************************************** * Private Data @@ -572,37 +714,122 @@ static const struct adc_ops_s g_adcops = .ao_ioctl = adc_ioctl, }; +/* Publicly visible ADC lower-half operations */ + +#ifdef CONFIG_STM32_ADC_LL_OPS +static const struct stm32_adc_ops_s g_adc_llops = +{ + .int_ack = adc_intack, + .int_get = adc_intget, + .int_en = adc_inten, + .int_dis = adc_intdis, + .val_get = adc_regget, + .reg_startconv = adc_llops_reg_startconv, +# ifdef ADC_HAVE_DMA + .regbuf_reg = adc_regbufregister, +# endif +# ifdef ADC_HAVE_INJECTED + .inj_get = adc_injget, + .inj_startconv = adc_llops_inj_startconv, +# endif +# ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME + .stime_set = adc_sampletime_set, + .stime_write = adc_sampletime_write, +# endif + .dump_regs = adc_llops_dumpregs +}; +#endif + +/* ADC instances are coupled in blocks for all IP versions except + * basic ADC IPv1 (F1, F37x). + */ + +#ifdef HAVE_ADC_CMN_DATA +# ifdef HAVE_IP_ADC_V1 +# define ADC1CMN_DATA g_adc123_cmn +# define ADC2CMN_DATA g_adc123_cmn +# define ADC3CMN_DATA g_adc123_cmn + +/* ADC123 common data */ + +struct adccmn_data_s g_adc123_cmn = +{ + .initialized = 0 +}; + +# elif defined(HAVE_IP_ADC_V2) +# define ADC1CMN_DATA g_adc12_cmn +# define ADC2CMN_DATA g_adc12_cmn +# define ADC3CMN_DATA g_adc34_cmn +# define ADC4CMN_DATA g_adc34_cmn +# if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) + +/* ADC12 common data */ + +struct adccmn_data_s g_adc12_cmn = +{ + .initialized = 0 +}; + +# endif +# if defined(CONFIG_STM32_ADC3) || defined(CONFIG_STM32_ADC4) + +/* ADC34 common data */ + +struct adccmn_data_s g_adc34_cmn = +{ + .initialized = 0 +}; + +# endif +# endif /* !HAVE_IP_ADC_V1 */ +#endif /* HAVE_ADC_CMN_DATA */ + /* ADC1 state */ #ifdef CONFIG_STM32_ADC1 static struct stm32_dev_s g_adcpriv1 = { -#if defined(STM32_IRQ_ADC1) +#ifdef CONFIG_STM32_ADC_LL_OPS + .llops = &g_adc_llops, +#endif +#ifndef CONFIG_STM32_ADC_NOIRQ +# if defined(STM32_IRQ_ADC1) .irq = STM32_IRQ_ADC1, .isr = adc1_interrupt, -#elif defined(STM32_IRQ_ADC12) +# elif defined(STM32_IRQ_ADC12) .irq = STM32_IRQ_ADC12, .isr = adc12_interrupt, -#elif defined(STM32_IRQ_ADC) +# elif defined(STM32_IRQ_ADC) .irq = STM32_IRQ_ADC, .isr = adc123_interrupt, -#else -# error "No STM32_IRQ_ADC1 STM32_IRQ_ADC12 or STM32_IRQ_ADC defined for CONFIG_STM32_ADC1" +# else +# error "No STM32_IRQ_ADC1 STM32_IRQ_ADC12 or STM32_IRQ_ADC defined for CONFIG_STM32_ADC1" +# endif +#endif /* CONFIG_STM32_ADC_NOIRQ */ +#ifdef HAVE_ADC_CMN_DATA + .cmn = &ADC1CMN_DATA, #endif .intf = 1, #ifdef HAVE_ADC_RESOLUTION .resolution = CONFIG_STM32_ADC1_RESOLUTION, #endif .base = STM32_ADC1_BASE, +#ifdef ADC1_HAVE_EXTCFG + .extcfg = ADC1_EXTCFG_VALUE, +#endif +#ifdef ADC1_HAVE_JEXTCFG + .jextcfg = ADC1_JEXTCFG_VALUE, +#endif #ifdef ADC1_HAVE_TIMER .trigger = CONFIG_STM32_ADC1_TIMTRIG, .tbase = ADC1_TIMER_BASE, - .extsel = ADC1_EXTSEL_VALUE, .pclck = ADC1_TIMER_PCLK_FREQUENCY, .freq = CONFIG_STM32_ADC1_SAMPLE_FREQUENCY, #endif #ifdef ADC1_HAVE_DMA .dmachan = ADC1_DMA_CHAN, + .dmacfg = CONFIG_STM32_ADC1_DMA_CFG, .hasdma = true, #endif }; @@ -619,29 +846,43 @@ static struct adc_dev_s g_adcdev1 = #ifdef CONFIG_STM32_ADC2 static struct stm32_dev_s g_adcpriv2 = { -#if defined(STM32_IRQ_ADC12) +#ifdef CONFIG_STM32_ADC_LL_OPS + .llops = &g_adc_llops, +#endif +#ifndef CONFIG_STM32_ADC_NOIRQ +# if defined(STM32_IRQ_ADC12) .irq = STM32_IRQ_ADC12, .isr = adc12_interrupt, -#elif defined(STM32_IRQ_ADC) +# elif defined(STM32_IRQ_ADC) .irq = STM32_IRQ_ADC, .isr = adc123_interrupt, -#else -# error "No STM32_IRQ_ADC12 or STM32_IRQ_ADC defined for CONFIG_STM32_ADC2" +# else +# error "No STM32_IRQ_ADC12 or STM32_IRQ_ADC defined for CONFIG_STM32_ADC2" +# endif +#endif /* CONFIG_STM32_ADC_NOIRQ */ +#ifdef HAVE_ADC_CMN_DATA + .cmn = &ADC2CMN_DATA, #endif .intf = 2, #ifdef HAVE_ADC_RESOLUTION .resolution = CONFIG_STM32_ADC2_RESOLUTION, #endif .base = STM32_ADC2_BASE, +#ifdef ADC2_HAVE_EXTCFG + .extcfg = ADC2_EXTCFG_VALUE, +#endif +#ifdef ADC2_HAVE_JEXTCFG + .jextcfg = ADC2_JEXTCFG_VALUE, +#endif #ifdef ADC2_HAVE_TIMER .trigger = CONFIG_STM32_ADC2_TIMTRIG, .tbase = ADC2_TIMER_BASE, - .extsel = ADC2_EXTSEL_VALUE, .pclck = ADC2_TIMER_PCLK_FREQUENCY, .freq = CONFIG_STM32_ADC2_SAMPLE_FREQUENCY, #endif #ifdef ADC2_HAVE_DMA .dmachan = ADC2_DMA_CHAN, + .dmacfg = CONFIG_STM32_ADC2_DMA_CFG, .hasdma = true, #endif }; @@ -658,29 +899,43 @@ static struct adc_dev_s g_adcdev2 = #ifdef CONFIG_STM32_ADC3 static struct stm32_dev_s g_adcpriv3 = { -#if defined(STM32_IRQ_ADC3) +#ifdef CONFIG_STM32_ADC_LL_OPS + .llops = &g_adc_llops, +#endif +#ifndef CONFIG_STM32_ADC_NOIRQ +# if defined(STM32_IRQ_ADC3) .irq = STM32_IRQ_ADC3, .isr = adc3_interrupt, -#elif defined(STM32_IRQ_ADC) +# elif defined(STM32_IRQ_ADC) .irq = STM32_IRQ_ADC, .isr = adc123_interrupt, -#else -# error "No STM32_IRQ_ADC3 or STM32_IRQ_ADC defined for CONFIG_STM32_ADC3" +# else +# error "No STM32_IRQ_ADC3 or STM32_IRQ_ADC defined for CONFIG_STM32_ADC3" +# endif +#endif /* CONFIG_STM32_ADC_NOIRQ */ +#ifdef HAVE_ADC_CMN_DATA + .cmn = &ADC3CMN_DATA, #endif .intf = 3, #ifdef HAVE_ADC_RESOLUTION .resolution = CONFIG_STM32_ADC3_RESOLUTION, #endif .base = STM32_ADC3_BASE, +#ifdef ADC3_HAVE_EXTCFG + .extcfg = ADC3_EXTCFG_VALUE, +#endif +#ifdef ADC3_HAVE_JEXTCFG + .jextcfg = ADC3_JEXTCFG_VALUE, +#endif #ifdef ADC3_HAVE_TIMER .trigger = CONFIG_STM32_ADC3_TIMTRIG, .tbase = ADC3_TIMER_BASE, - .extsel = ADC3_EXTSEL_VALUE, .pclck = ADC3_TIMER_PCLK_FREQUENCY, .freq = CONFIG_STM32_ADC3_SAMPLE_FREQUENCY, #endif #ifdef ADC3_HAVE_DMA .dmachan = ADC3_DMA_CHAN, + .dmacfg = CONFIG_STM32_ADC3_DMA_CFG, .hasdma = true, #endif }; @@ -697,22 +952,36 @@ static struct adc_dev_s g_adcdev3 = #ifdef CONFIG_STM32_ADC4 static struct stm32_dev_s g_adcpriv4 = { +#ifdef CONFIG_STM32_ADC_LL_OPS + .llops = &g_adc_llops, +#endif +#ifndef CONFIG_STM32_ADC_NOIRQ .irq = STM32_IRQ_ADC4, .isr = adc4_interrupt, +#endif +#ifdef HAVE_ADC_CMN_DATA + .cmn = &ADC4CMN_DATA, +#endif .intf = 4, #ifdef HAVE_ADC_RESOLUTION .resolution = CONFIG_STM32_ADC4_RESOLUTION, #endif .base = STM32_ADC4_BASE, +#ifdef ADC4_HAVE_EXTCFG + .extcfg = ADC4_EXTCFG_VALUE, +#endif +#ifdef ADC4_HAVE_JEXTCFG + .jextcfg = ADC4_JEXTCFG_VALUE, +#endif #ifdef ADC4_HAVE_TIMER .trigger = CONFIG_STM32_ADC4_TIMTRIG, .tbase = ADC4_TIMER_BASE, - .extsel = ADC4_EXTSEL_VALUE, .pclck = ADC4_TIMER_PCLK_FREQUENCY, .freq = CONFIG_STM32_ADC4_SAMPLE_FREQUENCY, #endif #ifdef ADC4_HAVE_DMA .dmachan = ADC4_DMA_CHAN, + .dmacfg = CONFIG_STM32_ADC4_DMA_CFG, .hasdma = true, #endif }; @@ -817,7 +1086,7 @@ static void adc_modifyreg(FAR struct stm32_dev_s *priv, int offset, adc_putreg(priv, offset, (adc_getreg(priv, offset) & ~clrbits) | setbits); } -#ifndef HAVE_ADC_CMN_REGS +#ifdef HAVE_ADC_CMN_REGS /**************************************************************************** * Name: adccmn_base_get @@ -825,17 +1094,20 @@ static void adc_modifyreg(FAR struct stm32_dev_s *priv, int offset, static uint32_t adccmn_base_get(FAR struct stm32_dev_s *priv) { - uint32_t base; + uint32_t base = 0; #if defined(HAVE_IP_ADC_V2) if (priv->base == STM32_ADC1_BASE || priv->base == STM32_ADC2_BASE) { base = STM32_ADC12CMN_BASE; } +# if defined(CONFIG_STM32_ADC3) || defined(CONFIG_STM32_ADC4) else { base = STM32_ADC34CMN_BASE; } +# endif + #elif defined(HAVE_IP_ADC_V1) base = STM32_ADCCMN_BASE; UNUSED(priv); @@ -1085,21 +1357,7 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) return ERROR; } - /* EXTSEL selection: These bits select the external event used to trigger - * the start of conversion of a regular group. NOTE: - * - * - The position with of the EXTSEL field varies from one STM32 MCU - * to another. - * - The width of the EXTSEL field varies from one STM32 MCU to another. - * - The value in priv->extsel is already shifted into the correct bit - * position. - */ - - ainfo("Initializing timers extsel = 0x%08x\n", priv->extsel); - - adc_modifyreg(priv, STM32_ADC_EXTREG_OFFSET, - ADC_EXTREG_EXTEN_MASK | ADC_EXTREG_EXTSEL_MASK, - ADC_EXTREG_EXTEN_DEFAULT | priv->extsel); + /* NOTE: EXTSEL configuration is done in adc_reset function */ /* Configure the timer channel to drive the ADC */ @@ -1401,10 +1659,10 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) #endif /**************************************************************************** - * Name: adc_startconv + * Name: adc_reg_startconv * * Description: - * Start (or stop) the ADC conversion process + * Start (or stop) the ADC regular conversion process * * Input Parameters: * priv - A reference to the ADC block status @@ -1415,11 +1673,11 @@ static int adc_timinit(FAR struct stm32_dev_s *priv) ****************************************************************************/ #if defined(HAVE_IP_ADC_V2) -static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable) +static void adc_reg_startconv(FAR struct stm32_dev_s *priv, bool enable) { uint32_t regval; - ainfo("enable: %d\n", enable ? 1 : 0); + ainfo("reg enable: %d\n", enable ? 1 : 0); if (enable) { @@ -1446,9 +1704,9 @@ static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable) } } #elif defined(HAVE_IP_ADC_V1) && !defined(HAVE_BASIC_ADC) -static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable) +static void adc_reg_startconv(FAR struct stm32_dev_s *priv, bool enable) { - ainfo("enable: %d\n", enable ? 1 : 0); + ainfo("reg enable: %d\n", enable ? 1 : 0); if (enable) { @@ -1464,9 +1722,9 @@ static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable) } } #else /* ADV IPv1 BASIC */ -static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable) +static void adc_reg_startconv(FAR struct stm32_dev_s *priv, bool enable) { - ainfo("enable: %d\n", enable ? 1 : 0); + ainfo("reg enable: %d\n", enable ? 1 : 0); if (!enable) { @@ -1485,6 +1743,113 @@ static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable) } #endif + +#ifdef ADC_HAVE_INJECTED + +/**************************************************************************** + * Name: adc_inj_startconv + * + * Description: + * Start (or stop) the ADC injected conversion process + * + * Input Parameters: + * priv - A reference to the ADC block status + * enable - True: Start conversion + * + * Returned Value: + * + ****************************************************************************/ + +#if defined(HAVE_IP_ADC_V2) +static void adc_inj_startconv(FAR struct stm32_dev_s *priv, bool enable) +{ + uint32_t regval; + + ainfo("inj enable: %d\n", enable ? 1 : 0); + + if (enable) + { + /* Start the conversion of regular channels */ + + adc_modifyreg(priv, STM32_ADC_CR_OFFSET, 0, ADC_CR_JADSTART); + } + else + { + regval = adc_getreg(priv, STM32_ADC_CR_OFFSET); + + /* Is a conversion ongoing? */ + + if ((regval & ADC_CR_JADSTART) != 0) + { + /* Stop the conversion */ + + adc_putreg(priv, STM32_ADC_CR_OFFSET, regval | ADC_CR_JADSTP); + + /* Wait for the conversion to stop */ + + while ((adc_getreg(priv, STM32_ADC_CR_OFFSET) & ADC_CR_JADSTP) != 0); + } + } +} +#elif defined(HAVE_IP_ADC_V1) && !defined(HAVE_BASIC_ADC) +static void adc_inj_startconv(FAR struct stm32_dev_s *priv, bool enable) +{ + ainfo("inj enable: %d\n", enable ? 1 : 0); + + if (enable) + { + /* Start the conversion of injected channels */ + + adc_modifyreg(priv, STM32_ADC_CR2_OFFSET, 0, ADC_CR2_JSWSTART); + } + else + { + /* Stop the conversion */ + + adc_modifyreg(priv, STM32_ADC_CR2_OFFSET, ADC_CR2_JSWSTART, 0); + } +} +#else /* ADV IPv1 BASIC */ +# error TODO +#endif + +#endif /* ADC_HAVE_INJECTED */ + +/**************************************************************************** + * Name: adccmn_lock + ****************************************************************************/ + +#ifdef HAVE_ADC_CMN_DATA +static int adccmn_lock(FAR struct stm32_dev_s *priv, bool lock) +{ + int ret; + + if (lock) + { + /* Take the semaphore (perhaps waiting) */ + + do + { + ret = nxsem_wait(&priv->cmn->lock); + + /* The only case that an error should occur here is if the wait + * was awakened by a signal. + */ + + DEBUGASSERT(ret == OK || ret == -EINTR); + } + while (ret == -EINTR); + } + else + { + (void)nxsem_post(&priv->cmn->lock); + ret = OK; + } + + return ret; +} +#endif + /**************************************************************************** * Name: adc_rccreset * @@ -1500,48 +1865,53 @@ static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable) * ****************************************************************************/ +#if defined(HAVE_IP_ADC_V1) && defined(HAVE_BASIC_ADC) static void adc_rccreset(FAR struct stm32_dev_s *priv, bool reset) { uint32_t adcbit; - /* Pick the appropriate bit in the APB2 reset register. - * For the STM32 F1, there is an individual bit to reset each ADC, - * but for the STM32 F2/F4, there is one common reset for all ADCs. - * THIS will probably cause some problems! - * - * REVISIT: this is correct only for F1! + /* Pick the appropriate bit in the RCC reset register. + * For the basic STM32 ADC IPv1, there is an individual bit to reset + * each ADC (ADC12 and ADC34). */ switch (priv->intf) { #ifdef CONFIG_STM32_ADC1 case 1: - adcbit = RCC_RSTR_ADC1RST; - break; + { + adcbit = RCC_RSTR_ADC1RST; + break; + } #endif #ifdef CONFIG_STM32_ADC2 case 2: - adcbit = RCC_RSTR_ADC2RST; - break; + { + adcbit = RCC_RSTR_ADC2RST; + break; + } #endif #ifdef CONFIG_STM32_ADC3 case 3: - adcbit = RCC_RSTR_ADC3RST; - break; + { + adcbit = RCC_RSTR_ADC3RST; + break; + } #endif #ifdef CONFIG_STM32_ADC4 case 4: - adcbit = RCC_RSTR_ADC4RST; - break; + { + adcbit = RCC_RSTR_ADC4RST; + break; + } #endif default: - return; + { + return; + } } - /* Set or clear the selected bit in the APB2 reset register. - * modifyreg32() disables interrupts. Disabling interrupts is necessary - * because the APB2RTSR register is used by several different drivers. - */ + /* Set or clear the selected bit in the RCC reset register */ if (reset) { @@ -1556,6 +1926,95 @@ static void adc_rccreset(FAR struct stm32_dev_s *priv, bool reset) modifyreg32(STM32_RCC_RSTR, adcbit, 0); } } +#elif defined(HAVE_IP_ADC_V1) +static void adc_rccreset(FAR struct stm32_dev_s *priv, bool reset) +{ + uint32_t adcbit; + + /* Pick the appropriate bit in the RCC reset register. + * For the STM32 ADC IPv1, there is one common reset for all ADCs. + */ + + switch (priv->intf) + { + case 1: + case 2: + case 3: + { + adcbit = RCC_RSTR_ADC123RST; + break; + } + + default: + { + return; + } + } + + /* Set or clear the selected bit in the RCC reset register */ + + if (reset) + { + /* Enable ADC reset state */ + + modifyreg32(STM32_RCC_RSTR, 0, adcbit); + } + else + { + /* Release ADC from reset state */ + + modifyreg32(STM32_RCC_RSTR, adcbit, 0); + } +} +#elif defined(HAVE_IP_ADC_V2) +static void adc_rccreset(FAR struct stm32_dev_s *priv, bool reset) +{ + uint32_t adcbit; + + /* Pick the appropriate bit in the RCC reset register. + * For the STM32 ADC IPv2, there is an individual bit to reset each ADC block. + */ + + switch (priv->intf) + { +#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) + case 1: + case 2: + { + adcbit = RCC_RSTR_ADC12RST; + break; + } +#endif +#if defined(CONFIG_STM32_ADC3) || defined(CONFIG_STM32_ADC4) + case 3: + case 4: + { + adcbit = RCC_RSTR_ADC34RST; + break; + } +#endif + default: + { + return; + } + } + + /* Set or clear the selected bit in the RCC reset register */ + + if (reset) + { + /* Enable ADC reset state */ + + modifyreg32(STM32_RCC_RSTR, 0, adcbit); + } + else + { + /* Release ADC from reset state */ + + modifyreg32(STM32_RCC_RSTR, adcbit, 0); + } +} +#endif /**************************************************************************** * Name: adc_power_down_idle @@ -1739,9 +2198,9 @@ static void adc_enable(FAR struct stm32_dev_s *priv, bool enable) } else if ((regval & ADC_CR_ADEN) != 0 && (regval & ADC_CR_ADDIS) == 0) { - /* Stop ongoing conversions */ + /* Stop ongoing regular conversions */ - adc_startconv(priv, false); + adc_reg_startconv(priv, false); /* Disable the ADC */ @@ -1774,98 +2233,6 @@ static void adc_enable(FAR struct stm32_dev_s *priv, bool enable) } #endif -/**************************************************************************** - * Name: adc_write_sample_time_registers - * - * Description: - * Writes previously defined values into ADC_SMPRx registers. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME -static void adc_write_sample_time_registers(FAR struct adc_dev_s *dev) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - uint32_t value = 0; - uint8_t i; - uint8_t shift; - - /* Sampling time individually for each channel. - * It's different for families. - */ - - for (i = 0, shift = 0; i < priv->adc_channels; i++) - { - value |= priv->sample_rate[i] << (shift * 3); - switch (i) - { -#if defined(STM32_ADC_SMPR0_OFFSET) && defined(STM32_ADC_SMPR3_OFFSET) - case 9: - { - adc_putreg(priv, STM32_ADC_SMPR3_OFFSET, value); - shift = 0; - value = 0; - break; - } - - case 19: - { - adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, value); - shift = 0; - value = 0; - break; - } - - case 29: - { - adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, value); - shift = 0; - value = 0; - break; - } - - case (ADC_CHANNELS_NUMBER - 1): - { - adc_putreg(priv, STM32_ADC_SMPR0_OFFSET, value); - shift = 0; - value = 0; - break; - } - -#elif defined(STM32_ADC_SMPR1_OFFSET) && defined(STM32_ADC_SMPR2_OFFSET) - case (ADC_CHANNELS_NUMBER - 1): - { - adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, value); - shift = 0; - value = 0; - break; - } - - case 9: - { - adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, value); - shift = 0; - value = 0; - break; - } -#else -# error "Not supported SMPRx configuration" -#endif - - default: - { - shift++; - break; - } - } - } -} -#endif - /**************************************************************************** * Name: adc_dmaconvcallback * @@ -1883,7 +2250,7 @@ static void adc_write_sample_time_registers(FAR struct adc_dev_s *dev) * ****************************************************************************/ -#ifdef ADC_HAVE_DMA +#if defined(ADC_HAVE_DMA) && !defined(CONFIG_STM32_ADC_NOIRQ) static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg) { FAR struct adc_dev_s *dev = (FAR struct adc_dev_s *)arg; @@ -1896,12 +2263,12 @@ static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg) { DEBUGASSERT(priv->cb->au_receive != NULL); - for (i = 0; i < priv->nchannels; i++) + for (i = 0; i < priv->rnchannels; i++) { - priv->cb->au_receive(dev, priv->chanlist[priv->current], - priv->dmabuffer[priv->current]); + priv->cb->au_receive(dev, priv->r_chanlist[priv->current], + priv->r_dmabuffer[priv->current]); priv->current++; - if (priv->current >= priv->nchannels) + if (priv->current >= priv->rnchannels) { /* Restart the conversion sequence from the beginning */ @@ -1929,10 +2296,13 @@ static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg) static int adc_bind(FAR struct adc_dev_s *dev, FAR const struct adc_callback_s *callback) { +#ifndef CONFIG_STM32_ADC_NOIRQ FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; DEBUGASSERT(priv != NULL); priv->cb = callback; +#endif + return OK; } @@ -1979,13 +2349,26 @@ static void adc_reset(FAR struct adc_dev_s *dev) #endif - /* Enable ADC reset state */ + /* Only if this is the first initialzied ADC instance in the ADC block */ - adc_rccreset(priv, true); +#ifdef HAVE_ADC_CMN_DATA + adccmn_lock(priv, true); - /* Release ADC from reset state */ + if (priv->cmn->initialized == 0) +#endif + { + /* Enable ADC reset state */ - adc_rccreset(priv, false); + adc_rccreset(priv, true); + + /* Release ADC from reset state */ + + adc_rccreset(priv, false); + } + +#ifdef HAVE_ADC_CMN_DATA + adccmn_lock(priv, false); +#endif #if defined(HAVE_IP_ADC_V2) @@ -2036,7 +2419,7 @@ static void adc_reset(FAR struct adc_dev_s *dev) */ #ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME - adc_write_sample_time_registers(dev); + adc_sampletime_write((FAR struct stm32_adc_dev_s *)dev); #else adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, ADC_SMPR1_DEFAULT); adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, ADC_SMPR2_DEFAULT); @@ -2054,20 +2437,31 @@ static void adc_reset(FAR struct adc_dev_s *dev) clrbits = ADC_CFGR1_AWD1CH_MASK; setbits = ADC_CFGR1_AWD1EN | ADC_CFGR1_AWD1SGL | - (priv->chanlist[0] << ADC_CFGR1_AWD1CH_SHIFT); + (priv->r_chanlist[0] << ADC_CFGR1_AWD1CH_SHIFT); -#ifdef ADC_HAVE_DMA +# ifdef ADC_HAVE_DMA if (priv->hasdma) { - /* Set DMA one shot mode */ + /* Set DMA mode */ - clrbits |= ADC_CFGR1_DMACFG; + if (priv->dmacfg == 0) + { + /* One Shot Mode */ + + clrbits |= ADC_CFGR1_DMACFG; + } + else + { + /* Circular Mode */ + + setbits |= ADC_CFGR1_DMACFG; + } /* Enable DMA */ setbits |= ADC_CFGR1_DMAEN; } -#endif +# endif /* Disable continuous mode and set align to right */ @@ -2082,6 +2476,7 @@ static void adc_reset(FAR struct adc_dev_s *dev) adc_modifyreg(priv, STM32_ADC_CFGR1_OFFSET, clrbits, setbits); +# ifndef CONFIG_STM32_ADC_NOIRQ /* Enable interrupt flags, but disable overrun interrupt */ clrbits = ADC_IER_OVR; @@ -2090,13 +2485,14 @@ static void adc_reset(FAR struct adc_dev_s *dev) /* Set IER configuration */ adc_modifyreg(priv, STM32_ADC_IER_OFFSET, clrbits, setbits); +# endif #else /* HAVE_IP_ADC_V1 */ /* Enable the analog watchdog */ clrbits = ADC_CR1_AWDCH_MASK; - setbits = ADC_CR1_AWDEN | (priv->chanlist[0] << ADC_CR1_AWDCH_SHIFT); + setbits = ADC_CR1_AWDEN | (priv->r_chanlist[0] << ADC_CR1_AWDCH_SHIFT); # ifdef HAVE_BASIC_ADC /* Set independent mode */ @@ -2156,6 +2552,23 @@ static void adc_reset(FAR struct adc_dev_s *dev) # ifdef ADC_HAVE_DMA if (priv->hasdma) { + /* Set DMA mode */ + + if (priv->dmacfg == 0) + { + /* One Shot Mode */ + + clrbits |= ADC_CR2_DDS; + } + else + { + /* Circular Mode */ + + setbits |= ADC_CR2_DDS; + } + + /* Enable DMA */ + setbits |= ADC_CR2_DMA; } # endif @@ -2168,7 +2581,19 @@ static void adc_reset(FAR struct adc_dev_s *dev) /* Configuration of the channel conversions */ - adc_set_ch(dev, 0); + if (priv->cr_channels > 0) + { + adc_set_ch(dev, 0); + } + +#ifdef ADC_HAVE_INJECTED + /* Configuration of the injected channel conversions after adc enabled */ + + if (priv->cj_channels > 0) + { + adc_inj_set_ch(dev, 0); + } +#endif /* ADC CCR configuration * REVISIT: simplify this @@ -2212,13 +2637,15 @@ static void adc_reset(FAR struct adc_dev_s *dev) priv->dma = stm32_dmachannel(priv->dmachan); +# ifndef CONFIG_STM32_ADC_NOIRQ stm32_dmasetup(priv->dma, priv->base + STM32_ADC_DR_OFFSET, - (uint32_t)priv->dmabuffer, - priv->nchannels, + (uint32_t)priv->r_dmabuffer, + priv->rnchannels, ADC_DMA_CONTROL_WORD); stm32_dmastart(priv->dma, adc_dmaconvcallback, dev, false); +# endif } #endif @@ -2233,6 +2660,20 @@ static void adc_reset(FAR struct adc_dev_s *dev) adc_enable(priv, true); + /* REVISIT: events configuration should be before adc_enable ?? */ + +#ifdef ADC_HAVE_EXTCFG + /* Configure external event for regular group */ + + adc_extcfg_set(dev, priv->extcfg); +#endif + +#ifdef ADC_HAVE_JEXTCFG + /* Configure external event for injected group */ + + adc_jextcfg_set(dev, priv->jextcfg); +#endif + #ifdef ADC_HAVE_TIMER if (priv->tbase != 0) { @@ -2242,10 +2683,10 @@ static void adc_reset(FAR struct adc_dev_s *dev) aerr("ERROR: adc_timinit failed: %d\n", ret); } - /* NOTE: for ADC IPv2 ADSTART bit must be set to start ADC conversion + /* NOTE: for ADC IPv2 (J)ADSTART bit must be set to start ADC conversion * even if hardware trigger is selected. * This is not done here, and you probably have to call ioctl - * with ANIOC_TRIGGER before reading from ADC! + * with ANIOC_TRIGGER before reading from ADC! */ } #ifndef CONFIG_STM32_ADC_NO_STARTUP_CONV @@ -2254,40 +2695,19 @@ static void adc_reset(FAR struct adc_dev_s *dev) #endif #ifndef CONFIG_STM32_ADC_NO_STARTUP_CONV { - adc_startconv(priv, true); + adc_reg_startconv(priv, true); + +# ifdef ADC_HAVE_INJECTED + adc_inj_startconv(priv, true); +# endif } #endif leave_critical_section(flags); -#if defined(HAVE_IP_ADC_V2) - ainfo("ISR: 0x%08x CR: 0x%08x CFGR1: 0x%08x\n", - adc_getreg(priv, STM32_ADC_ISR_OFFSET), - adc_getreg(priv, STM32_ADC_CR_OFFSET), - adc_getreg(priv, STM32_ADC_CFGR1_OFFSET)); -#else - ainfo("SR: 0x%08x CR1: 0x%08x CR2: 0x%08x\n", - adc_getreg(priv, STM32_ADC_SR_OFFSET), - adc_getreg(priv, STM32_ADC_CR1_OFFSET), - adc_getreg(priv, STM32_ADC_CR2_OFFSET)); -#endif + /* Dump regs */ - ainfo("SQR1: 0x%08x SQR2: 0x%08x SQR3: 0x%08x\n", - adc_getreg(priv, STM32_ADC_SQR1_OFFSET), - adc_getreg(priv, STM32_ADC_SQR2_OFFSET), - adc_getreg(priv, STM32_ADC_SQR3_OFFSET)); - -#if defined(STM32_ADC_SQR5_OFFSET) - ainfo("SQR4: 0x%08x SQR5: 0x%08x\n", - adc_getreg(priv, STM32_ADC_SQR4_OFFSET) - adc_getreg(priv, STM32_ADC_SQR5_OFFSET)); -#elif defined(STM32_ADC_SQR4_OFFSET) - ainfo("SQR4: 0x%08x\n", adc_getreg(priv, STM32_ADC_SQR4_OFFSET)); -#endif - -#if defined(HAVE_IP_ADC_V2) || (defined(HAVE_IP_ADC_V1) && !defined(HAVE_BASIC_ADC)) - ainfo("CCR: 0x%08x\n", adccmn_getreg(priv, STM32_ADC_CCR_OFFSET)); -#endif + adc_dumpregs(priv); } /**************************************************************************** @@ -2330,17 +2750,21 @@ static void adc_reset_hsi_disable(FAR struct adc_dev_s *dev) static int adc_setup(FAR struct adc_dev_s *dev) { +#if !defined(CONFIG_STM32_ADC_NOIRQ) || defined(HAVE_ADC_CMN_DATA) FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - int ret; +#endif + int ret = OK; /* Attach the ADC interrupt */ +#ifndef CONFIG_STM32_ADC_NOIRQ ret = irq_attach(priv->irq, priv->isr, NULL); if (ret < 0) { ainfo("irq_attach failed: %d\n", ret); return ret; } +#endif /* Make sure that the ADC device is in the powered up, reset state */ @@ -2348,8 +2772,18 @@ static int adc_setup(FAR struct adc_dev_s *dev) /* Enable the ADC interrupt */ +#ifndef CONFIG_STM32_ADC_NOIRQ ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq); up_enable_irq(priv->irq); +#endif + +#ifdef HAVE_ADC_CMN_DATA + /* Increase instances counter */ + + adccmn_lock(priv, true); + priv->cmn->initialized += 1; + adccmn_lock(priv, false); +#endif return ret; } @@ -2371,19 +2805,45 @@ static void adc_shutdown(FAR struct adc_dev_s *dev) { FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + /* Disable ADC */ + adc_enable(priv, false); + #ifdef HAVE_HSI_CONTROL adc_enable_hsi(false); #endif +#ifndef CONFIG_STM32_ADC_NOIRQ /* Disable ADC interrupts and detach the ADC interrupt handler */ up_disable_irq(priv->irq); irq_detach(priv->irq); +#endif - /* Disable and reset the ADC module */ +#ifdef HAVE_ADC_CMN_DATA + adccmn_lock(priv, true); - adc_rccreset(priv, true); + if (priv->cmn->initialized <= 1) +#endif + { + /* Disable and reset the ADC module. + * + * NOTE: The ADC block will be reset to its reset state only if all + * ADC block instances are closed. This means that the closed ADC + * may not be reset which in turn may affect low-power applications. + * (But ADC is turned off here, is not that enough?) + */ + + adc_rccreset(priv, true); + } + +#ifdef HAVE_ADC_CMN_DATA + /* Decrease instances counter */ + + priv->cmn->initialized -= 1; + + adccmn_lock(priv, false); +#endif } /**************************************************************************** @@ -2520,6 +2980,132 @@ errout: } #endif +/**************************************************************************** + * Name: adc_extsel_set + ****************************************************************************/ + +#ifdef ADC_HAVE_EXTCFG +static int adc_extcfg_set(FAR struct adc_dev_s *dev, uint32_t extcfg) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + uint32_t exten = 0; + uint32_t extsel = 0; + uint32_t setbits = 0; + uint32_t clrbits = 0; + + /* Get EXTEN and EXTSEL from input */ + + exten = (extcfg & ADC_EXTREG_EXTEN_MASK); + extsel = (extcfg & ADC_EXTREG_EXTSEL_MASK); + + /* EXTSEL selection: These bits select the external event used + * to trigger the start of conversion of a regular group. NOTE: + * + * - The position with of the EXTSEL field varies from one STM32 MCU + * to another. + * - The width of the EXTSEL field varies from one STM32 MCU to another. + */ + + if (exten > 0) + { + setbits = (extsel | exten); + clrbits = (ADC_EXTREG_EXTEN_MASK | ADC_EXTREG_EXTSEL_MASK); + + ainfo("Initializing extsel = 0x%08x\n", extsel); + + /* Write register */ + + adc_modifyreg(priv, STM32_ADC_EXTREG_OFFSET, clrbits, setbits); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc_jextsel_set + ****************************************************************************/ + +#ifdef ADC_HAVE_JEXTCFG +static int adc_jextcfg_set(FAR struct adc_dev_s *dev, uint32_t jextcfg) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + uint32_t jexten = 0; + uint32_t jextsel = 0; + uint32_t setbits = 0; + uint32_t clrbits = 0; + + /* Get JEXTEN and JEXTSEL from input */ + + jexten = (jextcfg & ADC_JEXTREG_JEXTEN_MASK); + jextsel = (jextcfg & ADC_JEXTREG_JEXTSEL_MASK); + + /* JEXTSEL selection: These bits select the external event used + * to trigger the start of conversion of a injected group. NOTE: + * + * - The position with of the JEXTSEL field varies from one STM32 MCU + * to another. + * - The width of the JEXTSEL field varies from one STM32 MCU to another. + */ + + if (jexten > 0) + { + setbits = (jexten | jextsel); + clrbits = (ADC_JEXTREG_JEXTEN_MASK | ADC_JEXTREG_JEXTSEL_MASK); + + ainfo("Initializing jextsel = 0x%08x\n", jextsel); + + /* Write register */ + + adc_modifyreg(priv, STM32_ADC_JEXTREG_OFFSET, clrbits, setbits); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: adc_dumpregs + ****************************************************************************/ + +static void adc_dumpregs(FAR struct stm32_dev_s *priv) +{ + UNUSED(priv); + +#if defined(HAVE_IP_ADC_V2) + ainfo("ISR: 0x%08x CR: 0x%08x CFGR1: 0x%08x\n", + adc_getreg(priv, STM32_ADC_ISR_OFFSET), + adc_getreg(priv, STM32_ADC_CR_OFFSET), + adc_getreg(priv, STM32_ADC_CFGR1_OFFSET)); +#else + ainfo("SR: 0x%08x CR1: 0x%08x CR2: 0x%08x\n", + adc_getreg(priv, STM32_ADC_SR_OFFSET), + adc_getreg(priv, STM32_ADC_CR1_OFFSET), + adc_getreg(priv, STM32_ADC_CR2_OFFSET)); +#endif + + ainfo("SQR1: 0x%08x SQR2: 0x%08x SQR3: 0x%08x\n", + adc_getreg(priv, STM32_ADC_SQR1_OFFSET), + adc_getreg(priv, STM32_ADC_SQR2_OFFSET), + adc_getreg(priv, STM32_ADC_SQR3_OFFSET)); + +#if defined(STM32_ADC_SQR5_OFFSET) + ainfo("SQR4: 0x%08x SQR5: 0x%08x\n", + adc_getreg(priv, STM32_ADC_SQR4_OFFSET) + adc_getreg(priv, STM32_ADC_SQR5_OFFSET)); +#elif defined(STM32_ADC_SQR4_OFFSET) + ainfo("SQR4: 0x%08x\n", adc_getreg(priv, STM32_ADC_SQR4_OFFSET)); +#endif + +#ifdef ADC_HAVE_INJECTED + ainfo("JSQR: 0x%08x\n", adc_getreg(priv, STM32_ADC_JSQR_OFFSET)); +#endif + +#if defined(HAVE_IP_ADC_V2) || (defined(HAVE_IP_ADC_V1) && !defined(HAVE_BASIC_ADC)) + ainfo("CCR: 0x%08x\n", adccmn_getreg(priv, STM32_ADC_CCR_OFFSET)); +#endif +} + /**************************************************************************** * Name: adc_enable_vbat_channel * @@ -2840,10 +3426,10 @@ static uint32_t adc_sqrbits(FAR struct stm32_dev_s *priv, int first, int last, int i; for (i = first - 1; - i < priv->nchannels && i < last; + i < priv->rnchannels && i < last; i++, offset += ADC_SQ_OFFSET) { - bits |= (uint32_t)priv->chanlist[i] << offset; + bits |= (uint32_t)priv->r_chanlist[i] << offset; } return bits; @@ -2873,19 +3459,19 @@ static int adc_set_ch(FAR struct adc_dev_s *dev, uint8_t ch) if (ch == 0) { priv->current = 0; - priv->nchannels = priv->cchannels; + priv->rnchannels = priv->cr_channels; } else { - for (i = 0; i < priv->cchannels && priv->chanlist[i] != ch - 1; i++); + for (i = 0; i < priv->cr_channels && priv->r_chanlist[i] != ch - 1; i++); - if (i >= priv->cchannels) + if (i >= priv->cr_channels) { return -ENODEV; } priv->current = i; - priv->nchannels = 1; + priv->rnchannels = 1; } #ifdef STM32_ADC_SQR5_OFFSET @@ -2904,13 +3490,47 @@ static int adc_set_ch(FAR struct adc_dev_s *dev, uint8_t ch) bits = adc_sqrbits(priv, ADC_SQR2_FIRST, ADC_SQR2_LAST, ADC_SQR2_SQ_OFFSET); adc_modifyreg(priv, STM32_ADC_SQR2_OFFSET, ~ADC_SQR2_RESERVED, bits); - bits = ((uint32_t)priv->nchannels - 1) << ADC_SQR1_L_SHIFT; + bits = ((uint32_t)priv->rnchannels - 1) << ADC_SQR1_L_SHIFT; bits |= adc_sqrbits(priv, ADC_SQR1_FIRST, ADC_SQR1_LAST, ADC_SQR1_SQ_OFFSET); adc_modifyreg(priv, STM32_ADC_SQR1_OFFSET, ~ADC_SQR1_RESERVED, bits); return OK; } +#ifdef ADC_HAVE_INJECTED + +/**************************************************************************** + * Name: adc_inj_set_ch + ****************************************************************************/ + +static int adc_inj_set_ch(FAR struct adc_dev_s *dev, uint8_t ch) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + uint32_t clrbits; + uint32_t setbits; + int i; + + /* Configure injected sequence length */ + + setbits = ADC_JSQR_JL(priv->cj_channels); + clrbits = ADC_JEXTREG_JEXTSEL_MASK | ADC_JSQR_JL_MASK; + + /* Configure injected channels */ + + for (i = 0 ; i < priv->cj_channels; i += 1) + { + setbits |= priv->j_chanlist[i] << (ADC_JSQR_JSQ1_SHIFT + + ADC_JSQR_JSQ_SHIFT * i); + } + + /* Write register */ + + adc_modifyreg(priv, STM32_ADC_JSQR_OFFSET, clrbits, setbits); + + return OK; +} +#endif + /**************************************************************************** * Name: adc_ioctl * @@ -2935,10 +3555,51 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) { case ANIOC_TRIGGER: { - adc_startconv(priv, true); + /* Start regular conversion if regular channels configured */ + + if (priv->cr_channels > 0) + { + adc_reg_startconv(priv, true); + } + +#ifdef ADC_HAVE_INJECTED + /* Start injected conversion if injected channels configured */ + + if (priv->cj_channels > 0) + { + adc_inj_startconv(priv, true); + } +#endif + break; } + case IO_TRIGGER_REG: + { + /* Start regular conversion if regular channels configured */ + + if (priv->cr_channels > 0) + { + adc_reg_startconv(priv, true); + } + + break; + } + +#ifdef ADC_HAVE_INJECTED + case IO_TRIGGER_INJ: + { + /* Start injected conversion if injected channels configured */ + + if (priv->cj_channels > 0) + { + adc_inj_startconv(priv, true); + } + + break; + } +#endif + case IO_ENABLE_DISABLE_AWDIE: case IO_ENABLE_DISABLE_EOCIE: case IO_ENABLE_DISABLE_JEOCIE: @@ -3014,14 +3675,14 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) #ifdef CONFIG_ADC if (ch) { - /* Clear fifo */ + /* Clear fifo if upper-half driver enabled */ dev->ad_recv.af_head = 0; dev->ad_recv.af_tail = 0; } #endif - adc_startconv(priv, true); + adc_reg_startconv(priv, true); break; } @@ -3036,6 +3697,8 @@ static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) return ret; } +#ifndef CONFIG_STM32_ADC_NOIRQ + /**************************************************************************** * Name: adc_interrupt * @@ -3097,7 +3760,7 @@ static int adc_interrupt(FAR struct adc_dev_s *dev) */ DEBUGASSERT(priv->cb->au_receive != NULL); - priv->cb->au_receive(dev, priv->chanlist[priv->current], data); + priv->cb->au_receive(dev, priv->r_chanlist[priv->current], data); } /* Set the channel number of the next channel that will complete @@ -3106,7 +3769,7 @@ static int adc_interrupt(FAR struct adc_dev_s *dev) priv->current++; - if (priv->current >= priv->nchannels) + if (priv->current >= priv->rnchannels) { /* Restart the conversion sequence from the beginning */ @@ -3209,6 +3872,7 @@ static int adc3_interrupt(int irq, FAR void *context, FAR void *arg) static int adc4_interrupt(int irq, FAR void *context, FAR void *arg) { adc_interrupt(&g_adcdev4); + return OK; } #endif @@ -3243,11 +3907,246 @@ static int adc123_interrupt(int irq, FAR void *context, FAR void *arg) return OK; } #endif +#endif /* CONFIG_STM32_ADC_NOIRQ */ + +#ifdef CONFIG_STM32_ADC_LL_OPS /**************************************************************************** - * Public Functions + * Name: adc_intack ****************************************************************************/ +static void adc_intack(FAR struct stm32_adc_dev_s *dev, uint32_t source) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + + /* Clear pending interrupts */ + +#ifdef HAVE_IP_ADC_V2 + /* Cleared by writing 1 to it */ + + adc_putreg(priv, STM32_ADC_ISR_OFFSET, (source & ADC_ISR_ALLINTS)); +#else + /* Cleared by writing 0 to it */ + + adc_modifyreg(priv, STM32_ADC_ISR_OFFSET, (source & ADC_ISR_ALLINTS), 0); +#endif +} + +/**************************************************************************** + * Name: adc_inten + ****************************************************************************/ + +static void adc_inten(FAR struct stm32_adc_dev_s *dev, uint32_t source) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + + /* Enable interrupts */ + + adc_modifyreg(priv, STM32_ADC_IER_OFFSET, 0, (source & ADC_IER_ALLINTS)); +} + +/**************************************************************************** + * Name: adc_intdis + ****************************************************************************/ + +static void adc_intdis(FAR struct stm32_adc_dev_s *dev, uint32_t source) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + + /* Disable interrupts */ + + adc_modifyreg(priv, STM32_ADC_IER_OFFSET, (source & ADC_IER_ALLINTS), 0); +} + +/**************************************************************************** + * Name: adc_ackget + ****************************************************************************/ + +static uint32_t adc_intget(FAR struct stm32_adc_dev_s *dev) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + uint32_t regval; + uint32_t pending; + + regval = adc_getreg(priv, STM32_ADC_ISR_OFFSET); + pending = regval & ADC_ISR_ALLINTS; + + return pending; +} + +/**************************************************************************** + * Name: adc_regget + ****************************************************************************/ + +static uint32_t adc_regget(FAR struct stm32_adc_dev_s *dev) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + + return adc_getreg(priv, STM32_ADC_DR_OFFSET) & ADC_DR_RDATA_MASK; +} + +/**************************************************************************** + * Name: adc_llops_reg_startconv + ****************************************************************************/ + +static void adc_llops_reg_startconv(FAR struct stm32_adc_dev_s *dev, bool enable) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + + adc_reg_startconv(priv, enable); +} + +/**************************************************************************** + * Name: adc_regbufregister + ****************************************************************************/ + +#ifdef ADC_HAVE_DMA +static int adc_regbufregister(FAR struct stm32_adc_dev_s *dev, uint16_t *buffer, + uint8_t len) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + + stm32_dmasetup(priv->dma, + priv->base + STM32_ADC_DR_OFFSET, + (uint32_t)buffer, + len, + ADC_DMA_CONTROL_WORD); + + /* No DMA callback */ + + stm32_dmastart(priv->dma, NULL, dev, false); + + return OK; +} +#endif /* ADC_HAVE_DMA */ + +/**************************************************************************** + * Name: adc_inj_get + ****************************************************************************/ + +#ifdef ADC_HAVE_INJECTED +static uint32_t adc_injget(FAR struct stm32_adc_dev_s *dev, uint8_t chan) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + uint32_t regval = 0; + + if (chan > priv->cj_channels-1) + { + /* REVISIT: return valute with MSB set to indicate error ? */ + + goto errout; + } + + regval = adc_getreg(priv, STM32_ADC_JDR1_OFFSET+4*(chan)) & ADC_JDR_JDATA_MASK; + +errout: + return regval; +} + +/**************************************************************************** + * Name: adc_llops_inj_startconv + ****************************************************************************/ + +static void adc_llops_inj_startconv(FAR struct stm32_adc_dev_s *dev, bool enable) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + + adc_inj_startconv(priv, enable); +} + +#endif /* ADC_HAVE_INJECTED */ + +/**************************************************************************** + * Name: adc_sampletime_write + * + * Description: + * Writes previously defined values into ADC_SMPRx registers. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME +static void adc_sampletime_write(FAR struct stm32_adc_dev_s *dev) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + uint32_t value = 0; + uint8_t i; + uint8_t shift; + + /* Sampling time individually for each channel. + * It's different for families. + */ + + for (i = 0, shift = 0; i < priv->adc_channels; i++) + { + value |= priv->sample_rate[i] << (shift * 3); + switch (i) + { +#if defined(STM32_ADC_SMPR0_OFFSET) && defined(STM32_ADC_SMPR3_OFFSET) + case 9: + { + adc_putreg(priv, STM32_ADC_SMPR3_OFFSET, value); + shift = 0; + value = 0; + break; + } + + case 19: + { + adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, value); + shift = 0; + value = 0; + break; + } + + case 29: + { + adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, value); + shift = 0; + value = 0; + break; + } + + case (ADC_CHANNELS_NUMBER - 1): + { + adc_putreg(priv, STM32_ADC_SMPR0_OFFSET, value); + shift = 0; + value = 0; + break; + } + +#elif defined(STM32_ADC_SMPR1_OFFSET) && defined(STM32_ADC_SMPR2_OFFSET) + case (ADC_CHANNELS_NUMBER - 1): + { + adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, value); + shift = 0; + value = 0; + break; + } + + case 9: + { + adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, value); + shift = 0; + value = 0; + break; + } +#else +# error "Not supported SMPRx configuration" +#endif + + default: + { + shift++; + break; + } + } + } +} + /**************************************************************************** * Name: adc_change_sample_time * @@ -3269,11 +4168,10 @@ static int adc123_interrupt(int irq, FAR void *context, FAR void *arg) * ****************************************************************************/ -#ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME -void stm32_adcchange_sample_time(FAR struct adc_dev_s *dev, - FAR struct adc_sample_time_s *time_samples) +void adc_sampletime_set(FAR struct stm32_adc_dev_s *dev, + FAR struct adc_sample_time_s *time_samples) { - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; uint8_t ch_index; uint8_t i; @@ -3299,7 +4197,24 @@ void stm32_adcchange_sample_time(FAR struct adc_dev_s *dev, } } } -#endif +#endif /* CONFIG_STM32_ADC_CHANGE_SAMPLETIME */ + +/**************************************************************************** + * Name: adc_llops_dumpregs + ****************************************************************************/ + +static void adc_llops_dumpregs(FAR struct stm32_adc_dev_s *dev) +{ + FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; + + adc_dumpregs(priv); +} + +#endif /* CONFIG_STM32_ADC_LL_OPS */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ /**************************************************************************** * Name: stm32_adcinitialize @@ -3307,20 +4222,42 @@ void stm32_adcchange_sample_time(FAR struct adc_dev_s *dev, * Description: * Initialize the ADC. * - * The logic is, save nchannels : # of channels (conversions) in ADC_SQR1_L - * Then, take the chanlist array and store it in the SQR Regs, - * chanlist[0] -> ADC_SQR3_SQ1 - * chanlist[1] -> ADC_SQR3_SQ2 - * ... - * chanlist[15]-> ADC_SQR1_SQ16 + * The logic allow initialize ADC regular and injected channels. * - * up to - * chanlist[nchannels] + * The number of injected channels for given ADC is selected from Kconfig + * with CONFIG_STM32_ADCx_INJECTED_CHAN definitions + * + * The number of regular channels is obtained from the equation: + * + * cr_channels = channels - cj_channels + * + * where: + * cr_channels - regular channels + * cj_channels - injected channels + * channels - this function parameter + * + * The chanlist array store both regular channels and injected channels + * configuration so that regular channels are the first in order: + * + * # regular channels start from here + * chanlist[0] -> ADC_SQRx_SQ1 + * chanlist[1] -> ADC_SQRx_SQ2 + * ... + * # injected channels start from here + * chanlist[channels - (y - 1)] -> ADC_JSQR_JSQ1 + * ... + * chanlist[channels] -> ADC_JSQR_ISQy + * + * where: + * y = CONFIG_STM32_ADCx_INJECTED_CHAN, and y > 0 + * + * If CONFIG_STM32_ADCx_INJECTED_CHAN = 0, then all channels from chanlist + * are regular channels. * * Input Parameters: - * intf - Could be {1,2,3} for ADC1, ADC2, or ADC3 - * chanlist - The list of channels - * cchannels - Number of channels + * intf - Could be {1,2,3,4} for ADC1, ADC2, ADC3 or ADC4 + * chanlist - The list of channels (regular + injected) + * channels - Number of channels (regular + injected) * * Returned Value: * Valid ADC device structure reference on succcess; a NULL on failure @@ -3328,48 +4265,109 @@ void stm32_adcchange_sample_time(FAR struct adc_dev_s *dev, ****************************************************************************/ struct adc_dev_s *stm32_adcinitialize(int intf, FAR const uint8_t *chanlist, - int cchannels) + int channels) { FAR struct adc_dev_s *dev; FAR struct stm32_dev_s *priv; - - ainfo("intf: %d cchannels: %d\n", intf, cchannels); + uint8_t cr_channels = 0; + uint8_t cj_channels = 0; +#ifdef ADC_HAVE_INJECTED + FAR uint8_t *j_chanlist = NULL; +#endif switch (intf) { #ifdef CONFIG_STM32_ADC1 case 1: - ainfo("ADC1 selected\n"); - dev = &g_adcdev1; - break; -#endif + { + ainfo("ADC1 selected\n"); + dev = &g_adcdev1; + cj_channels = CONFIG_STM32_ADC1_INJECTED_CHAN; + cr_channels = channels - cj_channels; +# ifdef ADC_HAVE_INJECTED + if (cj_channels > 0) + { + j_chanlist = (FAR uint8_t *)chanlist + cr_channels; + } +# endif + break; + } +#endif /* CONFIG_STM32_ADC1 */ #ifdef CONFIG_STM32_ADC2 case 2: - ainfo("ADC2 selected\n"); - dev = &g_adcdev2; - break; -#endif + { + ainfo("ADC2 selected\n"); + dev = &g_adcdev2; + cj_channels = CONFIG_STM32_ADC2_INJECTED_CHAN; + cr_channels = channels - cj_channels; +# ifdef ADC_HAVE_INJECTED + if (cj_channels > 0) + { + j_chanlist = (FAR uint8_t *)chanlist + cr_channels; + } +# endif + break; + } +#endif /* CONFIG_STM32_ADC2 */ #ifdef CONFIG_STM32_ADC3 case 3: - ainfo("ADC3 selected\n"); - dev = &g_adcdev3; - break; -#endif + { + ainfo("ADC3 selected\n"); + dev = &g_adcdev3; + cj_channels = CONFIG_STM32_ADC3_INJECTED_CHAN; + cr_channels = channels - cj_channels; +# ifdef ADC_HAVE_INJECTED + if (cj_channels > 0) + { + j_chanlist = (FAR uint8_t *)chanlist + cr_channels; + } +# endif + break; + } +#endif /* CONFIG_STM32_ADC3 */ #ifdef CONFIG_STM32_ADC4 case 4: - ainfo("ADC4 selected\n"); - dev = &g_adcdev4; - break; -#endif + { + ainfo("ADC4 selected\n"); + dev = &g_adcdev4; + cj_channels = CONFIG_STM32_ADC4_INJECTED_CHAN; + cr_channels = channels - cj_channels; +# ifdef ADC_HAVE_INJECTED + if (cj_channels > 0) + { + j_chanlist = (FAR uint8_t *)chanlist + cr_channels; + } +# endif + break; + } +#endif /* CONFIG_STM32_ADC4 */ default: - aerr("ERROR: No ADC interface defined\n"); - return NULL; + { + aerr("ERROR: No ADC interface defined\n"); + return NULL; + } } /* Configure the selected ADC */ priv = (FAR struct stm32_dev_s *)dev->ad_priv; + /* Configure regular channels */ + + DEBUGASSERT(cr_channels <= ADC_MAX_SAMPLES); + + priv->cr_channels = cr_channels; + memcpy(priv->r_chanlist, chanlist, cr_channels); + +#ifdef ADC_HAVE_INJECTED + /* Configure injected channels */ + + DEBUGASSERT(cj_channels <= ADC_INJ_MAX_SAMPLES); + + priv->cj_channels = cj_channels; + memcpy(priv->j_chanlist, j_chanlist, cj_channels); +#endif + #ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME /* Assign default values for the sample time table */ @@ -3377,12 +4375,26 @@ struct adc_dev_s *stm32_adcinitialize(int intf, FAR const uint8_t *chanlist, priv->adc_channels = ADC_CHANNELS_NUMBER; #endif - DEBUGASSERT(cchannels <= ADC_MAX_SAMPLES); - +#ifndef CONFIG_STM32_ADC_NOIRQ priv->cb = NULL; - priv->cchannels = cchannels; +#endif - memcpy(priv->chanlist, chanlist, cchannels); +#ifdef ADC_HAVE_INJECTED + ainfo("intf: %d cr_channels: %d, cj_channels: %d\n", + intf, priv->cr_channels, priv->cj_channels); +#else + ainfo("intf: %d cr_channels: %d\n", intf, priv->cr_channels); +#endif + +#ifdef HAVE_ADC_CMN_DATA + /* Initialize the ADC common data semaphore. + * + * REVISIT: This will be done several times for each initialzied ADC in + * the ADC block. + */ + + nxsem_init(&priv->cmn->lock, 0, 1); +#endif return dev; } diff --git a/arch/arm/src/stm32/stm32_adc.h b/arch/arm/src/stm32/stm32_adc.h index 2a06971080..59c000f3f3 100644 --- a/arch/arm/src/stm32/stm32_adc.h +++ b/arch/arm/src/stm32/stm32_adc.h @@ -303,6 +303,15 @@ # undef ADC4_HAVE_DMA #endif +/* Injected channels support */ + +#if (defined(CONFIG_STM32_ADC1) && (CONFIG_STM32_ADC1_INJECTED_CHAN > 0)) || \ + (defined(CONFIG_STM32_ADC2) && (CONFIG_STM32_ADC2_INJECTED_CHAN > 0)) || \ + (defined(CONFIG_STM32_ADC3) && (CONFIG_STM32_ADC3_INJECTED_CHAN > 0)) || \ + (defined(CONFIG_STM32_ADC4) && (CONFIG_STM32_ADC4_INJECTED_CHAN > 0)) +# define ADC_HAVE_INJECTED +#endif + /* Timer configuration: If a timer trigger is specified, then get * information about the timer. * @@ -1294,6 +1303,8 @@ # define ADC2_JEXTSEL_HRTTRG4 ADC12_JSQR_JEXTSEL_HRT1TRG4 #endif +/* EXTSEL configuration *****************************************************/ + #if defined(CONFIG_STM32_TIM1_ADC1) # if CONFIG_STM32_ADC1_TIMTRIG == 0 # define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC1 @@ -1454,14 +1465,6 @@ # define ADC1_EXTSEL_VALUE ADC1_EXTSEL_HRTTRG3 #endif -#if defined(CONFIG_STM32_HRTIM_ADC1_TRG2) -# define ADC1_JEXTSEL_VALUE ADC1_JEXTSEL_HRTTRG2 -#elif defined(CONFIG_STM32_HRTIM_ADC1_TRG4) -# define ADC1_JEXTSEL_VALUE ADC1_JEXTSEL_HRTTRG4 -#else -# define ADC1_JEXTSEL_VALUE 0 -#endif - #if defined(CONFIG_STM32_TIM1_ADC2) # if CONFIG_STM32_ADC2_TIMTRIG == 0 # define ADC2_EXTSEL_VALUE ADC2_EXTSEL_T1CC1 @@ -1580,14 +1583,6 @@ # define ADC2_EXTSEL_VALUE ADC1_EXTSEL_HRTTRG3 #endif -#if defined(CONFIG_STM32_HRTIM_ADC2_TRG2) -# define ADC2_JEXTSEL_VALUE ADC2_JEXTSEL_HRTTRG2 -#elif defined(CONFIG_STM32_HRTIM_ADC2_TRG4) -# define ADC2_JEXTSEL_VALUE ADC2_JEXTSEL_HRTTRG4 -#else -# define ADC2_JEXTSEL_VALUE 0 -#endif - #if defined(CONFIG_STM32_TIM1_ADC3) # if CONFIG_STM32_ADC3_TIMTRIG == 0 # define ADC3_EXTSEL_VALUE ADC3_EXTSEL_T1CC1 @@ -1844,6 +1839,99 @@ # endif #endif +/* JEXTSEL configuration ****************************************************/ + +/* TODO: ADC1 JEXTSEL trigger */ + +#if defined(CONFIG_STM32_HRTIM_ADC1_TRG2) +# define ADC1_JEXTSEL_VALUE ADC1_JEXTSEL_HRTTRG2 +#elif defined(CONFIG_STM32_HRTIM_ADC1_TRG4) +# define ADC1_JEXTSEL_VALUE ADC1_JEXTSEL_HRTTRG4 +#else +# undef ADC1_JEXTSEL_VALUE +#endif + +/* TODO: ADC2 JEXTSEL trigger */ + +#if defined(CONFIG_STM32_HRTIM_ADC2_TRG2) +# define ADC2_JEXTSEL_VALUE ADC2_JEXTSEL_HRTTRG2 +#elif defined(CONFIG_STM32_HRTIM_ADC2_TRG4) +# define ADC2_JEXTSEL_VALUE ADC2_JEXTSEL_HRTTRG4 +#else +# undef ADC2_JEXTSEL_VALUE +#endif + +/* TODO: ADC3 JEXTSEL trigger */ + +#undef ADC3_JEXTSEL_VALUE + +/* TODO: ADC4 JEXTSEL trigger */ + +#undef ADC4_JEXTSEL_VALUE + +/* ADC interrupts ***********************************************************/ + +#if defined(HAVE_IP_ADC_V1) +# define ADC_ISR_EOC ADC_SR_EOC +# define ADC_IER_EOC ADC_CR1_EOCIE +# define ADC_ISR_AWD ADC_SR_AWD +# define ADC_IER_AWD ADC_CR1_AWDIE +# define ADC_ISR_JEOC ADC_SR_JEOC +# define ADC_IER_JEOC ADC_CR1_JEOCIE +# define ADC_ISR_JEOS 0 /* No JEOS */ +# define ADC_IER_JEOS 0 /* No JEOS */ +# ifdef HAVE_BASIC_ADC +# define ADC_ISR_OVR 0 +# define ADC_IER_OVR 0 +# else +# define ADC_ISR_OVR ADC_SR_OVR +# define ADC_IER_OVR ADC_CR1_OVRIE +# endif +#elif defined(HAVE_IP_ADC_V2) +# define ADC_ISR_EOC ADC_INT_EOC +# define ADC_IER_EOC ADC_INT_EOC +# define ADC_ISR_AWD ADC_INT_AWD1 +# define ADC_IER_AWD ADC_INT_AWD1 +# define ADC_ISR_JEOC ADC_INT_JEOC +# define ADC_IER_JEOC ADC_INT_JEOC +# define ADC_ISR_OVR ADC_INT_OVR +# define ADC_IER_OVR ADC_INT_OVR +# define ADC_ISR_JEOS ADC_INT_JEOS +# define ADC_IER_JEOS ADC_INT_JEOS +#endif + +#define ADC_ISR_ALLINTS (ADC_ISR_EOC | ADC_ISR_AWD | ADC_ISR_JEOC | \ + ADC_ISR_JEOS | ADC_ISR_OVR) +#define ADC_IER_ALLINTS (ADC_IER_EOC | ADC_IER_AWD | ADC_IER_JEOC | \ + ADC_IER_JEOS | ADC_IER_OVR) + +/* Low-level ops helpers ****************************************************/ + +#define ADC_INT_ACK(adc, source) \ + (adc)->llops->int_ack(adc, source) +#define ADC_INT_GET(adc) \ + (adc)->llops->int_get(adc) +#define ADC_INT_ENABLE(adc, source) \ + (adc)->llops->int_en(adc, source) +#define ADC_INT_DISABLE(adc, source) \ + (adc)->llops->int_dis(adc, source) +#define ADC_REGDATA_GET(adc) \ + (adc)->llops->val_get(adc) +#define ADC_REGBUF_REGISTER(adc, buffer, len) \ + (adc)->llops->regbuf_reg(adc, buffer, len) +#define ADC_REG_STARTCONV(adc, state) \ + (adc)->llops->reg_startconv(adc, state) +#define ADC_INJ_STARTCONV(adc, state) \ + (adc)->llops->inj_startconv(adc, state) +#define ADC_INJDATA_GET(adc, chan) \ + (adc)->llops->inj_get(adc, chan) +#define ADC_SAMPLETIME_SET(adc, time_samples) \ + (adc)->llops->stime_set(adc, time_samples) +#define ADC_SAMPLETIME_WRITE(adc) \ + (adc)->llops->stime_write(adc) +#define ADC_DUMP_REGS(adc) \ + (adc)->llops->dump_regs(adc) + /************************************************************************************ * Public Types ************************************************************************************/ @@ -1870,6 +1958,10 @@ enum adc_io_cmds_e IO_STOP_ADC, IO_START_ADC, IO_START_CONV, + IO_TRIGGER_REG, +#ifdef ADC_HAVE_INJECTED + IO_TRIGGER_INJ, +#endif #ifdef HAVE_ADC_POWERDOWN IO_ENABLE_DISABLE_PDI, IO_ENABLE_DISABLE_PDD, @@ -1887,6 +1979,8 @@ enum stm32_adc_resoluton_e ADC_RESOLUTION_6BIT = 3 /* 6 bit */ }; +#ifdef CONFIG_STM32_ADC_LL_OPS + #ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME /* Channel and sample time pair */ @@ -1895,16 +1989,7 @@ typedef struct adc_channel_s { uint8_t channel:5; - /* Sampling time individually for each channel - * 000: 4 cycles - * 001: 9 cycles - * 010: 16 cycles - * 011: 24 cycles - * 100: 48 cycles - * 101: 96 cycles - * 110: 192 cycles - * 111: 384 cycles - selected for all channels - */ + /* Sampling time individually for each channel. It differs between families */ uint8_t sample_time:3; } adc_channel_t; @@ -1915,19 +2000,13 @@ typedef struct adc_channel_s struct adc_sample_time_s { - adc_channel_t *channel; /* Array of channels */ - uint8_t channels_nbr:5; /* Number of channels in array */ - bool all_same:1; /* All channels will get the - * same value of the sample time */ - uint8_t all_ch_sample_time:3; /* Sample time for all channels */ + adc_channel_t *channel; /* Array of channels */ + uint8_t channels_nbr:5; /* Number of channels in array */ + bool all_same:1; /* All channels will get the + * same value of the sample time */ + uint8_t all_ch_sample_time:3; /* Sample time for all channels */ }; -#endif - -#ifdef CONFIG_STM32_STM32F33XX - -/* At this moment only for STM32F33XX family */ - -#ifdef CONFIG_STM32_ADC_NOIRQ +#endif /* CONFIG_STM32_ADC_CHANGE_SAMPLETIME */ /* This structure provides the publicly visable representation of the * "lower-half" ADC driver structure. @@ -1937,14 +2016,15 @@ struct stm32_adc_dev_s { /* Publicly visible portion of the "lower-half" ADC driver structure */ - FAR const struct stm32_adc_ops_s *ops; + FAR const struct stm32_adc_ops_s *llops; /* Require cast-compatibility with private "lower-half" ADC strucutre */ }; +/* Low-level operations for ADC */ + struct stm32_adc_ops_s { - /* Acknowledge interrupts */ void (*int_ack)(FAR struct stm32_adc_dev_s *dev, uint32_t source); @@ -1969,13 +2049,35 @@ struct stm32_adc_ops_s int (*regbuf_reg)(FAR struct stm32_adc_dev_s *dev, uint16_t *buffer, uint8_t len); + /* Start/stop regular conversion */ + + void (*reg_startconv)(FAR struct stm32_adc_dev_s *dev, bool state); + +#ifdef ADC_HAVE_INJECTED /* Get current ADC injected data register */ uint32_t (*inj_get)(FAR struct stm32_adc_dev_s *dev, uint8_t chan); + + /* Start/stop injected conversion */ + + void (*inj_startconv)(FAR struct stm32_adc_dev_s *dev, bool state); +#endif + +#ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME + /* Set ADC sample time */ + + void (*stime_set)(FAR struct stm32_adc_dev_s *dev, + FAR struct adc_sample_time_s *time_samples); + + /* Write ADC sample time */ + + void (*stime_write)(FAR struct stm32_adc_dev_s *dev); +#endif + + void (*dump_regs)(FAR struct stm32_adc_dev_s *dev); }; -#endif /* CONFIG_STM32_ADC_NOIRQ */ -#endif /* CONFIG_STM32_STM32F33XX */ +#endif /* CONFIG_STM32_ADC_LL_OPS */ /************************************************************************************ * Public Function Prototypes @@ -1994,12 +2096,12 @@ extern "C" * Name: stm32_adcinitialize * * Description: - * Initialize the ADC. + * Initialize the ADC. See stm32_adc.c for more details. * * Input Parameters: - * intf - Could be {1,2,3} for ADC1, ADC2, or ADC3 - * chanlist - The list of channels - * nchannels - Number of channels + * intf - Could be {1,2,3,4} for ADC1, ADC2, ADC3 or ADC4 + * chanlist - The list of channels (regular + injected) + * nchannels - Number of channels (regular + injected) * * Returned Value: * Valid can device structure reference on succcess; a NULL on failure @@ -2008,11 +2110,14 @@ extern "C" struct adc_dev_s; struct adc_dev_s *stm32_adcinitialize(int intf, FAR const uint8_t *chanlist, - int nchannels); + int channels); -#ifdef CONFIG_STM32_ADC_CHANGE_SAMPLETIME -void stm32_adcchange_sample_time(FAR struct adc_dev_s *dev, - FAR struct adc_sample_time_s *time_samples); +/************************************************************************************ + * Name: stm32_adc_llops_get + ************************************************************************************/ + +#ifdef CONFIG_STM32_ADC_LL_OPS +FAR const struct stm32_adc_ops_s *stm32_adc_llops_get(FAR struct adc_dev_s *dev); #endif #undef EXTERN diff --git a/arch/arm/src/stm32/stm32_dma.c b/arch/arm/src/stm32/stm32_dma.c index 64553a7d5c..6c0028aed7 100644 --- a/arch/arm/src/stm32/stm32_dma.c +++ b/arch/arm/src/stm32/stm32_dma.c @@ -53,13 +53,16 @@ * The STM32 F4 DMA differs from the F1 DMA primarily in that it adds the * concept of "streams" that are used to associate DMA sources with DMA * channels. + * + * TODO: use STM32 DMA IP version instead of chip faimily: + * - STM32 DMA IP core version 1 - F0, F1, F3, L1 + * - STM32 DMA IP core version 2 - F2, F4, F7, H7 */ #if defined(CONFIG_STM32_STM32L15XX) || defined(CONFIG_STM32_STM32F10XX) || \ - defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F37XX) + defined(CONFIG_STM32_STM32F30XX) || defined(CONFIG_STM32_STM32F33XX) || \ + defined(CONFIG_STM32_STM32F37XX) # include "stm32f10xxx_dma.c" -#elif defined(CONFIG_STM32_STM32F33XX) -# include "stm32f33xxx_dma.c" #elif defined(CONFIG_STM32_STM32F20XX) # include "stm32f20xxx_dma.c" #elif defined(CONFIG_STM32_STM32F4XXX) diff --git a/arch/arm/src/stm32/stm32_dma.h b/arch/arm/src/stm32/stm32_dma.h index 96ce90c4be..3dcf762089 100644 --- a/arch/arm/src/stm32/stm32_dma.h +++ b/arch/arm/src/stm32/stm32_dma.h @@ -347,12 +347,11 @@ void stm32_dmadump(DMA_HANDLE handle, const struct stm32_dmaregs_s *regs, # define stm32_dmadump(handle,regs,msg) #endif -#ifdef CONFIG_STM32_STM32F33XX - -/* At this moment only for STM32F33XX family */ - /* High performance, zero latency DMA interrupts need some additional * interfaces. + * + * TODO: For now the interface is different for STM32 DMAv1 and STM32 DMAv2. + * It should be unified somehow. */ #ifdef CONFIG_ARCH_HIPRI_INTERRUPT @@ -365,7 +364,11 @@ void stm32_dmadump(DMA_HANDLE handle, const struct stm32_dmaregs_s *regs, * ****************************************************************************/ +#if defined(HAVE_IP_DMA_V1) void stm32_dma_intack(unsigned int chndx, uint32_t isr); +#elif defined(HAVE_IP_DMA_V2) +void stm32_dma_intack(unsigned int controller, uint8_t stream, uint32_t isr); +#endif /**************************************************************************** * Name: stm32_dma_intget @@ -375,9 +378,13 @@ void stm32_dma_intack(unsigned int chndx, uint32_t isr); * ****************************************************************************/ +#if defined(HAVE_IP_DMA_V1) uint32_t stm32_dma_intget(unsigned int chndx); +#elif defined(HAVE_IP_DMA_V2) +uint8_t stm32_dma_intget(unsigned int controller, uint8_t stream); +#endif + #endif /* CONFIG_ARCH_HIPRI_INTERRUPT */ -#endif /* CONFIG_STM32_STM32F33XX */ #undef EXTERN #if defined(__cplusplus) diff --git a/arch/arm/src/stm32/stm32_hrtim.c b/arch/arm/src/stm32/stm32_hrtim.c index 6aaf38e739..57e26ad817 100644 --- a/arch/arm/src/stm32/stm32_hrtim.c +++ b/arch/arm/src/stm32/stm32_hrtim.c @@ -646,13 +646,13 @@ static int stm32_hrtim_ioctl(FAR struct file *filep, int cmd, unsigned long arg) /* HRTIM Register access */ -static void stm32_modifyreg32(unsigned int addr, uint32_t clrbits, - uint32_t setbits); static uint32_t hrtim_cmn_getreg(FAR struct stm32_hrtim_s *priv, uint32_t offset); static void hrtim_cmn_putreg(FAR struct stm32_hrtim_s *priv, uint32_t offset, uint32_t value); +#ifdef CONFIG_STM32_HRTIM_BURST static void hrtim_cmn_modifyreg(FAR struct stm32_hrtim_s *priv, uint32_t offset, uint32_t clrbits, uint32_t setbits); +#endif static void hrtim_tim_putreg(FAR struct stm32_hrtim_s *priv, uint8_t timer, uint32_t offset, uint32_t value); static void hrtim_tim_modifyreg(FAR struct stm32_hrtim_s *priv, uint8_t timer, @@ -671,8 +671,10 @@ static uint32_t hrtim_tim_getreg(FAR struct stm32_hrtim_s *priv, uint8_t timer, uint32_t offset); static FAR struct stm32_hrtim_tim_s *hrtim_tim_get(FAR struct stm32_hrtim_s *priv, uint8_t timer); +#if defined(CONFIG_STM32_HRTIM_PWM) || defined(CONFIG_STM32_HRTIM_FAULTS) static FAR struct stm32_hrtim_slave_priv_s *hrtim_slave_get(FAR struct stm32_hrtim_s *priv, uint8_t timer); +#endif static uint32_t hrtim_base_get(FAR struct stm32_hrtim_s *priv, uint8_t timer); /* Configuration */ @@ -764,8 +766,10 @@ static uint16_t hrtim_cmp_get(FAR struct hrtim_dev_s *dev, uint8_t timer, static uint64_t hrtim_fclk_get(FAR struct hrtim_dev_s *dev, uint8_t timer); static int hrtim_soft_update(FAR struct hrtim_dev_s *dev, uint8_t timer); static int hrtim_soft_reset(FAR struct hrtim_dev_s *dev, uint8_t timer); -static int hrtim_tim_freq_set(FAR struct hrtim_dev_s *hrtim, uint8_t timer, +static int hrtim_tim_freq_set(FAR struct hrtim_dev_s *dev, uint8_t timer, uint64_t freq); +static int hrtim_tim_enable(FAR struct hrtim_dev_s *dev, uint8_t timers, + bool state); static int hrtim_tim_reset_set(FAR struct stm32_hrtim_s *priv, uint8_t timer, uint64_t reset); static int hrtim_reset_config(FAR struct stm32_hrtim_s *priv); @@ -1585,6 +1589,7 @@ static const struct stm32_hrtim_ops_s g_hrtim1ops = .soft_update = hrtim_soft_update, .soft_reset = hrtim_soft_reset, .freq_set = hrtim_tim_freq_set, + .tim_enable = hrtim_tim_enable, #ifdef CONFIG_STM32_HRTIM_INTERRUPTS .irq_ack = hrtim_irq_ack, .irq_get = hrtim_irq_get, @@ -1699,28 +1704,6 @@ static int stm32_hrtim_ioctl(FAR struct file *filep, int cmd, unsigned long arg) #endif /* CONFIG_STM32_HRTIM_DISABLE_CHARDRV */ -/**************************************************************************** - * Name: stm32_modifyreg32 - * - * Description: - * Modify the value of a 32-bit register (not atomic). - * - * Input Parameters: - * addr - The address of the register - * clrbits - The bits to clear - * setbits - The bits to set - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void stm32_modifyreg32(unsigned int addr, uint32_t clrbits, - uint32_t setbits) -{ - putreg32((getreg32(addr) & ~clrbits) | setbits, addr); -} - /**************************************************************************** * Name: hrtim_cmn_getreg * @@ -1781,6 +1764,7 @@ static void hrtim_cmn_putreg(FAR struct stm32_hrtim_s *priv, uint32_t offset, * ****************************************************************************/ +#ifdef CONFIG_STM32_HRTIM_BURST static void hrtim_cmn_modifyreg(FAR struct stm32_hrtim_s *priv, uint32_t offset, uint32_t clrbits, uint32_t setbits) @@ -1788,6 +1772,7 @@ static void hrtim_cmn_modifyreg(FAR struct stm32_hrtim_s *priv, hrtim_cmn_putreg(priv, offset, (hrtim_cmn_getreg(priv, offset) & ~clrbits) | setbits); } +#endif /**************************************************************************** * Name: hrtim_tim_get @@ -1882,7 +1867,7 @@ static FAR struct stm32_hrtim_tim_s * * ****************************************************************************/ - +#if defined(CONFIG_STM32_HRTIM_PWM) || defined(CONFIG_STM32_HRTIM_FAULTS) static FAR struct stm32_hrtim_slave_priv_s * hrtim_slave_get(FAR struct stm32_hrtim_s *priv, uint8_t timer) { @@ -1913,6 +1898,7 @@ static FAR struct stm32_hrtim_slave_priv_s * errout: return slave; } +#endif /**************************************************************************** * Name: hrtim_base_get @@ -3253,6 +3239,7 @@ errout: /**************************************************************************** * Name: hrtim_output_rst_set ****************************************************************************/ + static int hrtim_output_rst_set(FAR struct hrtim_dev_s *dev, uint16_t output, uint32_t rst) { @@ -5256,7 +5243,7 @@ static int hrtim_soft_reset(FAR struct hrtim_dev_s *dev, uint8_t timer) * ****************************************************************************/ -static int hrtim_tim_freq_set(FAR struct hrtim_dev_s *hrtim, uint8_t timer, +static int hrtim_tim_freq_set(FAR struct hrtim_dev_s *dev, uint8_t timer, uint64_t freq) { uint64_t per = 0; @@ -5265,7 +5252,7 @@ static int hrtim_tim_freq_set(FAR struct hrtim_dev_s *hrtim, uint8_t timer, /* Get Timer period value for given frequency */ - fclk = HRTIM_FCLK_GET(hrtim, timer); + fclk = HRTIM_FCLK_GET(dev, timer); per = fclk/freq; if (per > HRTIM_PER_MAX) { @@ -5277,12 +5264,49 @@ static int hrtim_tim_freq_set(FAR struct hrtim_dev_s *hrtim, uint8_t timer, /* Set Timer period value */ - HRTIM_PER_SET(hrtim, timer, (uint16_t)per); + HRTIM_PER_SET(dev, timer, (uint16_t)per); - errout: +errout: return ret; } +/**************************************************************************** + * Name: hrtim_tim_enable + * + * Description: + * Enable/disable HRTIM timer counter (bulk operation) + * + * Returned Value: + * 0 on success, a negated errno value on failure + * + ****************************************************************************/ + +static int hrtim_tim_enable(FAR struct hrtim_dev_s *dev, uint8_t timers, + bool state) +{ + FAR struct stm32_hrtim_s *priv = (FAR struct stm32_hrtim_s *)dev->hd_priv; + uint32_t regval = 0; + + regval |= (timers & HRTIM_TIMERS_MASK) << HRTIM_MCR_TCEN_SHIFT; + + if (state == true) + { + /* Set bits */ + + hrtim_tim_modifyreg(priv, HRTIM_TIMER_MASTER, STM32_HRTIM_TIM_CR_OFFSET, + 0, regval); + } + else + { + /* Clear bits */ + + hrtim_tim_modifyreg(priv, HRTIM_TIMER_MASTER, STM32_HRTIM_TIM_CR_OFFSET, + regval, 0); + } + + return OK; +} + /**************************************************************************** * Name: hrtim_tim_reset_set * @@ -5727,33 +5751,36 @@ static int stm32_hrtimconfig(FAR struct stm32_hrtim_s *priv) } #endif +#ifndef CONFIG_STM32_HRTIM_NO_ENABLE_TIMERS /* Enable Master Timer */ -#ifdef CONFIG_STM32_HRTIM_MASTER +# ifdef CONFIG_STM32_HRTIM_MASTER regval |= HRTIM_MCR_MCEN; -#endif +# endif /* Enable Slave Timers */ -#ifdef CONFIG_STM32_HRTIM_TIMA +# ifdef CONFIG_STM32_HRTIM_TIMA regval |= HRTIM_MCR_TACEN; -#endif +# endif -#ifdef CONFIG_STM32_HRTIM_TIMB +# ifdef CONFIG_STM32_HRTIM_TIMB regval |= HRTIM_MCR_TBCEN; -#endif +# endif -#ifdef CONFIG_STM32_HRTIM_TIMC +# ifdef CONFIG_STM32_HRTIM_TIMC regval |= HRTIM_MCR_TCCEN; -#endif +# endif -#ifdef CONFIG_STM32_HRTIM_TIMD +# ifdef CONFIG_STM32_HRTIM_TIMD regval |= HRTIM_MCR_TDCEN; -#endif +# endif -#ifdef CONFIG_STM32_HRTIM_TIME +# ifdef CONFIG_STM32_HRTIM_TIME regval |= HRTIM_MCR_TECEN; -#endif +# endif + +#endif /* CONFIG_STM32_HRTIM_NO_ENABLE_TIMERS */ /* Write enable bits at once */ diff --git a/arch/arm/src/stm32/stm32_hrtim.h b/arch/arm/src/stm32/stm32_hrtim.h index bb5551455c..5deed1e514 100644 --- a/arch/arm/src/stm32/stm32_hrtim.h +++ b/arch/arm/src/stm32/stm32_hrtim.h @@ -232,6 +232,8 @@ (hrtim)->hd_ops->soft_reset(hrtim, timer) #define HRTIM_FREQ_SET(hrtim, timer,freq) \ (hrtim)->hd_ops->freq_set(hrtim, timer, freq) +#define HRTIM_TIM_ENABLE(hrtim, timers, state) \ + (hrtim)->hd_ops->tim_enable(hrtim, timers, state) #define HRTIM_OUTPUTS_ENABLE(hrtim, outputs, state) \ (hrtim)->hd_ops->outputs_enable(hrtim, outputs, state) #define HRTIM_OUTPUT_SET_SET(hrtim, output, set) \ @@ -278,7 +280,9 @@ enum stm32_hrtim_tim_e #ifdef CONFIG_STM32_HRTIM_TIME HRTIM_TIMER_TIME = (1<<5), #endif - HRTIM_TIMER_COMMON = (1<<6) + HRTIM_TIMER_COMMON = (1<<6), + + HRTIM_TIMERS_MASK = 0x3f }; /* Source which can force the Tx1/Tx2 output to its inactive state */ @@ -1028,8 +1032,10 @@ struct stm32_hrtim_ops_s uint64_t (*fclk_get)(FAR struct hrtim_dev_s *dev, uint8_t timer); int (*soft_update)(FAR struct hrtim_dev_s *dev, uint8_t timer); int (*soft_reset)(FAR struct hrtim_dev_s *dev, uint8_t timer); - int (*freq_set)(FAR struct hrtim_dev_s *hrtim, uint8_t timer, + int (*freq_set)(FAR struct hrtim_dev_s *dev, uint8_t timer, uint64_t freq); + int (*tim_enable)(FAR struct hrtim_dev_s *dev, uint8_t timers, + bool state); #ifdef CONFIG_STM32_HRTIM_INTERRUPTS int (*irq_ack)(FAR struct hrtim_dev_s *dev, uint8_t timer, int source); diff --git a/arch/arm/src/stm32/stm32_pwm.c b/arch/arm/src/stm32/stm32_pwm.c index 35b6b2d95f..bcb5c47a0b 100644 --- a/arch/arm/src/stm32/stm32_pwm.c +++ b/arch/arm/src/stm32/stm32_pwm.c @@ -486,6 +486,7 @@ static int pwm_arr_update(FAR struct pwm_lowerhalf_s *dev, uint32_t arr); static uint32_t pwm_arr_get(FAR struct pwm_lowerhalf_s *dev); static int pwm_duty_update(FAR struct pwm_lowerhalf_s *dev, uint8_t channel, ub16_t duty); +static int pwm_timer_enable(FAR struct pwm_lowerhalf_s *dev, bool state); #ifdef HAVE_ADVTIM static int pwm_break_dt_configure(FAR struct stm32_pwmtimer_s *priv); @@ -569,9 +570,14 @@ static const struct stm32_pwm_ops_s g_llpwmops = .arr_get = pwm_arr_get, .outputs_enable = pwm_outputs_enable, .soft_update = pwm_soft_update, -#ifdef HAVE_COMPLEMENTARY + .freq_update = pwm_frequency_update, + .tim_enable = pwm_timer_enable, +# ifdef CONFIG_DEBUG_PWM_INFO + .dump_regs = pwm_dumpregs, +# endif +# ifdef HAVE_COMPLEMENTARY .dt_update = pwm_deadtime_update, -#endif +# endif }; #endif @@ -2010,7 +2016,7 @@ static void pwm_dumpregs(struct stm32_pwmtimer_s *priv, FAR const char *msg) pwm_getreg(priv, STM32_GTIM_PSC_OFFSET), pwm_getreg(priv, STM32_GTIM_ARR_OFFSET)); - if (priv->timid == 1 || priv->timid == 8 ||i + if (priv->timid == 1 || priv->timid == 8 || (priv->timid >= 15 && priv->timid <= 17)) { pwminfo(" RCR: %04x BDTR: %04x\n", @@ -2067,6 +2073,8 @@ static int pwm_ccr_update(FAR struct pwm_lowerhalf_s *dev, uint8_t index, } #endif + /* REVISIT: start index from 0? */ + switch (index) { case 1: @@ -2267,6 +2275,30 @@ static int pwm_duty_update(FAR struct pwm_lowerhalf_s *dev, uint8_t channel, return OK; } +/**************************************************************************** + * Name: pwm_timer_enable + ****************************************************************************/ + +static int pwm_timer_enable(FAR struct pwm_lowerhalf_s *dev, bool state) +{ + FAR struct stm32_pwmtimer_s *priv = (FAR struct stm32_pwmtimer_s *)dev; + + if (state == true) + { + /* Enable timer counter */ + + pwm_modifyreg(priv, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN); + } + else + { + /* Disable timer counter */ + + pwm_modifyreg(priv, STM32_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0); + } + + return OK; +} + /**************************************************************************** * Name: pwm_frequency_update * @@ -3138,7 +3170,7 @@ static int pwm_pulsecount_configure(FAR struct pwm_lowerhalf_s *dev) /* Disable the timer until we get it configured */ - pwm_modifyreg(priv, STM32_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0); + pwm_timer_enable(dev, false); /* Get configured outputs */ @@ -3348,7 +3380,7 @@ static int pwm_pulsecount_timer(FAR struct pwm_lowerhalf_s *dev, /* Enable the timer */ - pwm_modifyreg(priv, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN); + pwm_timer_enable(dev, true); /* And enable timer interrupts at the NVIC */ @@ -3394,7 +3426,7 @@ static int pwm_configure(FAR struct pwm_lowerhalf_s *dev) /* Disable the timer until we get it configured */ - pwm_modifyreg(priv, STM32_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0); + pwm_timer_enable(dev, false); /* Initial timer configuration */ @@ -3646,7 +3678,7 @@ static int pwm_timer(FAR struct pwm_lowerhalf_s *dev, /* Just enable the timer, leaving all interrupts disabled */ - pwm_modifyreg(priv, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN); + pwm_timer_enable(dev, true); pwm_dumpregs(priv, "After starting"); @@ -4659,29 +4691,5 @@ errout: return (FAR struct pwm_lowerhalf_s *)lower; } -/**************************************************************************** - * Name: stm32_llops_get - * - * Description: - * Get low-level ops from the generic PWM lower-half data. - * - * Input Parameters: - * dev - A reference to the lower half PWM driver state structure - * - * Returned Value: - * Pointer to low-level PWM ops - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_PWM_LL_OPS -FAR const struct stm32_pwm_ops_s * -stm32_pwm_llops_get(FAR struct pwm_lowerhalf_s *dev) -{ - FAR struct stm32_pwmtimer_s *priv = (FAR struct stm32_pwmtimer_s *)dev; - - return priv->llops; -} -#endif - #endif /* CONFIG_STM32_TIMn_PWM, n = 1,...,17 */ diff --git a/arch/arm/src/stm32/stm32_pwm.h b/arch/arm/src/stm32/stm32_pwm.h index d38d9c0bde..bdd08bd992 100644 --- a/arch/arm/src/stm32/stm32_pwm.h +++ b/arch/arm/src/stm32/stm32_pwm.h @@ -854,6 +854,40 @@ # define PWM_TIM17_CH1NCFG 0 #endif +/* Low-level ops helpers ************************************************************/ + +/* NOTE: low-level ops accept pwm_lowerhalf_s as first argument, but llops access + * can be found in stm32_pwm_dev_s + */ + +#define PWM_SETUP(dev) \ + (dev)->ops->setup((FAR struct pwm_lowerhalf_s *)dev) +#define PWM_SHUTDOWN(dev) \ + (dev)->ops->shutdown((FAR struct pwm_lowerhalf_s *)dev) +#define PWM_CCR_UPDATE(dev, index, ccr) \ + (dev)->llops->ccr_update((FAR struct pwm_lowerhalf_s *)dev, index, ccr) +#define PWM_CCR_GET(dev, index) \ + (dev)->llops->ccr_get((FAR struct pwm_lowerhalf_s *)dev, index) +#define PWM_ARR_UPDATE(dev, arr) \ + (dev)->llops->arr_update((FAR struct pwm_lowerhalf_s *)dev, arr) +#define PWM_ARR_GET(dev) \ + (dev)->llops->arr_get((FAR struct pwm_lowerhalf_s *)dev) +#define PWM_OUTPUTS_ENABLE(dev, out, state) \ + (dev)->llops->outputs_enable((FAR struct pwm_lowerhalf_s *)dev, out, state) +#define PWM_SOFT_UPDATE(dev) \ + (dev)->llops->soft_update((FAR struct pwm_lowerhalf_s *)dev) +#define PWM_CONFIGURE(dev) \ + (dev)->llops->configure((FAR struct pwm_lowerhalf_s *)dev) +#define PWM_SOFT_BREAK(dev, state) \ + (dev)->llops->soft_break((FAR struct pwm_lowerhalf_s *)dev, state) +#define PWM_FREQ_UPDATE(dev, freq) \ + (dev)->llops->freq_update((FAR struct pwm_lowerhalf_s *)dev, freq) +#define PWM_TIM_ENABLE(dev, state) \ + (dev)->llops->tim_enable((FAR struct pwm_lowerhalf_s *)dev, state) +#define PWM_DUMP_REGS(dev) \ + (dev)->llops->dump_regs((FAR struct pwm_lowerhalf_s *)dev) +#define PWM_DT_UPDATE(dev, dt) \ + (dev)->llops->dt_update((FAR struct pwm_lowerhalf_s *)dev, dt) /************************************************************************************ * Public Types @@ -924,7 +958,27 @@ enum stm32_chan_e #ifdef CONFIG_STM32_PWM_LL_OPS -/* */ +/* This structure provides the publicly visable representation of the + * "lower-half" PWM driver structure. + */ + +struct stm32_pwm_dev_s +{ + /* The first field of this state structure must be a pointer to the PWM + * callback structure to be consistent with upper-half PWM driver. + */ + + FAR const struct pwm_ops_s *ops; + + /* Publicly visible portion of the "lower-half" PWM driver structure */ + + FAR const struct stm32_pwm_ops_s *llops; + + /* Require cast-compatibility with private "lower-half" PWM strucutre */ +}; + +/* Low-level operations for PWM */ + struct pwm_lowerhalf_s; struct stm32_pwm_ops_s { @@ -960,6 +1014,20 @@ struct stm32_pwm_ops_s int (*soft_break)(FAR struct pwm_lowerhalf_s *dev, bool state); + /* Update frequency */ + + int (*freq_update)(FAR struct pwm_lowerhalf_s *dev, uint32_t frequency); + + /* Enable timer counter */ + + int (*tim_enable)(FAR struct pwm_lowerhalf_s *dev, bool state); + +#ifdef CONFIG_DEBUG_PWM_INFO + /* Dump timer registers */ + + int (*dump_regs)(FAR struct pwm_lowerhalf_s *dev); +#endif + #ifdef HAVE_COMPLEMENTARY /* Deadtime update */ @@ -967,7 +1035,7 @@ struct stm32_pwm_ops_s #endif }; -#endif +#endif /* CONFIG_STM32_PWM_LL_OPS */ /************************************************************************************ * Public Data @@ -1007,15 +1075,6 @@ extern "C" FAR struct pwm_lowerhalf_s *stm32_pwminitialize(int timer); -/************************************************************************************ - * Name: stm32_pwm_llops_get - * - ************************************************************************************/ - -#ifdef CONFIG_STM32_PWM_LL_OPS - FAR const struct stm32_pwm_ops_s *stm32_pwm_llops_get(FAR struct pwm_lowerhalf_s *dev); -#endif - #undef EXTERN #if defined(__cplusplus) } diff --git a/arch/arm/src/stm32/stm32f10xxx_dma.c b/arch/arm/src/stm32/stm32f10xxx_dma.c index dcc97fbbfb..f3972b3dc5 100644 --- a/arch/arm/src/stm32/stm32f10xxx_dma.c +++ b/arch/arm/src/stm32/stm32f10xxx_dma.c @@ -55,7 +55,6 @@ #include "stm32_dma.h" #include "stm32.h" - #if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \ defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F37XX) || \ defined(CONFIG_STM32_STM32L15XX) @@ -756,4 +755,37 @@ void stm32_dmadump(DMA_HANDLE handle, const struct stm32_dmaregs_s *regs, } #endif +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + +/**************************************************************************** + * Name: stm32_dma_intack + * + * Description: + * Public visible interface to acknowledge interrupts on DMA channel + * + ****************************************************************************/ + +void stm32_dma_intack(unsigned int chndx, uint32_t isr) +{ + struct stm32_dma_s *dmach = &g_dma[chndx]; + + dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET, isr); +} + +/**************************************************************************** + * Name: stm32_dma_intget + * + * Description: + * Public visible interface to get pending interrupts from DMA channel + * + ****************************************************************************/ + +uint32_t stm32_dma_intget(unsigned int chndx) +{ + struct stm32_dma_s *dmach = &g_dma[chndx]; + + return dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) & DMA_ISR_CHAN_MASK(dmach->chan); +} +#endif /* CONFIG_ARCH_HIPRI_INTERRUPT */ + #endif /* CONFIG_STM32_STM32F10XX */ diff --git a/arch/arm/src/stm32/stm32f20xxx_dma.c b/arch/arm/src/stm32/stm32f20xxx_dma.c index b987a7888f..38dc97858e 100644 --- a/arch/arm/src/stm32/stm32f20xxx_dma.c +++ b/arch/arm/src/stm32/stm32f20xxx_dma.c @@ -57,6 +57,8 @@ /* This file supports only the STM32 F2 family (although it is identical to * the corresponding F4 file). + * + * TODO: merge this with stm32f40xxx_dma.c (STM32 DMA IP core version 2) */ #if defined(CONFIG_STM32_STM32F20XX) diff --git a/arch/arm/src/stm32/stm32f33xxx_adc.c b/arch/arm/src/stm32/stm32f33xxx_adc.c deleted file mode 100644 index 6c9653a0fd..0000000000 --- a/arch/arm/src/stm32/stm32f33xxx_adc.c +++ /dev/null @@ -1,2410 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32/stm32f33xxx_adc.c - * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. - * - * based on stm32_adc.c - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "up_internal.h" -#include "up_arch.h" - -#include "chip.h" -#include "stm32.h" -#include "stm32_dma.h" -#include "stm32_adc.h" - -/* ADC "upper half" support must be enabled */ - -#ifdef CONFIG_STM32_ADC - -/* Some ADC peripheral must be enabled */ - -#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* This implementation is for the STM32F33XXX only. - * - * STM32F33XXX chips are intended for digital power conversion applications, - * which casue some differences in use comapred to the standard STM32 ADC driver. - * This include: - * - lower half ADC driver can be used not only with the upper-half ADC driver, - * but also as the lower-half logic for the power-related drivers (eg. SMPS - * upper driver), - * - ADC will be used in time-critical operations (eg. converter control loop), - * therfore it is necessary to support the high performecne, zero latency ADC - * interrupts - * - ADC triggering from the high resolution timer (HRTIM) and external lines - * - support for injected sequence - */ - -#if defined(CONFIG_STM32_STM32F33XX) - -#warning "ADC support for STM32F33XX under development !" - -#if defined(ADC1_INJECTED_CHAN) && !defined(CONFIG_STM32_ADC1_INJECTED) -# warning -#endif -#if defined(ADC2_INJECTED_CHAN) && !defined(CONFIG_STM32_ADC2_INJECTED) -# warning -#endif - -#if defined(CONFIG_STM32_ADC1_INJECTED) || defined(CONFIG_STM32_ADC2_INJECTED) -# define ADC_HAVE_INJECTED 1 -#endif - -#ifndef CONFIG_STM32_ADC1_INJECTED -# define ADC1_INJECTED_CHAN 0 -#else -# define ADC1_HAVE_JEXTSEL -#endif -#ifndef CONFIG_STM32_ADC2_INJECTED -# define ADC2_INJECTED_CHAN 0 -#else -# define ADC2_HAVE_JEXTSEL -#endif - -/* RCC reset ****************************************************************/ - -#define STM32_RCC_RSTR STM32_RCC_AHBRSTR -#define STM32_RCC_ENR STM32_RCC_AHBENR -#define RCC_RSTR_ADC12RST RCC_AHBRSTR_ADC12RST -#define RCC_RSTR_ADC12EN RCC_AHBENR_ADC12EN - -/* ADC interrupts ***********************************************************/ - -#define STM32_ADC_DMAREG_OFFSET STM32_ADC_CFGR1_OFFSET -#define ADC_DMAREG_DMA ADC_CFGR1_DMAEN -#define STM32_ADC_EXTREG_OFFSET STM32_ADC_CFGR1_OFFSET -#define ADC_EXTREG_EXTSEL_MASK ADC_CFGR1_EXTSEL_MASK -#define ADC_EXTREG_EXTEN_MASK ADC_CFGR1_EXTEN_MASK -#define ADC_EXTREG_EXTEN_DEFAULT ADC_CFGR1_EXTEN_RISING -#define STM32_ADC_JEXTREG_OFFSET STM32_ADC_JSQR_OFFSET -#define ADC_JEXTREG_JEXTSEL_MASK ADC_JSQR_JEXTSEL_MASK -#define ADC_JEXTREG_JEXTEN_MASK ADC_JSQR_JEXTEN_MASK -#define ADC_JEXTREG_JEXTEN_DEFAULT ADC_JSQR_JEXTEN_RISING - -#define ADC_ISR_EOC ADC_INT_EOC -#define ADC_IER_EOC ADC_INT_EOC -#define ADC_ISR_AWD ADC_INT_AWD1 -#define ADC_IER_AWD ADC_INT_AWD1 -#define ADC_ISR_JEOC ADC_INT_JEOC -#define ADC_IER_JEOC ADC_INT_JEOC -#define ADC_ISR_JEOS ADC_INT_JEOS -#define ADC_IER_JEOS ADC_INT_JEOS -#define ADC_ISR_OVR ADC_INT_OVR -#define ADC_IER_OVR ADC_INT_OVR - -#define ADC_ISR_ALLINTS (ADC_ISR_EOC | ADC_ISR_AWD | ADC_ISR_JEOC | \ - ADC_ISR_JEOS | ADC_ISR_OVR) -#define ADC_IER_ALLINTS (ADC_IER_EOC | ADC_IER_AWD | ADC_IER_JEOC | \ - ADC_IER_JEOS| ADC_IER_OVR) - -/* ADC Channels/DMA ********************************************************/ -/* The maximum number of channels that can be sampled. If DMA support is - * not enabled, then only a single channel can be sampled. Otherwise, - * data overruns would occur. - */ - -#define ADC_MAX_CHANNELS_DMA 16 -#define ADC_MAX_CHANNELS_NOIRQ 16 -#define ADC_MAX_CHANNELS_NODMA 1 - -#if defined(ADC_HAVE_DMA) -# define ADC_REG_MAX_SAMPLES ADC_MAX_CHANNELS_DMA -#elif defined(CONFIG_STM32_ADC_NOIRQ) -# define ADC_REG_MAX_SAMPLES ADC_MAX_CHANNELS_NOIRQ -#else -# define ADC_REG_MAX_SAMPLES ADC_MAX_CHANNELS_NODMA -#endif - -#define ADC_INJ_MAX_SAMPLES 4 - -#define ADC_DMA_CONTROL_WORD (DMA_CCR_MSIZE_16BITS | \ - DMA_CCR_PSIZE_16BITS | \ - DMA_CCR_MINC | \ - DMA_CCR_CIRC) - -#if defined(ADC_HAVE_DMA) || (ADC_REG_MAX_SAMPLES == 1) -# define ADC_SMPR_DEFAULT ADC_SMPR_61p5 -#else /* Slow down sampling frequency */ -# define ADC_SMPR_DEFAULT ADC_SMPR_601p5 -#endif - -#ifndef ADC1_SMP1 -# define ADC1_SMP1 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP2 -# define ADC1_SMP2 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP3 -# define ADC1_SMP3 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP4 -# define ADC1_SMP4 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP5 -# define ADC1_SMP5 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP6 -# define ADC1_SMP6 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP7 -# define ADC1_SMP7 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP8 -# define ADC1_SMP8 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP9 -# define ADC1_SMP9 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP10 -# define ADC1_SMP10 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP11 -# define ADC1_SMP11 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP12 -# define ADC1_SMP12 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP13 -# define ADC1_SMP13 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP14 -# define ADC1_SMP14 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP15 -# define ADC1_SMP15 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP16 -# define ADC1_SMP16 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP17 -# define ADC1_SMP17 ADC_SMPR_DEFAULT -#endif -#ifndef ADC1_SMP18 -# define ADC1_SMP18 ADC_SMPR_DEFAULT -#endif - -#ifndef ADC2_SMP1 -# define ADC2_SMP1 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP2 -# define ADC2_SMP2 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP3 -# define ADC2_SMP3 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP4 -# define ADC2_SMP4 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP5 -# define ADC2_SMP5 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP6 -# define ADC2_SMP6 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP7 -# define ADC2_SMP7 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP8 -# define ADC2_SMP8 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP9 -# define ADC2_SMP9 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP10 -# define ADC2_SMP10 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP11 -# define ADC2_SMP11 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP12 -# define ADC2_SMP12 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP13 -# define ADC2_SMP13 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP14 -# define ADC2_SMP14 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP15 -# define ADC2_SMP15 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP16 -# define ADC2_SMP16 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP17 -# define ADC2_SMP17 ADC_SMPR_DEFAULT -#endif -#ifndef ADC2_SMP18 -# define ADC2_SMP18 ADC_SMPR_DEFAULT -#endif - -#define ADC1_SMPR1 ((ADC1_SMP1 << ADC_SMPR1_SMP1_SHIFT) | \ - (ADC1_SMP2 << ADC_SMPR1_SMP2_SHIFT) | \ - (ADC1_SMP3 << ADC_SMPR1_SMP3_SHIFT) | \ - (ADC1_SMP4 << ADC_SMPR1_SMP4_SHIFT) | \ - (ADC1_SMP5 << ADC_SMPR1_SMP5_SHIFT) | \ - (ADC1_SMP6 << ADC_SMPR1_SMP6_SHIFT) | \ - (ADC1_SMP7 << ADC_SMPR1_SMP7_SHIFT) | \ - (ADC1_SMP8 << ADC_SMPR1_SMP8_SHIFT) | \ - (ADC1_SMP9 << ADC_SMPR1_SMP9_SHIFT)) -#define ADC1_SMPR2 ((ADC1_SMP10 << ADC_SMPR2_SMP10_SHIFT) | \ - (ADC1_SMP11 << ADC_SMPR2_SMP11_SHIFT) | \ - (ADC1_SMP12 << ADC_SMPR2_SMP12_SHIFT) | \ - (ADC1_SMP13 << ADC_SMPR2_SMP13_SHIFT) | \ - (ADC1_SMP14 << ADC_SMPR2_SMP14_SHIFT) | \ - (ADC1_SMP15 << ADC_SMPR2_SMP15_SHIFT) | \ - (ADC1_SMP16 << ADC_SMPR2_SMP16_SHIFT) | \ - (ADC1_SMP17 << ADC_SMPR2_SMP17_SHIFT) | \ - (ADC1_SMP18 << ADC_SMPR2_SMP18_SHIFT)) - -#define ADC2_SMPR1 ((ADC2_SMP1 << ADC_SMPR1_SMP1_SHIFT) | \ - (ADC2_SMP2 << ADC_SMPR1_SMP2_SHIFT) | \ - (ADC2_SMP3 << ADC_SMPR1_SMP3_SHIFT) | \ - (ADC2_SMP4 << ADC_SMPR1_SMP4_SHIFT) | \ - (ADC2_SMP5 << ADC_SMPR1_SMP5_SHIFT) | \ - (ADC2_SMP6 << ADC_SMPR1_SMP6_SHIFT) | \ - (ADC2_SMP7 << ADC_SMPR1_SMP7_SHIFT) | \ - (ADC2_SMP8 << ADC_SMPR1_SMP8_SHIFT) | \ - (ADC2_SMP9 << ADC_SMPR1_SMP9_SHIFT)) -#define ADC2_SMPR2 ((ADC2_SMP10 << ADC_SMPR2_SMP10_SHIFT) | \ - (ADC2_SMP11 << ADC_SMPR2_SMP11_SHIFT) | \ - (ADC2_SMP12 << ADC_SMPR2_SMP12_SHIFT) | \ - (ADC2_SMP13 << ADC_SMPR2_SMP13_SHIFT) | \ - (ADC2_SMP14 << ADC_SMPR2_SMP14_SHIFT) | \ - (ADC2_SMP15 << ADC_SMPR2_SMP15_SHIFT) | \ - (ADC2_SMP16 << ADC_SMPR2_SMP16_SHIFT) | \ - (ADC2_SMP17 << ADC_SMPR2_SMP17_SHIFT) | \ - (ADC2_SMP18 << ADC_SMPR2_SMP18_SHIFT)) - -/* Last bit of the extsel fields indicate if external trigger is in use */ - -#define HAVE_EXTSEL_MASK (1<<31) - -#if defined(ADC1_HAVE_TIMER) || defined(ADC1_HAVE_HRTIM) || defined(ADC1_HAVE_EXTI) -# define ADC1_HAVE_EXTSEL 1 -#else -# undef ADC1_HAVE_EXTSEL -#endif - -#if defined(ADC2_HAVE_TIMER) || defined(ADC2_HAVE_HRTIM) || defined(ADC2_HAVE_EXTI) -# define ADC2_HAVE_EXTSEL 1 -#else -# undef ADC2_HAVE_EXTSEL -#endif - -#if defined(ADC1_HAVE_EXTSEL) || defined(ADC2_HAVE_EXTSEL) -# define ADC_HAVE_EXTSEL -#endif - -#if defined(ADC1_HAVE_JEXTSEL) || defined(ADC2_HAVE_JEXTSEL) -# define ADC_HAVE_JEXTSEL -#endif - -/* Default ADC resolution */ - -#ifndef ADC1_RESOLUTION -# define ADC1_RESOLUTION ADC_RESOLUTION_12BIT -#endif -#ifndef ADC2_RESOLUTION -# define ADC2_RESOLUTION ADC_RESOLUTION_12BIT -#endif - -/* Default ADC DMA configuration */ - -#ifndef ADC1_DMA_CFG -# define ADC1_DMA_CFG ADC_CFGR1_DMACFG -#endif -#ifndef ADC2_DMA_CFG -# define ADC2_DMA_CFG ADC_CFGR1_DMACFG -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Data common to all ADC instances */ - -struct adc_cmn_s -{ - uint8_t initialized; /* How many ADC instances are currently in use */ - /* TODO: dual ADC mode */ -}; - -/* This structure describes the state of one ADC block */ - -struct stm32_dev_s -{ -#ifdef CONFIG_STM32_ADC_NOIRQ - FAR const struct stm32_adc_ops_s *ops; /* Publicly visible portion */ -#else - FAR const struct adc_callback_s *cb; - uint8_t irq; /* Interrupt generated by this ADC block */ -#endif - struct adc_cmn_s *cmn; /* Common ADC data */ - uint8_t rnchannels; /* Number of regular channels */ - uint8_t cr_channels; /* Number of configured regular channels */ -#ifdef ADC_HAVE_INJECTED - uint8_t cj_channels; /* Number of configured injected channels */ -#endif - uint8_t intf; /* ADC interface number */ - uint8_t resolution; /* ADC resolution*/ - uint8_t current; /* Current ADC channel being converted */ -#ifdef ADC_HAVE_DMA - uint8_t dmachan; /* DMA channel needed by this ADC */ - uint8_t dmacfg; /* DMA channel configuration */ - bool hasdma; /* True: This channel supports DMA */ -#endif -#ifdef ADC_HAVE_TIMER - uint8_t trigger; /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3, - * 3=CC4, 4=TRGO */ -#endif -#ifndef CONFIG_STM32_ADC_NOIRQ - xcpt_t isr; /* Interrupt handler for this ADC block */ -#endif - uint32_t base; /* Base address of registers unique to this ADC - * block */ - uint32_t smp1; /* Sample time part 1 */ - uint32_t smp2; /* Sample time part 2 */ -#ifdef ADC_HAVE_EXTSEL - uint32_t extsel; /* EXTSEL value used by this ADC block */ -#endif -#ifdef ADC_HAVE_JEXTSEL - uint32_t jextsel; /* JEXTSEL value used by this ADC block */ -#endif -#ifdef ADC_HAVE_TIMER - uint32_t tbase; /* Base address of timer used by this ADC block */ - uint32_t pclck; /* The PCLK frequency that drives this timer */ - uint32_t freq; /* The desired frequency of conversions */ -#endif -#ifdef ADC_HAVE_DMA - DMA_HANDLE dma; /* Allocated DMA channel */ - - /* DMA transfer buffer for regular channels */ - - uint16_t r_dmabuffer[ADC_REG_MAX_SAMPLES]; -#endif - - /* List of selected ADC regular channels to sample */ - - uint8_t r_chanlist[ADC_REG_MAX_SAMPLES]; - -#ifdef ADC_HAVE_INJECTED - /* List of selected ADC injected channels to sample */ - - uint8_t j_chanlist[ADC_INJ_MAX_SAMPLES]; -#endif -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* ADC Register access */ - -static void stm32_modifyreg32(unsigned int addr, uint32_t clrbits, - uint32_t setbits); -static uint32_t adc_getreg(FAR struct stm32_dev_s *priv, int offset); -static void adc_putreg(FAR struct stm32_dev_s *priv, int offset, - uint32_t value); -static void adc_modifyreg(FAR struct stm32_dev_s *priv, int offset, - uint32_t clrbits, uint32_t setbits); -#ifdef ADC_HAVE_TIMER -static uint16_t tim_getreg(FAR struct stm32_dev_s *priv, int offset); -static void tim_putreg(FAR struct stm32_dev_s *priv, int offset, - uint16_t value); -static void tim_modifyreg(FAR struct stm32_dev_s *priv, int offset, - uint16_t clrbits, uint16_t setbits); -static void tim_dumpregs(FAR struct stm32_dev_s *priv, - FAR const char *msg); -#endif - -static void adc_rccreset(FAR struct stm32_dev_s *priv, bool reset); - -/* ADC Interrupt Handler */ - -#ifndef CONFIG_STM32_ADC_NOIRQ -static int adc_interrupt(FAR struct adc_dev_s *dev); -static int adc12_interrupt(int irq, FAR void *context, FAR void *arg); -#endif - -/* ADC Driver Methods */ - -static int adc_bind(FAR struct adc_dev_s *dev, - FAR const struct adc_callback_s *callback); -static void adc_reset(FAR struct adc_dev_s *dev); -static int adc_setup(FAR struct adc_dev_s *dev); -static void adc_shutdown(FAR struct adc_dev_s *dev); -static void adc_rxint(FAR struct adc_dev_s *dev, bool enable); -static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg); -static void adc_enable(FAR struct stm32_dev_s *priv, bool enable); - -static uint32_t adc_sqrbits(FAR struct stm32_dev_s *priv, int first, int last, - int offset); -static int adc_set_ch(FAR struct adc_dev_s *dev, uint8_t ch); - -#ifdef ADC_HAVE_TIMER -static void adc_timstart(FAR struct stm32_dev_s *priv, bool enable); -static int adc_timinit(FAR struct stm32_dev_s *priv); -#endif - -#if defined(ADC_HAVE_DMA) && !defined(CONFIG_STM32_ADC_NOIRQ) -static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr, - FAR void *arg); -#endif - -static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable); -#ifdef ADC_HAVE_INJECTED -static void adc_inj_startconv(FAR struct stm32_dev_s *priv, bool enable); -static int adc_inj_set_ch(FAR struct adc_dev_s *dev, uint8_t ch); -#endif - -#ifdef CONFIG_STM32_ADC_NOIRQ -static void adc_intack(FAR struct stm32_adc_dev_s *dev, uint32_t source); -static void adc_inten(FAR struct stm32_adc_dev_s *dev, uint32_t source); -static void adc_intdis(FAR struct stm32_adc_dev_s *dev, uint32_t source); -static uint32_t adc_intget(FAR struct stm32_adc_dev_s *dev); -static uint32_t adc_regget(FAR struct stm32_adc_dev_s *dev); -# ifdef ADC_HAVE_DMA -static int adc_regbufregister(FAR struct stm32_adc_dev_s *dev, uint16_t *buffer, uint8_t len); -# endif -# ifdef ADC_HAVE_INJECTED -static uint32_t adc_injget(FAR struct stm32_adc_dev_s *dev, uint8_t chan); -# endif -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* ADC interface operations */ - -static const struct adc_ops_s g_adcops = -{ - .ao_bind = adc_bind, - .ao_reset = adc_reset, - .ao_setup = adc_setup, - .ao_shutdown = adc_shutdown, - .ao_rxint = adc_rxint, - .ao_ioctl = adc_ioctl, -}; - -/* Publicly visible ADC lower-half operations */ - -#ifdef CONFIG_STM32_ADC_NOIRQ -static const struct stm32_adc_ops_s g_adc_lowerops = -{ - .int_ack = adc_intack, - .int_get = adc_intget, - .int_en = adc_inten, - .int_dis = adc_intdis, - .val_get = adc_regget, -#ifdef ADC_HAVE_DMA - .regbuf_reg = adc_regbufregister, -#endif -#ifdef ADC_HAVE_INJECTED - .inj_get = adc_injget, -#endif -}; -#endif - -/* Common ADC12 data */ - -struct adc_cmn_s g_adc12_cmn = -{ - .initialized = 0 -}; - -/* ADC1 state */ - -#ifdef CONFIG_STM32_ADC1 -static struct stm32_dev_s g_adcpriv1 = -{ -#ifdef CONFIG_STM32_ADC_NOIRQ - .ops = &g_adc_lowerops, -#else - .irq = STM32_IRQ_ADC12, - .isr = adc12_interrupt, -#endif - .cmn = &g_adc12_cmn, - .intf = 1, - .resolution = ADC1_RESOLUTION, - .base = STM32_ADC1_BASE, - .smp1 = ADC1_SMPR1, - .smp2 = ADC1_SMPR2, -#if defined(ADC1_HAVE_EXTSEL) - .extsel = ADC1_EXTSEL_VALUE | HAVE_EXTSEL_MASK, -#endif -#if defined(ADC1_HAVE_JEXTSEL) - .jextsel = ADC1_JEXTSEL_VALUE | HAVE_EXTSEL_MASK, -#endif -#ifdef ADC1_HAVE_TIMER - .trigger = CONFIG_STM32_ADC1_TIMTRIG, - .tbase = ADC1_TIMER_BASE, - .pclck = ADC1_TIMER_PCLK_FREQUENCY, - .freq = CONFIG_STM32_ADC1_SAMPLE_FREQUENCY, -#endif -#ifdef ADC1_HAVE_DMA - .dmachan = ADC1_DMA_CHAN, - .dmacfg = ADC1_DMA_CFG, - .hasdma = true, -#endif -}; - -static struct adc_dev_s g_adcdev1 = -{ - .ad_ops = &g_adcops, - .ad_priv = &g_adcpriv1, -}; -#endif - -/* ADC2 state */ - -#ifdef CONFIG_STM32_ADC2 -static struct stm32_dev_s g_adcpriv2 = -{ -#ifdef CONFIG_STM32_ADC_NOIRQ - .ops = &g_adc_lowerops, -#else - .irq = STM32_IRQ_ADC12, - .isr = adc12_interrupt, -#endif - .cmn = &g_adc12_cmn, - .intf = 2, - .resolution = ADC2_RESOLUTION, - .base = STM32_ADC2_BASE, - .smp1 = ADC2_SMPR1, - .smp2 = ADC2_SMPR2, -#ifdef ADC2_HAVE_EXTSEL - .extsel = ADC2_EXTSEL_VALUE | HAVE_EXTSEL_MASK, -#endif -#ifdef ADC2_HAVE_JEXTSEL - .jextsel = ADC2_JEXTSEL_VALUE | HAVE_EXTSEL_MASK, -#endif -#ifdef ADC2_HAVE_TIMER - .trigger = CONFIG_STM32_ADC2_TIMTRIG, - .tbase = ADC2_TIMER_BASE, - .pclck = ADC2_TIMER_PCLK_FREQUENCY, - .freq = CONFIG_STM32_ADC2_SAMPLE_FREQUENCY, -#endif -#ifdef ADC2_HAVE_DMA - .dmachan = ADC2_DMA_CHAN, - .dmacfg = ADC2_DMA_CFG, - .hasdma = true, -#endif -}; - -static struct adc_dev_s g_adcdev2 = -{ - .ad_ops = &g_adcops, - .ad_priv = &g_adcpriv2, -}; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_modifyreg32 - * - * Description: - * Modify the value of a 32-bit register (not atomic). - * - * Input Parameters: - * addr - The address of the register - * clrbits - The bits to clear - * setbits - The bits to set - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void stm32_modifyreg32(unsigned int addr, uint32_t clrbits, - uint32_t setbits) -{ - putreg32((getreg32(addr) & ~clrbits) | setbits, addr); -} - -/**************************************************************************** - * Name: adc_getreg - * - * Description: - * Read the value of an ADC register. - * - * Input Parameters: - * priv - A reference to the ADC block status - * offset - The offset to the register to read - * - * Returned Value: - * The current contents of the specified register - * - ****************************************************************************/ - -static uint32_t adc_getreg(FAR struct stm32_dev_s *priv, int offset) -{ - return getreg32(priv->base + offset); -} - -/**************************************************************************** - * Name: adc_putreg - * - * Description: - * Write a value to an ADC register. - * - * Input Parameters: - * priv - A reference to the ADC block status - * offset - The offset to the register to write to - * value - The value to write to the register - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void adc_putreg(FAR struct stm32_dev_s *priv, int offset, - uint32_t value) -{ - putreg32(value, priv->base + offset); -} - -/**************************************************************************** - * Name: adc_modifyreg - * - * Description: - * Modify the value of an ADC register (not atomic). - * - * Input Parameters: - * priv - A reference to the ADC block status - * offset - The offset to the register to modify - * clrbits - The bits to clear - * setbits - The bits to set - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void adc_modifyreg(FAR struct stm32_dev_s *priv, int offset, - uint32_t clrbits, uint32_t setbits) -{ - adc_putreg(priv, offset, (adc_getreg(priv, offset) & ~clrbits) | setbits); -} - -/**************************************************************************** - * Name: tim_getreg - * - * Description: - * Read the value of an ADC timer register. - * - * Input Parameters: - * priv - A reference to the ADC block status - * offset - The offset to the register to read - * - * Returned Value: - * The current contents of the specified register - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static uint16_t tim_getreg(FAR struct stm32_dev_s *priv, int offset) -{ - return getreg16(priv->tbase + offset); -} -#endif - -/**************************************************************************** - * Name: tim_putreg - * - * Description: - * Write a value to an ADC timer register. - * - * Input Parameters: - * priv - A reference to the ADC block status - * offset - The offset to the register to write to - * value - The value to write to the register - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static void tim_putreg(FAR struct stm32_dev_s *priv, int offset, - uint16_t value) -{ - putreg16(value, priv->tbase + offset); -} -#endif - -/**************************************************************************** - * Name: tim_modifyreg - * - * Description: - * Modify the value of an ADC timer register (not atomic). - * - * Input Parameters: - * priv - A reference to the ADC block status - * offset - The offset to the register to modify - * clrbits - The bits to clear - * setbits - The bits to set - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static void tim_modifyreg(FAR struct stm32_dev_s *priv, int offset, - uint16_t clrbits, uint16_t setbits) -{ - tim_putreg(priv, offset, (tim_getreg(priv, offset) & ~clrbits) | setbits); -} -#endif - -/**************************************************************************** - * Name: tim_dumpregs - * - * Description: - * Dump all timer registers. - * - * Input Parameters: - * priv - A reference to the ADC block status - * - * Returned Value: - * None - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static void tim_dumpregs(FAR struct stm32_dev_s *priv, FAR const char *msg) -{ - ainfo("%s:\n", msg); - ainfo(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n", - tim_getreg(priv, STM32_GTIM_CR1_OFFSET), - tim_getreg(priv, STM32_GTIM_CR2_OFFSET), - tim_getreg(priv, STM32_GTIM_SMCR_OFFSET), - tim_getreg(priv, STM32_GTIM_DIER_OFFSET)); - ainfo(" SR: %04x EGR: 0000 CCMR1: %04x CCMR2: %04x\n", - tim_getreg(priv, STM32_GTIM_SR_OFFSET), - tim_getreg(priv, STM32_GTIM_CCMR1_OFFSET), - tim_getreg(priv, STM32_GTIM_CCMR2_OFFSET)); - ainfo(" CCER: %04x CNT: %04x PSC: %04x ARR: %04x\n", - tim_getreg(priv, STM32_GTIM_CCER_OFFSET), - tim_getreg(priv, STM32_GTIM_CNT_OFFSET), - tim_getreg(priv, STM32_GTIM_PSC_OFFSET), - tim_getreg(priv, STM32_GTIM_ARR_OFFSET)); - ainfo(" CCR1: %04x CCR2: %04x CCR3: %04x CCR4: %04x\n", - tim_getreg(priv, STM32_GTIM_CCR1_OFFSET), - tim_getreg(priv, STM32_GTIM_CCR2_OFFSET), - tim_getreg(priv, STM32_GTIM_CCR3_OFFSET), - tim_getreg(priv, STM32_GTIM_CCR4_OFFSET)); - - if (priv->tbase == STM32_TIM1_BASE) - { - ainfo(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n", - tim_getreg(priv, STM32_ATIM_RCR_OFFSET), - tim_getreg(priv, STM32_ATIM_BDTR_OFFSET), - tim_getreg(priv, STM32_ATIM_DCR_OFFSET), - tim_getreg(priv, STM32_ATIM_DMAR_OFFSET)); - } - else - { - ainfo(" DCR: %04x DMAR: %04x\n", - tim_getreg(priv, STM32_GTIM_DCR_OFFSET), - tim_getreg(priv, STM32_GTIM_DMAR_OFFSET)); - } -} -#endif - -/**************************************************************************** - * Name: adc_timstart - * - * Description: - * Start (or stop) the timer counter - * - * Input Parameters: - * priv - A reference to the ADC block status - * enable - True: Start conversion - * - * Returned Value: - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static void adc_timstart(FAR struct stm32_dev_s *priv, bool enable) -{ - ainfo("enable: %d\n", enable ? 1 : 0); - - if (enable) - { - /* Start the counter */ - - tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_CEN); - } - else - { - /* Disable the counter */ - - tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, GTIM_CR1_CEN, 0); - } -} -#endif - -/**************************************************************************** - * Name: adc_timinit - * - * Description: - * Initialize the timer that drivers the ADC sampling for this channel - * using the pre-calculated timer divider definitions. - * - * Input Parameters: - * priv - A reference to the ADC block status - * - * Returned Value: - * Zero on success; a negated errno value on failure. - * - ****************************************************************************/ - -#ifdef ADC_HAVE_TIMER -static int adc_timinit(FAR struct stm32_dev_s *priv) -{ - uint32_t prescaler; - uint32_t reload; - uint32_t timclk; - - uint16_t clrbits = 0; - uint16_t setbits = 0; - uint16_t cr2; - uint16_t ccmr1; - uint16_t ccmr2; - uint16_t ocmode1; - uint16_t ocmode2; - uint16_t ccenable; - uint16_t ccer; - uint16_t egr; - - /* If the timer base address is zero, then this ADC was not configured to - * use a timer. - */ - - if (priv->tbase == 0) - { - return ERROR; - } - - /* Configure the timer channel to drive the ADC */ - - /* Caculate optimal values for the timer prescaler and for the timer - * reload register. If freq is the desired frequency, then - * - * reload = timclk / freq - * reload = (pclck / prescaler) / freq - * - * There are many solutions to do this, but the best solution will be the - * one that has the largest reload value and the smallest prescaler value. - * That is the solution that should give us the most accuracy in the timer - * control. Subject to: - * - * 0 <= prescaler <= 65536 - * 1 <= reload <= 65535 - * - * So ( prescaler = pclck / 65535 / freq ) would be optimal. - */ - - prescaler = (priv->pclck / priv->freq + 65534) / 65535; - - /* We need to decrement the prescaler value by one, but only, the value - * does not underflow. - */ - - if (prescaler < 1) - { - awarn("WARNING: Prescaler underflowed.\n"); - prescaler = 1; - } - - /* Check for overflow */ - - else if (prescaler > 65536) - { - awarn("WARNING: Prescaler overflowed.\n"); - prescaler = 65536; - } - - timclk = priv->pclck / prescaler; - - reload = timclk / priv->freq; - if (reload < 1) - { - awarn("WARNING: Reload value underflowed.\n"); - reload = 1; - } - else if (reload > 65535) - { - awarn("WARNING: Reload value overflowed.\n"); - reload = 65535; - } - - /* Disable the timer until we get it configured */ - - adc_timstart(priv, false); - - /* Set up the timer CR1 register. - * - * Select the Counter Mode == count up: - * - * ATIM_CR1_EDGE: The counter counts up or down depending on the - * direction bit(DIR). - * ATIM_CR1_DIR: 0: count up, 1: count down - * - * Set the clock division to zero for all - */ - - clrbits = GTIM_CR1_DIR | GTIM_CR1_CMS_MASK | GTIM_CR1_CKD_MASK; - setbits = GTIM_CR1_EDGE; - tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, clrbits, setbits); - - /* Set the reload and prescaler values */ - - tim_putreg(priv, STM32_GTIM_PSC_OFFSET, prescaler-1); - tim_putreg(priv, STM32_GTIM_ARR_OFFSET, reload); - - /* TIMx event generation: Bit 0 UG: Update generation */ - - tim_putreg(priv, STM32_GTIM_EGR_OFFSET, GTIM_EGR_UG); - - /* Handle channel specific setup */ - - ocmode1 = 0; - ocmode2 = 0; - - switch (priv->trigger) - { - case 0: /* TimerX CC1 event */ - { - ccenable = ATIM_CCER_CC1E; - ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC1S_SHIFT) | - (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC1M_SHIFT) | - ATIM_CCMR1_OC1PE; - - /* Set the event CC1 */ - - egr = ATIM_EGR_CC1G; - - /* Set the duty cycle by writing to the CCR register for this - * channel - */ - - tim_putreg(priv, STM32_GTIM_CCR1_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - case 1: /* TimerX CC2 event */ - { - ccenable = ATIM_CCER_CC2E; - ocmode1 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR1_CC2S_SHIFT) | - (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR1_OC2M_SHIFT) | - ATIM_CCMR1_OC2PE; - - /* Set the event CC2 */ - - egr = ATIM_EGR_CC2G; - - /* Set the duty cycle by writing to the CCR register for this - * channel - */ - - tim_putreg(priv, STM32_GTIM_CCR2_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - case 2: /* TimerX CC3 event */ - { - ccenable = ATIM_CCER_CC3E; - ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC3S_SHIFT) | - (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC3M_SHIFT) | - ATIM_CCMR2_OC3PE; - - /* Set the event CC3 */ - - egr = ATIM_EGR_CC3G; - - /* Set the duty cycle by writing to the CCR register for this - * channel - */ - - tim_putreg(priv, STM32_GTIM_CCR3_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - case 3: /* TimerX CC4 event */ - { - ccenable = ATIM_CCER_CC4E; - ocmode2 = (ATIM_CCMR_CCS_CCOUT << ATIM_CCMR2_CC4S_SHIFT) | - (ATIM_CCMR_MODE_PWM1 << ATIM_CCMR2_OC4M_SHIFT) | - ATIM_CCMR2_OC4PE; - - /* Set the event CC4 */ - - egr = ATIM_EGR_CC4G; - - /* Set the duty cycle by writing to the CCR register for this - * channel - */ - - tim_putreg(priv, STM32_GTIM_CCR4_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - case 4: /* TimerX TRGO event */ - { - /* TODO: TRGO support not yet implemented */ - /* Set the event TRGO */ - - ccenable = 0; - egr = GTIM_EGR_TG; - - /* Set the duty cycle by writing to the CCR register for this - * channel - */ - - tim_putreg(priv, STM32_GTIM_CCR4_OFFSET, (uint16_t)(reload >> 1)); - } - break; - - default: - aerr("ERROR: No such trigger: %d\n", priv->trigger); - return -EINVAL; - } - - /* Disable the Channel by resetting the CCxE Bit in the CCER register */ - - ccer = tim_getreg(priv, STM32_GTIM_CCER_OFFSET); - ccer &= ~ccenable; - tim_putreg(priv, STM32_GTIM_CCER_OFFSET, ccer); - - /* Fetch the CR2, CCMR1, and CCMR2 register (already have ccer) */ - - cr2 = tim_getreg(priv, STM32_GTIM_CR2_OFFSET); - ccmr1 = tim_getreg(priv, STM32_GTIM_CCMR1_OFFSET); - ccmr2 = tim_getreg(priv, STM32_GTIM_CCMR2_OFFSET); - - /* Reset the Output Compare Mode Bits and set the select output compare - * mode - */ - - ccmr1 &= ~(ATIM_CCMR1_CC1S_MASK | ATIM_CCMR1_OC1M_MASK | ATIM_CCMR1_OC1PE | - ATIM_CCMR1_CC2S_MASK | ATIM_CCMR1_OC2M_MASK | ATIM_CCMR1_OC2PE); - ccmr2 &= ~(ATIM_CCMR2_CC3S_MASK | ATIM_CCMR2_OC3M_MASK | ATIM_CCMR2_OC3PE | - ATIM_CCMR2_CC4S_MASK | ATIM_CCMR2_OC4M_MASK | ATIM_CCMR2_OC4PE); - ccmr1 |= ocmode1; - ccmr2 |= ocmode2; - - /* Reset the output polarity level of all channels (selects high - * polarity) - */ - - ccer &= ~(ATIM_CCER_CC1P | ATIM_CCER_CC2P | - ATIM_CCER_CC3P | ATIM_CCER_CC4P); - - /* Enable the output state of the selected channel (only) */ - - ccer &= ~(ATIM_CCER_CC1E | ATIM_CCER_CC2E | - ATIM_CCER_CC3E | ATIM_CCER_CC4E); - ccer |= ccenable; - - if (priv->tbase == STM32_TIM1_BASE) - { - /* Reset output N polarity level, output N state, output compare state, - * output compare N idle state. - */ - - ccer &= ~(ATIM_CCER_CC1NE | ATIM_CCER_CC1NP | - ATIM_CCER_CC2NE | ATIM_CCER_CC2NP | - ATIM_CCER_CC3NE | ATIM_CCER_CC3NP | - ATIM_CCER_CC4NP); - - /* Reset the output compare and output compare N IDLE State */ - - cr2 &= ~(ATIM_CR2_OIS1 | ATIM_CR2_OIS1N | - ATIM_CR2_OIS2 | ATIM_CR2_OIS2N | - ATIM_CR2_OIS3 | ATIM_CR2_OIS3N | - ATIM_CR2_OIS4); - } - else - { - ccer &= ~(GTIM_CCER_CC1NP | GTIM_CCER_CC2NP | GTIM_CCER_CC3NP); - } - - /* Save the modified register values */ - - tim_putreg(priv, STM32_GTIM_CR2_OFFSET, cr2); - tim_putreg(priv, STM32_GTIM_CCMR1_OFFSET, ccmr1); - tim_putreg(priv, STM32_GTIM_CCMR2_OFFSET, ccmr2); - tim_putreg(priv, STM32_GTIM_CCER_OFFSET, ccer); - tim_putreg(priv, STM32_GTIM_EGR_OFFSET, egr); - - /* Set the ARR Preload Bit */ - - tim_modifyreg(priv, STM32_GTIM_CR1_OFFSET, 0, GTIM_CR1_ARPE); - - /* Enable the timer counter */ - - adc_timstart(priv, true); - - tim_dumpregs(priv, "After starting timers"); - - return OK; -} -#endif - -/**************************************************************************** - * Name: adc_startconv - * - * Description: - * Start (or stop) the ADC conversion process - * - * Input Parameters: - * priv - A reference to the ADC block status - * enable - True: Start conversion - * - * Returned Value: - * - ****************************************************************************/ - -static void adc_startconv(FAR struct stm32_dev_s *priv, bool enable) -{ - uint32_t regval; - - ainfo("regular enable: %d\n", enable ? 1 : 0); - - if (enable) - { - /* Start the conversion of regular channels */ - - adc_modifyreg(priv, STM32_ADC_CR_OFFSET, 0, ADC_CR_ADSTART); - } - else - { - regval = adc_getreg(priv, STM32_ADC_CR_OFFSET); - - /* Is a conversion ongoing? */ - - if ((regval & ADC_CR_ADSTART) != 0) - { - /* Stop the conversion */ - - adc_putreg(priv, STM32_ADC_CR_OFFSET, regval | ADC_CR_ADSTP); - - /* Wait for the conversion to stop */ - - while ((adc_getreg(priv, STM32_ADC_CR_OFFSET) & ADC_CR_ADSTP) != 0); - } - } -} - -/**************************************************************************** - * Name: adc_inj_startconv - * - * Description: - * Start (or stop) the ADC conversion process - * - * Input Parameters: - * priv - A reference to the ADC block status - * enable - True: Start conversion - * - * Returned Value: - * - ****************************************************************************/ - -#ifdef ADC_HAVE_INJECTED -static void adc_inj_startconv(FAR struct stm32_dev_s *priv, bool enable) -{ - uint32_t regval; - - ainfo("injected enable: %d\n", enable ? 1 : 0); - - if (enable) - { - /* Start the conversion of regular channels */ - - adc_modifyreg(priv, STM32_ADC_CR_OFFSET, 0, ADC_CR_JADSTART); - } - else - { - regval = adc_getreg(priv, STM32_ADC_CR_OFFSET); - - /* Is a conversion ongoing? */ - - if ((regval & ADC_CR_JADSTART) != 0) - { - /* Stop the conversion */ - - adc_putreg(priv, STM32_ADC_CR_OFFSET, regval | ADC_CR_JADSTP); - - /* Wait for the conversion to stop */ - - while ((adc_getreg(priv, STM32_ADC_CR_OFFSET) & ADC_CR_JADSTP) != 0); - } - } -} -#endif - -/**************************************************************************** - * Name: adc_rccreset - * - * Description: - * Deinitializes the ADCx peripheral registers to their default - * reset values. It could set all the ADCs configured. - * - * Input Parameters: - * regaddr - The register to read - * reset - Condition, set or reset - * - * Returned Value: - * - ****************************************************************************/ - -static void adc_rccreset(FAR struct stm32_dev_s *priv, bool reset) -{ - uint32_t rstbit; - uint32_t enbit; - uint32_t rst_reg; - uint32_t en_reg; - - /* Pick the appropriate bit in the APB2 reset register. - * For the STM32 F1, there is an individual bit to reset each ADC, - * but for the STM32 F2/F4, there is one common reset for all ADCs. - * THIS will probably cause some problems! - */ - - switch (priv->intf) - { -#if defined(CONFIG_STM32_ADC1) || defined(CONFIG_STM32_ADC2) - case 1: - case 2: - { - rstbit = RCC_RSTR_ADC12RST; - enbit = RCC_RSTR_ADC12EN; - rst_reg = RCC_RSTR_ADC12RST; - en_reg = RCC_RSTR_ADC12EN; - break; - } -#endif - default: - { - return; - } - } - - /* Set or clear the selected bit in the APB2 reset register. - * modifyreg32() disables interrupts. Disabling interrupts is necessary - * because the APB2RTSR register is used by several different drivers. - */ - - if (reset) - { - /* Enable ADC reset state */ - - modifyreg32(rst_reg, 0, rstbit); - } - else - { - /* Release ADC from reset state */ - - modifyreg32(en_reg, enbit, 1); - } -} - -/**************************************************************************** - * Name: adc_enable - * - * Description: - * Enables or disables the specified ADC peripheral. Also, starts a - * conversion when the ADC is not triggered by timers - * - * Input Parameters: - * - * enable - true: enable ADC conversion - * false: disable ADC conversion - * - * Returned Value: - * - ****************************************************************************/ - -static void adc_enable(FAR struct stm32_dev_s *priv, bool enable) -{ - uint32_t regval; - - ainfo("enable: %d\n", enable ? 1 : 0); - - regval = adc_getreg(priv, STM32_ADC_CR_OFFSET); - - if (enable) - { - /* Enable the ADC */ - - adc_putreg(priv, STM32_ADC_CR_OFFSET, regval | ADC_CR_ADEN); - - /* Wait for the ADC to be ready */ - - while ((adc_getreg(priv, STM32_ADC_ISR_OFFSET) & ADC_INT_ARDY) == 0); - } - else if ((regval & ADC_CR_ADEN) != 0 && (regval & ADC_CR_ADDIS) == 0) - { - /* Stop ongoing regular conversions */ - - adc_startconv(priv, false); - -#ifdef ADC_HAVE_INJECTED - /* Stop ongoing injected conversion */ - - adc_inj_startconv(priv, false); -#endif - - /* Disable the ADC */ - - adc_putreg(priv, STM32_ADC_CR_OFFSET, regval | ADC_CR_ADDIS); - - /* Wait for the ADC to be disabled */ - - while ((adc_getreg(priv, STM32_ADC_CR_OFFSET) & ADC_CR_ADEN) != 0); - } -} - -/**************************************************************************** - * Name: adc_dmaconvcallback - * - * Description: - * Callback for DMA. Called from the DMA transfer complete interrupt after - * all channels have been converted and transferred with DMA. - * Only for regular conversion. - * - * Input Parameters: - * - * handle - handle to DMA - * isr - - * arg - adc device - * - * Returned Value: - * - ****************************************************************************/ - -#if defined(ADC_HAVE_DMA) && !defined(CONFIG_STM32_ADC_NOIRQ) -static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr, FAR void *arg) -{ - FAR struct adc_dev_s *dev = (FAR struct adc_dev_s *)arg; - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - int i; - - /* Verify that the upper-half driver has bound its callback functions */ - - if (priv->cb != NULL) - { - DEBUGASSERT(priv->cb->au_receive != NULL); - - for (i = 0; i < priv->rnchannels; i++) - { - priv->cb->au_receive(dev, priv->r_chanlist[priv->current], - priv->r_dmabuffer[priv->current]); - priv->current++; - if (priv->current >= priv->rnchannels) - { - /* Restart the conversion sequence from the beginning */ - - priv->current = 0; - } - } - } - - /* Restart DMA for the next conversion series */ - - adc_modifyreg(priv, STM32_ADC_DMAREG_OFFSET, ADC_DMAREG_DMA, 0); - adc_modifyreg(priv, STM32_ADC_DMAREG_OFFSET, 0, ADC_DMAREG_DMA); -} -#endif - -/**************************************************************************** - * Name: adc_bind - * - * Description: - * Bind the upper-half driver callbacks to the lower-half implementation. - * This must be called early in order to receive ADC event notifications. - * - ****************************************************************************/ - -static int adc_bind(FAR struct adc_dev_s *dev, - FAR const struct adc_callback_s *callback) -{ -#ifndef CONFIG_STM32_ADC_NOIRQ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - - DEBUGASSERT(priv != NULL); - priv->cb = callback; -#endif - - return OK; -} - -/**************************************************************************** - * Name: adc_reset - * - * Description: - * Reset the ADC device. Called early to initialize the hardware. - * This is called, before adc_setup() and on error conditions. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -static void adc_reset(FAR struct adc_dev_s *dev) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - irqstate_t flags; - uint32_t clrbits; - uint32_t setbits; -#ifdef ADC_HAVE_TIMER - int ret; -#endif - - ainfo("intf: %d\n", priv->intf); - flags = enter_critical_section(); - - /* Turn off the ADC so we can write the RCC bits */ - - adc_enable(priv, false); - - /* Only if this is the first instance */ - - if (priv->cmn->initialized <= 0) - { - /* Enable ADC reset state */ - - adc_rccreset(priv, true); - - /* Release ADC from reset state */ - - adc_rccreset(priv, false); - } - - /* Set voltage regular enable to intermediate state */ - - adc_modifyreg(priv, STM32_ADC_CR_OFFSET, ADC_CR_ADVREGEN_MASK, - ADC_CR_ADVREGEN_INTER); - - /* Enable the ADC voltage regulator */ - - adc_modifyreg(priv, STM32_ADC_CR_OFFSET, ADC_CR_ADVREGEN_MASK, - ADC_CR_ADVREGEN_ENABLED); - - /* Wait for the ADC voltage regulator to startup */ - - up_udelay(10); - -#if 0 /* Doesn't work */ - - /* Calibrate the ADC */ - - adc_modifyreg(priv, STM32_ADC_CR_OFFSET, ADC_CR_ADCALDIF, AD_CR_ADCAL); - - /* Wait for the calibration to complete */ - - while ((adc_getreg(priv, STM32_ADC_CR_OFFSET) & ADC_CR_ADCAL) != 0); - -#endif - - /* Initialize the watchdog 1 threshold register */ - - adc_putreg(priv, STM32_ADC_TR1_OFFSET, 0x0fff0000); - - /* Initialize the same sample time for each ADC. - * During sample cycles channel selection bits must remain unchanged. - */ - - adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, priv->smp1); - adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, priv->smp2); - - /* Enable the analog watchdog */ - - clrbits = ADC_CFGR1_AWD1CH_MASK; - setbits = ADC_CFGR1_AWD1EN | ADC_CFGR1_AWD1SGL | - (priv->r_chanlist[0] << ADC_CFGR1_AWD1CH_SHIFT); - - /* Set the resolution of the conversion */ - - clrbits |= ADC_CFGR1_RES_MASK; - setbits |= priv->resolution << ADC_CFGR1_RES_SHIFT; - -#ifdef ADC_HAVE_DMA - if (priv->hasdma) - { - /* Set DMA mode */ - - clrbits |= ADC_CFGR1_DMACFG; - - setbits |= priv->dmacfg; - - /* Enable DMA */ - - setbits |= ADC_CFGR1_DMAEN; - } -#endif - - /* Disable continuous mode and set align to right */ - - clrbits |= ADC_CFGR1_CONT | ADC_CFGR1_ALIGN; - - /* Disable external trigger for regular channels */ - - clrbits |= ADC_CFGR1_EXTEN_MASK; - setbits |= ADC_CFGR1_EXTEN_NONE; - - /* Set CFGR configuration */ - - adc_modifyreg(priv, STM32_ADC_CFGR1_OFFSET, clrbits, setbits); - -#ifndef CONFIG_STM32_ADC_NOIRQ - /* Enable interrupt flags, but disable overrun interrupt */ - - clrbits = ADC_IER_OVR; - setbits = ADC_IER_ALLINTS & ~ADC_IER_OVR; - - /* Set IER configuration */ - - adc_modifyreg(priv, STM32_ADC_IER_OFFSET, clrbits, setbits); -#endif - - /* Configuration of the regular channel conversions */ - - if (priv->cr_channels > 0) - { - adc_set_ch(dev, 0); - } - - /* ADC CCR configuration */ - - clrbits = ADC_CCR_DUAL_MASK | ADC_CCR_DELAY_MASK | ADC_CCR_DMACFG | - ADC_CCR_MDMA_MASK | ADC_CCR_CKMODE_MASK | ADC_CCR_VREFEN | - ADC_CCR_TSEN | ADC_CCR_VBATEN; - setbits = ADC_CCR_DUAL_IND | ADC_CCR_DELAY(0) | ADC_CCR_MDMA_DISABLED | - ADC_CCR_CKMODE_ASYNCH; - - if (priv->base == STM32_ADC1_BASE || priv->base == STM32_ADC2_BASE) - { - stm32_modifyreg32(STM32_ADC12_CCR, clrbits, setbits); - } - - stm32_modifyreg32(STM32_ADC12_CCR, clrbits, setbits); - -#ifdef ADC_HAVE_DMA - - /* Enable DMA */ - - if (priv->hasdma) - { - /* Stop and free DMA if it was started before */ - - if (priv->dma != NULL) - { - stm32_dmastop(priv->dma); - stm32_dmafree(priv->dma); - } - - priv->dma = stm32_dmachannel(priv->dmachan); - -#ifndef CONFIG_STM32_ADC_NOIRQ - stm32_dmasetup(priv->dma, - priv->base + STM32_ADC_DR_OFFSET, - (uint32_t)priv->r_dmabuffer, - priv->rnchannels, - ADC_DMA_CONTROL_WORD); - - stm32_dmastart(priv->dma, adc_dmaconvcallback, dev, false); -#endif - } - -#endif - - /* Set ADON to wake up the ADC from the power down state */ - - adc_enable(priv, true); - - /* EXTSEL selection: These bits select the external event used - * to trigger the start of conversion of a regular group. NOTE: - * - * - The position with of the EXTSEL field varies from one STM32 MCU - * to another. - * - The width of the EXTSEL field varies from one STM32 MCU to another. - * - The value in priv->extsel is already shifted into the correct bit - * position. - */ - -#ifdef ADC_HAVE_EXTSEL - if (priv->extsel & HAVE_EXTSEL_MASK) - { - ainfo("Initializing extsel = 0x%08x\n", (priv->extsel & ~HAVE_EXTSEL_MASK)); - - adc_modifyreg(priv, STM32_ADC_EXTREG_OFFSET, - ADC_EXTREG_EXTEN_MASK | ADC_EXTREG_EXTSEL_MASK, - ADC_EXTREG_EXTEN_DEFAULT | (priv->extsel & ~HAVE_EXTSEL_MASK)); - } -#endif - -#ifdef ADC_HAVE_INJECTED - /* Configuration of the injected channel conversions after adc enabled */ - - if (priv->cj_channels > 0) - { - adc_inj_set_ch(dev, 0); - } -#endif - -#ifdef ADC_HAVE_TIMER - if (priv->tbase != 0) - { - ret = adc_timinit(priv); - if (ret < 0) - { - aerr("ERROR: adc_timinit failed: %d\n", ret); - } - } -#ifndef CONFIG_STM32_ADC_NO_STARTUP_CONV - else -#endif -#endif -#ifndef CONFIG_STM32_ADC_NO_STARTUP_CONV - { - adc_startconv(priv, true); - -#ifdef ADC_HAVE_INJECTED - adc_inj_startconv(priv, true); -#endif - } -#endif - - leave_critical_section(flags); - - ainfo("ISR: 0x%08x CR: 0x%08x CFGR: 0x%08x\n", - adc_getreg(priv, STM32_ADC_ISR_OFFSET), - adc_getreg(priv, STM32_ADC_CR_OFFSET), - adc_getreg(priv, STM32_ADC_CFGR1_OFFSET)); - - ainfo("SQR1: 0x%08x SQR2: 0x%08x SQR3: 0x%08x\n", - adc_getreg(priv, STM32_ADC_SQR1_OFFSET), - adc_getreg(priv, STM32_ADC_SQR2_OFFSET), - adc_getreg(priv, STM32_ADC_SQR3_OFFSET)); - - ainfo("SQR4: 0x%08x\n", adc_getreg(priv, STM32_ADC_SQR4_OFFSET)); - - if (priv->base == STM32_ADC1_BASE || priv->base == STM32_ADC2_BASE) - { - ainfo("CCR: 0x%08x\n", getreg32(STM32_ADC12_CCR)); - } - - ainfo("SMPR1: 0x%08x SMPR2: 0x%08x\n", - adc_getreg(priv, STM32_ADC_SMPR1_OFFSET), - adc_getreg(priv, STM32_ADC_SMPR2_OFFSET)); - - ainfo("JSQR: 0x%08x DIFSEL: 0x%08x IER: 0x%08x\n", - adc_getreg(priv, STM32_ADC_JSQR_OFFSET), - adc_getreg(priv, STM32_ADC_DIFSEL_OFFSET), - adc_getreg(priv, STM32_ADC_IER_OFFSET)); -} - -/**************************************************************************** - * Name: adc_setup - * - * Description: - * Configure the ADC. This method is called the first time that the ADC - * device is opened. This will occur when the port is first opened. - * This setup includes configuring and attaching ADC interrupts. - * Interrupts are all disabled upon return. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -static int adc_setup(FAR struct adc_dev_s *dev) -{ -#ifndef CONFIG_STM32_ADC_NOIRQ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; -#endif - int ret = OK; - - /* Attach the ADC interrupt */ - -#ifndef CONFIG_STM32_ADC_NOIRQ - ret = irq_attach(priv->irq, priv->isr, NULL); - if (ret < 0) - { - ainfo("irq_attach failed: %d\n", ret); - return ret; - } -#endif - - /* Make sure that the ADC device is in the powered up, reset state */ - - adc_reset(dev); - - /* Enable the ADC interrupt */ - -#ifndef CONFIG_STM32_ADC_NOIRQ - ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq); - up_enable_irq(priv->irq); -#endif - - return ret; -} - -/**************************************************************************** - * Name: adc_shutdown - * - * Description: - * Disable the ADC. This method is called when the ADC device is closed. - * This method reverses the operation the setup method. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -static void adc_shutdown(FAR struct adc_dev_s *dev) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - - adc_enable(priv, false); - - /* Disable ADC interrupts and detach the ADC interrupt handler */ - -#ifndef CONFIG_STM32_ADC_NOIRQ - up_disable_irq(priv->irq); - irq_detach(priv->irq); -#endif - - if (priv->cmn->initialized <= 1) - { - /* Disable and reset the ADC module only when last instance */ - - adc_rccreset(priv, true); - - /* Decrease instances counter */ - } - - priv->cmn->initialized -= 1; -} - -/**************************************************************************** - * Name: adc_rxint - * - * Description: - * Call to enable or disable RX interrupts. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -static void adc_rxint(FAR struct adc_dev_s *dev, bool enable) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - uint32_t regval; - - ainfo("intf: %d enable: %d\n", priv->intf, enable ? 1 : 0); - - if (enable) - { - /* Enable the analog watchdog / overrun interrupts, and if no DMA, - * end-of-conversion ADC. - */ - - regval = ADC_IER_ALLINTS; -#ifdef ADC_HAVE_DMA - if (priv->hasdma) - { - regval &= ~(ADC_IER_EOC | ADC_IER_JEOC); - } -#endif - - adc_modifyreg(priv, STM32_ADC_IER_OFFSET, 0, regval); - } - else - { - /* Disable all ADC interrupts */ - - adc_modifyreg(priv, STM32_ADC_IER_OFFSET, ADC_IER_ALLINTS, 0); - } -} - -/**************************************************************************** - * Name: adc_sqrbits - ****************************************************************************/ - -static uint32_t adc_sqrbits(FAR struct stm32_dev_s *priv, int first, int last, - int offset) -{ - uint32_t bits = 0; - int i; - - for (i = first - 1; - i < priv->rnchannels && i < last; - i++, offset += ADC_SQ_OFFSET) - { - bits |= ((uint32_t)priv->r_chanlist[i]) << offset; - } - - return bits; -} - -/**************************************************************************** - * Name: adc_set_ch - * - * Description: - * Sets the ADC channel. - * - * Input Parameters: - * dev - pointer to device structure used by the driver - * ch - ADC channel number + 1. 0 reserved for all configured channels - * - * Returned Value: - * int - errno - * - ****************************************************************************/ - -static int adc_set_ch(FAR struct adc_dev_s *dev, uint8_t ch) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - uint32_t bits; - int i; - - if (ch == 0) - { - priv->current = 0; - priv->rnchannels = priv->cr_channels; - } - else - { - for (i = 0; i < priv->cr_channels && priv->r_chanlist[i] != ch - 1; i++); - - if (i >= priv->cr_channels) - { - return -ENODEV; - } - - priv->current = i; - priv->rnchannels = 1; - } - - bits = adc_sqrbits(priv, ADC_SQR4_FIRST, ADC_SQR4_LAST, ADC_SQR4_SQ_OFFSET); - adc_modifyreg(priv, STM32_ADC_SQR4_OFFSET, ~ADC_SQR4_RESERVED, bits); - - bits = adc_sqrbits(priv, ADC_SQR3_FIRST, ADC_SQR3_LAST, ADC_SQR3_SQ_OFFSET); - adc_modifyreg(priv, STM32_ADC_SQR3_OFFSET, ~ADC_SQR3_RESERVED, bits); - - bits = adc_sqrbits(priv, ADC_SQR2_FIRST, ADC_SQR2_LAST, ADC_SQR2_SQ_OFFSET); - adc_modifyreg(priv, STM32_ADC_SQR2_OFFSET, ~ADC_SQR2_RESERVED, bits); - - bits = ((uint32_t)priv->rnchannels - 1) << ADC_SQR1_L_SHIFT | - adc_sqrbits(priv, ADC_SQR1_FIRST, ADC_SQR1_LAST, ADC_SQR1_SQ_OFFSET); - adc_modifyreg(priv, STM32_ADC_SQR1_OFFSET, ~ADC_SQR1_RESERVED, bits); - - return OK; -} - -#ifdef ADC_HAVE_INJECTED -static int adc_inj_set_ch(FAR struct adc_dev_s *dev, uint8_t ch) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - uint32_t regval = 0; - int i; - - /* Configure JEXTSEL */ - - if (priv->jextsel & HAVE_EXTSEL_MASK) - { - ainfo("Initializing jextsel = 0x%08x\n", (priv->jextsel & ~HAVE_EXTSEL_MASK)); - - regval = ADC_JEXTREG_JEXTEN_DEFAULT | (priv->jextsel & ~HAVE_EXTSEL_MASK); - } - - /* Configure injected sequence length */ - - regval |= ADC_JSQR_JL(priv->cj_channels); - - /* Configure injected channels */ - - for (i = 0 ; i < priv->cj_channels; i += 1) - { - regval |= priv->j_chanlist[i] << (ADC_JSQR_JSQ1_SHIFT + 6 * i); - } - - adc_putreg(priv, STM32_ADC_JSQR_OFFSET, regval); - - return OK; -} -#endif - -/**************************************************************************** - * Name: adc_ioctl - * - * Description: - * All ioctl calls will be routed through this method. - * - * Input Parameters: - * dev - pointer to device structure used by the driver - * cmd - command - * arg - arguments passed with command - * - * Returned Value: - * - ****************************************************************************/ - -static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - int ret = OK; - - switch (cmd) - { - case ANIOC_TRIGGER: - { - /* Start regular conversion if regular channels configured */ - - if (priv->cr_channels > 0) - { - adc_startconv(priv, true); - } - -#ifdef ADC_HAVE_INJECTED - /* Start injected conversion if injected channels configured */ - - if (priv->cj_channels > 0) - { - adc_inj_startconv(priv, true); - } -#endif - - break; - } - default: - { - aerr("ERROR: Unknown cmd: %d\n", cmd); - ret = -ENOTTY; - break; - } - } - - return ret; -} - -/**************************************************************************** - * Name: adc_interrupt - * - * Description: - * Common ADC interrupt handler. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -#ifndef CONFIG_STM32_ADC_NOIRQ -static int adc_interrupt(FAR struct adc_dev_s *dev) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev->ad_priv; - uint32_t regval; - uint32_t pending; - int32_t data; - - regval = adc_getreg(priv, STM32_ADC_ISR_OFFSET); - pending = regval & ADC_ISR_ALLINTS; - if (pending == 0) - { - return OK; - } - - /* Identifies the interruption AWD, OVR or EOC */ - - if ((regval & ADC_ISR_AWD) != 0) - { - awarn("WARNING: Analog Watchdog, Value converted out of range!\n"); - } - - if ((regval & ADC_ISR_OVR) != 0) - { - awarn("WARNING: Overrun has occurred!\n"); - } - - /* EOC: End of conversion */ - - if ((regval & ADC_ISR_EOC) != 0) - { - /* Read the converted value and clear EOC bit - * (It is cleared by reading the ADC_DR) - */ - - data = adc_getreg(priv, STM32_ADC_DR_OFFSET) & ADC_DR_RDATA_MASK; - - /* Verify that the upper-half driver has bound its callback functions */ - - if (priv->cb != NULL) - { - /* Give the ADC data to the ADC driver. The ADC receive() method - * accepts 3 parameters: - * - * 1) The first is the ADC device instance for this ADC block. - * 2) The second is the channel number for the data, and - * 3) The third is the converted data for the channel. - */ - - DEBUGASSERT(priv->cb->au_receive != NULL); - priv->cb->au_receive(dev, priv->r_chanlist[priv->current], data); - } - - /* Set the channel number of the next channel that will complete - * conversion. - */ - - priv->current++; - - if (priv->current >= priv->rnchannels) - { - /* Restart the conversion sequence from the beginning */ - - priv->current = 0; - } - } - - /* Clear pending interrupts */ - - adc_putreg(priv, STM32_ADC_ISR_OFFSET, pending); - - return OK; -} -#endif - -/**************************************************************************** - * Name: adc12_interrupt - * - * Description: - * ADC1/2 interrupt handler for the STM32 F1/F3 families. - * - * Input Parameters: - * - * Returned Value: - * - ****************************************************************************/ - -#ifndef CONFIG_STM32_ADC_NOIRQ -static int adc12_interrupt(int irq, FAR void *context, FAR void *arg) -{ -#ifdef CONFIG_STM32_ADC1 - adc_interrupt(&g_adcdev1); -#endif - -#ifdef CONFIG_STM32_ADC2 - adc_interrupt(&g_adcdev2); -#endif - - return OK; -} -#endif - -#ifdef CONFIG_STM32_ADC_NOIRQ - -/**************************************************************************** - * Name: adc_intack - ****************************************************************************/ - -static void adc_intack(FAR struct stm32_adc_dev_s *dev, uint32_t source) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; - - /* Clear pending interrupts */ - - adc_putreg(priv, STM32_ADC_ISR_OFFSET, source); -} - -/**************************************************************************** - * Name: adc_inten - ****************************************************************************/ - -static void adc_inten(FAR struct stm32_adc_dev_s *dev, uint32_t source) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; - - /* Enable interrupts */ - - adc_modifyreg(priv, STM32_ADC_IER_OFFSET, 0, source); -} - -/**************************************************************************** - * Name: adc_intdis - ****************************************************************************/ - -static void adc_intdis(FAR struct stm32_adc_dev_s *dev, uint32_t source) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; - - /* Disable interrupts */ - - adc_modifyreg(priv, STM32_ADC_IER_OFFSET, source, 0); -} - -/**************************************************************************** - * Name: adc_ackget - ****************************************************************************/ - -static uint32_t adc_intget(FAR struct stm32_adc_dev_s *dev) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; - uint32_t regval; - uint32_t pending; - - regval = adc_getreg(priv, STM32_ADC_ISR_OFFSET); - pending = regval & ADC_ISR_ALLINTS; - - return pending; -} - - -/**************************************************************************** - * Name: adc_regget - ****************************************************************************/ - -static uint32_t adc_regget(FAR struct stm32_adc_dev_s *dev) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; - - return adc_getreg(priv, STM32_ADC_DR_OFFSET) & ADC_DR_RDATA_MASK; -} - -/**************************************************************************** - * Name: adc_regbufregister - ****************************************************************************/ -#ifdef ADC_HAVE_DMA -static int adc_regbufregister(FAR struct stm32_adc_dev_s *dev, uint16_t *buffer, uint8_t len) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; - - stm32_dmasetup(priv->dma, - priv->base + STM32_ADC_DR_OFFSET, - (uint32_t)buffer, - len, - ADC_DMA_CONTROL_WORD); - - /* No DMA callback */ - - stm32_dmastart(priv->dma, NULL, dev, false); - - return OK; -} -#endif - -/**************************************************************************** - * Name: adc_inj_get - ****************************************************************************/ - -#ifdef ADC_HAVE_INJECTED -static uint32_t adc_injget(FAR struct stm32_adc_dev_s *dev, uint8_t chan) -{ - FAR struct stm32_dev_s *priv = (FAR struct stm32_dev_s *)dev; - uint32_t regval = 0; - - if (chan > priv->cj_channels-1) - { - goto errout; - } - - regval = adc_getreg(priv, STM32_ADC_JDR1_OFFSET+4*(chan)) & ADC_JDR_JDATA_MASK; - -errout: - return regval; -} -#endif -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_adcinitialize - * - * Description: - * Initialize the ADC. - * - * TODO: describe injected channels configuration. - * - * The logic is, save rnchannels : # of channels (conversions) in ADC_SQR1_L - * Then, take the chanlist array and store it in the SQR Regs, - * chanlist[0] -> ADC_SQR3_SQ1 - * chanlist[1] -> ADC_SQR3_SQ2 - * ... - * chanlist[15]-> ADC_SQR1_SQ16 - * - * up to - * chanlist[rnchannels] - * - * Input Parameters: - * intf - Could be {1,2,3} for ADC1, ADC2, or ADC3 - * chanlist - The list of channels - * cchannels - Number of channels - * - * Returned Value: - * Valid ADC device structure reference on succcess; a NULL on failure - * - ****************************************************************************/ - -struct adc_dev_s *stm32_adcinitialize(int intf, FAR const uint8_t *chanlist, - int channels) -{ - FAR struct adc_dev_s *dev; - FAR struct stm32_dev_s *priv; - uint8_t cr_channels = 0; -#ifdef ADC_HAVE_INJECTED - uint8_t cj_channels = 0; - FAR uint8_t *j_chanlist = NULL; -#endif - - switch (intf) - { -#ifdef CONFIG_STM32_ADC1 - case 1: - { - ainfo("ADC1 selected\n"); - dev = &g_adcdev1; - cr_channels = channels - ADC1_INJECTED_CHAN; -#ifdef ADC_HAVE_INJECTED - cj_channels = ADC1_INJECTED_CHAN; - j_chanlist = (FAR uint8_t *)chanlist + cr_channels; -#endif - break; - } -#endif -#ifdef CONFIG_STM32_ADC2 - case 2: - { - ainfo("ADC2 selected\n"); - dev = &g_adcdev2; - cr_channels = channels - ADC2_INJECTED_CHAN; -#ifdef ADC_HAVE_INJECTED - cj_channels = ADC2_INJECTED_CHAN; - j_chanlist = (FAR uint8_t *)chanlist + cr_channels; -#endif - break; - } -#endif - default: - { - aerr("ERROR: No ADC interface defined\n"); - return NULL; - } - } - - /* Configure the selected ADC */ - - priv = (FAR struct stm32_dev_s *)dev->ad_priv; - - DEBUGASSERT(cr_channels <= ADC_REG_MAX_SAMPLES); - - /* Configure regular channels */ - - priv->cr_channels = cr_channels; - memcpy(priv->r_chanlist, chanlist, cr_channels); - -#ifdef ADC_HAVE_INJECTED - /* Configure injected channels */ - - DEBUGASSERT(cj_channels <= ADC_INJ_MAX_SAMPLES); - - priv->cj_channels = cj_channels; - memcpy(priv->j_chanlist, j_chanlist, cj_channels); -#endif - -#ifndef CONFIG_STM32_ADC_NOIRQ - priv->cb = NULL; -#endif - -#ifdef ADC_HAVE_INJECTED - ainfo("intf: %d cr_channels: %d, cj_channels: %d\n", - intf, priv->cr_channels, priv->cj_channels); -#else - ainfo("intf: %d cr_channels: %d\n", intf, priv->cr_channels); -#endif - - /* Increase instances counter */ - - priv->cmn->initialized += 1; - - return dev; -} - -#endif /* CONFIG_STM32_STM32F33XX */ -#endif /* CONFIG_STM32_ADC1 || CONFIG_STM32_ADC2 */ -#endif /* CONFIG_STM32_ADC */ diff --git a/arch/arm/src/stm32/stm32f33xxx_dma.c b/arch/arm/src/stm32/stm32f33xxx_dma.c deleted file mode 100644 index 4b6379981d..0000000000 --- a/arch/arm/src/stm32/stm32f33xxx_dma.c +++ /dev/null @@ -1,731 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32/stm32f33xxx_dma.c - * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt - * Mateusz Szafoni - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "up_arch.h" -#include "up_internal.h" -#include "sched/sched.h" -#include "chip.h" -#include "stm32_dma.h" -#include "stm32.h" - -#if defined(CONFIG_STM32_DMA1) && defined(CONFIG_STM32_STM32F33XX) - -#ifndef CONFIG_ARCH_DMA -# warning "STM32 DMA enabled but CONFIG_ARCH_DMA disabled" -#endif - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define DMA1_NCHANNELS 7 -#define DMA_NCHANNELS DMA1_NCHANNELS - -#ifndef CONFIG_DMA_PRI -# define CONFIG_DMA_PRI NVIC_SYSH_PRIORITY_DEFAULT -#endif - -/* Convert the DMA channel base address to the DMA register block address */ - -#define DMA_BASE(ch) (ch & 0xfffffc00) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure descibes one DMA channel */ - -struct stm32_dma_s -{ - uint8_t chan; /* DMA channel number (0-6) */ - uint8_t irq; /* DMA channel IRQ number */ - sem_t sem; /* Used to wait for DMA channel to become available */ - uint32_t base; /* DMA register channel base address */ - dma_callback_t callback; /* Callback invoked when the DMA completes */ - void *arg; /* Argument passed to callback function */ -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This array describes the state of each DMA */ - -static struct stm32_dma_s g_dma[DMA_NCHANNELS] = -{ - { - .chan = 0, - .irq = STM32_IRQ_DMA1CH1, - .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(0), - }, - { - .chan = 1, - .irq = STM32_IRQ_DMA1CH2, - .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(1), - }, - { - .chan = 2, - .irq = STM32_IRQ_DMA1CH3, - .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(2), - }, - { - .chan = 3, - .irq = STM32_IRQ_DMA1CH4, - .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(3), - }, - { - .chan = 4, - .irq = STM32_IRQ_DMA1CH5, - .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(4), - }, - { - .chan = 5, - .irq = STM32_IRQ_DMA1CH6, - .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(5), - }, - { - .chan = 6, - .irq = STM32_IRQ_DMA1CH7, - .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(6), - }, -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * DMA register access functions - ****************************************************************************/ - -/* Get non-channel register from DMA1 or DMA2 */ - -static inline uint32_t dmabase_getreg(struct stm32_dma_s *dmach, uint32_t offset) -{ - return getreg32(DMA_BASE(dmach->base) + offset); -} - -/* Write to non-channel register in DMA1 or DMA2 */ - -static inline void dmabase_putreg(struct stm32_dma_s *dmach, uint32_t offset, uint32_t value) -{ - putreg32(value, DMA_BASE(dmach->base) + offset); -} - -/* Get channel register from DMA1 or DMA2 */ - -static inline uint32_t dmachan_getreg(struct stm32_dma_s *dmach, uint32_t offset) -{ - return getreg32(dmach->base + offset); -} - -/* Write to channel register in DMA1 or DMA2 */ - -static inline void dmachan_putreg(struct stm32_dma_s *dmach, uint32_t offset, uint32_t value) -{ - putreg32(value, dmach->base + offset); -} - -/************************************************************************************ - * Name: stm32_dmatake() and stm32_dmagive() - * - * Description: - * Used to get exclusive access to a DMA channel. - * - ************************************************************************************/ - -static void stm32_dmatake(FAR struct stm32_dma_s *dmach) -{ - int ret; - - do - { - /* Take the semaphore (perhaps waiting) */ - - ret = nxsem_wait(&dmach->sem); - - /* The only case that an error should occur here is if the wait was - * awakened by a signal. - */ - - DEBUGASSERT(ret == OK || ret == -EINTR); - } - while (ret == -EINTR); -} - -static inline void stm32_dmagive(FAR struct stm32_dma_s *dmach) -{ - (void)nxsem_post(&dmach->sem); -} - -/************************************************************************************ - * Name: stm32_dmachandisable - * - * Description: - * Disable the DMA channel - * - ************************************************************************************/ - -static void stm32_dmachandisable(struct stm32_dma_s *dmach) -{ - uint32_t regval; - - /* Disable all interrupts at the DMA controller */ - - regval = dmachan_getreg(dmach, STM32_DMACHAN_CCR_OFFSET); - regval &= ~DMA_CCR_ALLINTS; - - /* Disable the DMA channel */ - - regval &= ~DMA_CCR_EN; - dmachan_putreg(dmach, STM32_DMACHAN_CCR_OFFSET, regval); - - /* Clear pending channel interrupts */ - - dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET, DMA_ISR_CHAN_MASK(dmach->chan)); -} - -/************************************************************************************ - * Name: stm32_dmainterrupt - * - * Description: - * DMA interrupt handler - * - ************************************************************************************/ - -static int stm32_dmainterrupt(int irq, void *context, FAR void *arg) -{ - struct stm32_dma_s *dmach; - uint32_t isr; - int chndx = 0; - - /* Get the channel structure from the interrupt number */ - - if (irq >= STM32_IRQ_DMA1CH1 && irq <= STM32_IRQ_DMA1CH7) - { - chndx = irq - STM32_IRQ_DMA1CH1; - } - else - { - DEBUGPANIC(); - } - dmach = &g_dma[chndx]; - - /* Get the interrupt status (for this channel only) */ - - isr = dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) & DMA_ISR_CHAN_MASK(dmach->chan); - - /* Clear the interrupts we are handling */ - - dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET, isr); - - /* Invoke the callback */ - - if (dmach->callback) - { - dmach->callback(dmach, isr >> DMA_ISR_CHAN_SHIFT(dmach->chan), dmach->arg); - } - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stm32_dmainitialize - * - * Description: - * Initialize the DMA subsystem - * - * Returned Value: - * None - * - ****************************************************************************/ - -void weak_function up_dma_initialize(void) -{ - struct stm32_dma_s *dmach; - int chndx; - - /* Initialize each DMA channel */ - - for (chndx = 0; chndx < DMA_NCHANNELS; chndx++) - { - dmach = &g_dma[chndx]; - nxsem_init(&dmach->sem, 0, 1); - - /* Attach DMA interrupt vectors */ - - (void)irq_attach(dmach->irq, stm32_dmainterrupt, NULL); - - /* Disable the DMA channel */ - - stm32_dmachandisable(dmach); - - /* Enable the IRQ at the NVIC (still disabled at the DMA controller) */ - - up_enable_irq(dmach->irq); - -#ifdef CONFIG_ARCH_IRQPRIO - /* Set the interrupt priority */ - - up_prioritize_irq(dmach->irq, CONFIG_DMA_PRI); -#endif - } -} - -/**************************************************************************** - * Name: stm32_dmachannel - * - * Description: - * Allocate a DMA channel. This function gives the caller mutually - * exclusive access to the DMA channel specified by the 'chndx' argument. - * DMA channels are shared on the STM32: Devices sharing the same DMA - * channel cannot do DMA concurrently! See the DMACHAN_* definitions in - * stm32_dma.h. - * - * If the DMA channel is not available, then stm32_dmachannel() will wait - * until the holder of the channel relinquishes the channel by calling - * stm32_dmafree(). WARNING: If you have two devices sharing a DMA - * channel and the code never releases the channel, the stm32_dmachannel - * call for the other will hang forever in this function! Don't let your - * design do that! - * - * Hmm.. I suppose this interface could be extended to make a non-blocking - * version. Feel free to do that if that is what you need. - * - * Input Parameters: - * chndx - Identifies the stream/channel resource. For the STM32 F1, this - * is simply the channel number as provided by the DMACHAN_* definitions - * in chip/stm32f10xxx_dma.h. - * - * Returned Value: - * Provided that 'chndx' is valid, this function ALWAYS returns a non-NULL, - * void* DMA channel handle. (If 'chndx' is invalid, the function will - * assert if debug is enabled or do something ignorant otherwise). - * - * Assumptions: - * - The caller does not hold he DMA channel. - * - The caller can wait for the DMA channel to be freed if it is no - * available. - * - ****************************************************************************/ - -DMA_HANDLE stm32_dmachannel(unsigned int chndx) -{ - struct stm32_dma_s *dmach = &g_dma[chndx]; - - DEBUGASSERT(chndx < DMA_NCHANNELS); - - /* Get exclusive access to the DMA channel -- OR wait until the channel - * is available if it is currently being used by another driver - */ - - stm32_dmatake(dmach); - - /* The caller now has exclusive use of the DMA channel */ - - return (DMA_HANDLE)dmach; -} - -/**************************************************************************** - * Name: stm32_dmafree - * - * Description: - * Release a DMA channel. If another thread is waiting for this DMA channel - * in a call to stm32_dmachannel, then this function will re-assign the - * DMA channel to that thread and wake it up. NOTE: The 'handle' used - * in this argument must NEVER be used again until stm32_dmachannel() is - * called again to re-gain access to the channel. - * - * Returned Value: - * None - * - * Assumptions: - * - The caller holds the DMA channel. - * - There is no DMA in progress - * - ****************************************************************************/ - -void stm32_dmafree(DMA_HANDLE handle) -{ - struct stm32_dma_s *dmach = (struct stm32_dma_s *)handle; - - DEBUGASSERT(handle != NULL); - - /* Release the channel */ - - stm32_dmagive(dmach); -} - -/**************************************************************************** - * Name: stm32_dmasetup - * - * Description: - * Configure DMA before using - * - ****************************************************************************/ - -void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, - size_t ntransfers, uint32_t ccr) -{ - struct stm32_dma_s *dmach = (struct stm32_dma_s *)handle; - uint32_t regval; - - /* Then DMA_CNDTRx register can only be modified if the DMA channel is - * disabled. - */ - - regval = dmachan_getreg(dmach, STM32_DMACHAN_CCR_OFFSET); - regval &= ~(DMA_CCR_EN); - dmachan_putreg(dmach, STM32_DMACHAN_CCR_OFFSET, regval); - - /* Set the peripheral register address in the DMA_CPARx register. The data - * will be moved from/to this address to/from the memory after the - * peripheral event. - */ - - dmachan_putreg(dmach, STM32_DMACHAN_CPAR_OFFSET, paddr); - - /* Set the memory address in the DMA_CMARx register. The data will be - * written to or read from this memory after the peripheral event. - */ - - dmachan_putreg(dmach, STM32_DMACHAN_CMAR_OFFSET, maddr); - - /* Configure the total number of data to be transferred in the DMA_CNDTRx - * register. After each peripheral event, this value will be decremented. - */ - - dmachan_putreg(dmach, STM32_DMACHAN_CNDTR_OFFSET, ntransfers); - - /* Configure the channel priority using the PL[1:0] bits in the DMA_CCRx - * register. Configure data transfer direction, circular mode, peripheral & memory - * incremented mode, peripheral & memory data size, and interrupt after - * half and/or full transfer in the DMA_CCRx register. - */ - - regval = dmachan_getreg(dmach, STM32_DMACHAN_CCR_OFFSET); - regval &= ~(DMA_CCR_MEM2MEM | DMA_CCR_PL_MASK | DMA_CCR_MSIZE_MASK | - DMA_CCR_PSIZE_MASK | DMA_CCR_MINC | DMA_CCR_PINC | DMA_CCR_CIRC | - DMA_CCR_DIR); - ccr &= (DMA_CCR_MEM2MEM | DMA_CCR_PL_MASK | DMA_CCR_MSIZE_MASK | - DMA_CCR_PSIZE_MASK | DMA_CCR_MINC | DMA_CCR_PINC | DMA_CCR_CIRC | - DMA_CCR_DIR); - regval |= ccr; - dmachan_putreg(dmach, STM32_DMACHAN_CCR_OFFSET, regval); -} - -/**************************************************************************** - * Name: stm32_dmastart - * - * Description: - * Start the DMA transfer - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - No DMA in progress - * - ****************************************************************************/ - -void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, - void *arg, bool half) -{ - struct stm32_dma_s *dmach = (struct stm32_dma_s *)handle; - uint32_t ccr; - - DEBUGASSERT(handle != NULL); - - /* Save the callback info. This will be invoked whent the DMA commpletes */ - - dmach->callback = callback; - dmach->arg = arg; - - /* Activate the channel by setting the ENABLE bit in the DMA_CCRx register. - * As soon as the channel is enabled, it can serve any DMA request from the - * peripheral connected on the channel. - */ - - ccr = dmachan_getreg(dmach, STM32_DMACHAN_CCR_OFFSET); - ccr |= DMA_CCR_EN; - - /* In normal mode, interrupt at either half or full completion. In circular mode, - * always interrupt on buffer wrap, and optionally interrupt at the halfway point. - */ - - if ((ccr & DMA_CCR_CIRC) == 0) - { - /* Once half of the bytes are transferred, the half-transfer flag (HTIF) is - * set and an interrupt is generated if the Half-Transfer Interrupt Enable - * bit (HTIE) is set. At the end of the transfer, the Transfer Complete Flag - * (TCIF) is set and an interrupt is generated if the Transfer Complete - * Interrupt Enable bit (TCIE) is set. - */ - - ccr |= (half ? (DMA_CCR_HTIE | DMA_CCR_TEIE) : (DMA_CCR_TCIE | DMA_CCR_TEIE)); - } - else - { - /* In nonstop mode, when the transfer completes it immediately resets - * and starts again. The transfer-complete interrupt is thus always - * enabled, and the half-complete interrupt can be used in circular - * mode to determine when the buffer is half-full, or in double-buffered - * mode to determine when one of the two buffers is full. - */ - - ccr |= (half ? DMA_CCR_HTIE : 0) | DMA_CCR_TCIE | DMA_CCR_TEIE; - } - - dmachan_putreg(dmach, STM32_DMACHAN_CCR_OFFSET, ccr); -} - -/**************************************************************************** - * Name: stm32_dmastop - * - * Description: - * Cancel the DMA. After stm32_dmastop() is called, the DMA channel is - * reset and stm32_dmasetup() must be called before stm32_dmastart() can be - * called again - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - ****************************************************************************/ - -void stm32_dmastop(DMA_HANDLE handle) -{ - struct stm32_dma_s *dmach = (struct stm32_dma_s *)handle; - stm32_dmachandisable(dmach); -} - -/**************************************************************************** - * Name: stm32_dmaresidual - * - * Description: - * Returns the number of bytes remaining to be transferred - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - ****************************************************************************/ - -size_t stm32_dmaresidual(DMA_HANDLE handle) -{ - struct stm32_dma_s *dmach = (struct stm32_dma_s *)handle; - - return dmachan_getreg(dmach, STM32_DMACHAN_CNDTR_OFFSET); -} - -/**************************************************************************** - * Name: stm32_dmacapable - * - * Description: - * Check if the DMA controller can transfer data to/from given memory - * address. This depends on the internal connections in the ARM bus matrix - * of the processor. Note that this only applies to memory addresses, it - * will return false for any peripheral address. - * - * Returned Value: - * True, if transfer is possible. - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_DMACAPABLE -bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr) -{ - uint32_t transfer_size; - uint32_t mend; - - /* Verify that the address conforms to the memory transfer size. - * Transfers to/from memory performed by the DMA controller are - * required to be aligned to their size. - * - * See ST RM0090 rev4, section 9.3.11 - * - * Compute mend inline to avoid a possible non-constant integer - * multiply. - */ - - switch (ccr & DMA_CCR_MSIZE_MASK) - { - case DMA_CCR_MSIZE_8BITS: - transfer_size = 1; - mend = maddr + count - 1; - break; - - case DMA_CCR_MSIZE_16BITS: - transfer_size = 2; - mend = maddr + (count << 1) - 1; - break; - - case DMA_CCR_MSIZE_32BITS: - transfer_size = 4; - mend = maddr + (count << 2) - 1; - break; - - default: - return false; - } - - if ((maddr & (transfer_size - 1)) != 0) - { - return false; - } - - /* Verify that the transfer is to a memory region that supports DMA. */ - - if ((maddr & STM32_REGION_MASK) != (mend & STM32_REGION_MASK)) - { - return false; - } - - switch (maddr & STM32_REGION_MASK) - { - case STM32_SRAM_BASE: - case STM32_CODE_BASE: - /* All RAM and flash is supported */ - - return true; - - default: - /* Everything else is unsupported by DMA */ - - return false; - } -} -#endif - -/**************************************************************************** - * Name: stm32_dmasample - * - * Description: - * Sample DMA register contents - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - ****************************************************************************/ - -#ifdef CONFIG_DEBUG_DMA_INFO -void stm32_dmasample(DMA_HANDLE handle, struct stm32_dmaregs_s *regs) -{ - struct stm32_dma_s *dmach = (struct stm32_dma_s *)handle; - irqstate_t flags; - - flags = enter_critical_section(); - regs->isr = dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET); - regs->ccr = dmachan_getreg(dmach, STM32_DMACHAN_CCR_OFFSET); - regs->cndtr = dmachan_getreg(dmach, STM32_DMACHAN_CNDTR_OFFSET); - regs->cpar = dmachan_getreg(dmach, STM32_DMACHAN_CPAR_OFFSET); - regs->cmar = dmachan_getreg(dmach, STM32_DMACHAN_CMAR_OFFSET); - leave_critical_section(flags); -} -#endif - -/**************************************************************************** - * Name: stm32_dmadump - * - * Description: - * Dump previously sampled DMA register contents - * - * Assumptions: - * - DMA handle allocated by stm32_dmachannel() - * - ****************************************************************************/ - -#ifdef CONFIG_DEBUG_DMA_INFO -void stm32_dmadump(DMA_HANDLE handle, const struct stm32_dmaregs_s *regs, - const char *msg) -{ - struct stm32_dma_s *dmach = (struct stm32_dma_s *)handle; - uint32_t dmabase = DMA_BASE(dmach->base); - - dmainfo("DMA Registers: %s\n", msg); - dmainfo(" ISRC[%08x]: %08x\n", dmabase + STM32_DMA_ISR_OFFSET, regs->isr); - dmainfo(" CCR[%08x]: %08x\n", dmach->base + STM32_DMACHAN_CCR_OFFSET, regs->ccr); - dmainfo(" CNDTR[%08x]: %08x\n", dmach->base + STM32_DMACHAN_CNDTR_OFFSET, regs->cndtr); - dmainfo(" CPAR[%08x]: %08x\n", dmach->base + STM32_DMACHAN_CPAR_OFFSET, regs->cpar); - dmainfo(" CMAR[%08x]: %08x\n", dmach->base + STM32_DMACHAN_CMAR_OFFSET, regs->cmar); -} -#endif - -/**************************************************************************** - * Name: stm32_dma_intack - * - * Description: - * Public visible interface to acknowledge interrupts on DMA channel - * - ****************************************************************************/ - -void stm32_dma_intack(unsigned int chndx, uint32_t isr) -{ - struct stm32_dma_s *dmach = &g_dma[chndx]; - - dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET, isr); -} - -/**************************************************************************** - * Name: stm32_dma_intget - * - * Description: - * Public visible interface to get pending interrupts from DMA channel - * - ****************************************************************************/ - -uint32_t stm32_dma_intget(unsigned int chndx) -{ - struct stm32_dma_s *dmach = &g_dma[chndx]; - - return dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) & DMA_ISR_CHAN_MASK(dmach->chan); -} - -#endif /* CONFIG_STM32_DMA1 && CONFIG_STM32_STM32F33XX */ diff --git a/arch/arm/src/stm32/stm32f40xxx_dma.c b/arch/arm/src/stm32/stm32f40xxx_dma.c index b2212835f2..41fc843589 100644 --- a/arch/arm/src/stm32/stm32f40xxx_dma.c +++ b/arch/arm/src/stm32/stm32f40xxx_dma.c @@ -1055,4 +1055,81 @@ void stm32_dmadump(DMA_HANDLE handle, const struct stm32_dmaregs_s *regs, } #endif +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + +/**************************************************************************** + * Name: stm32_dma_intack + * + * Description: + * Public visible interface to acknowledge interrupts on DMA stream + * + ****************************************************************************/ + +void stm32_dma_intack(unsigned int controller, uint8_t stream, uint32_t isr) +{ + struct stm32_dma_s *dmast = stm32_dmastream(stream, controller); + uint32_t regval = 0; + uint32_t offset = 0; + + /* Select the interrupt flag clear register (either the LIFCR or HIFCR) + * based on the stream number + */ + + if (stream < 4) + { + offset = STM32_DMA_LIFCR_OFFSET; + } + else + { + offset = STM32_DMA_HIFCR_OFFSET; + } + + /* Get value to write */ + + regval |= ((isr & DMA_STREAM_MASK) << dmast->shift); + + /* Write register */ + + dmabase_putreg(dmast, offset, regval); +} + +/**************************************************************************** + * Name: stm32_dma_intget + * + * Description: + * Public visible interface to get pending interrupts from DMA stream + * + ****************************************************************************/ + +uint8_t stm32_dma_intget(unsigned int controller, uint8_t stream) +{ + struct stm32_dma_s *dmast = stm32_dmastream(stream, controller); + uint32_t regval = 0; + uint32_t offset = 0; + + /* Select the interrupt status register (either the LISR or HISR) + * based on the stream number + */ + + if (stream < 4) + { + offset = STM32_DMA_LISR_OFFSET; + } + else + { + offset = STM32_DMA_HISR_OFFSET; + } + + /* Get register value */ + + regval = dmabase_getreg(dmast, offset); + + /* Get stream status */ + + regval = ((regval >> dmast->shift) & DMA_STREAM_MASK); + + return (uint8_t)regval; +} +#endif /* CONFIG_ARCH_HIPRI_INTERRUPT */ + #endif /* CONFIG_STM32_STM32F4XXX */ diff --git a/configs/Kconfig b/configs/Kconfig index dc265ba2a0..cba51c04d4 100644 --- a/configs/Kconfig +++ b/configs/Kconfig @@ -2094,6 +2094,9 @@ endif if ARCH_BOARD_NUCLEO_F091RC source "configs/nucleo-f091rc/Kconfig" endif +if ARCH_BOARD_NUCLEO_F302R8 +source "configs/nucleo-f302r8/Kconfig" +endif if ARCH_BOARD_NUCLEO_F303RE source "configs/nucleo-f303re/Kconfig" endif diff --git a/configs/nucleo-f302r8/Kconfig b/configs/nucleo-f302r8/Kconfig index 898f9725b6..0ae63bc953 100644 --- a/configs/nucleo-f302r8/Kconfig +++ b/configs/nucleo-f302r8/Kconfig @@ -5,4 +5,8 @@ if ARCH_BOARD_NUCLEO_F302R8 +config NUCLEOF302R8_HIGHPRI + bool "High priority interrupt test" + default n + endif diff --git a/configs/nucleo-f302r8/highpri/defconfig b/configs/nucleo-f302r8/highpri/defconfig new file mode 100644 index 0000000000..c6f16bc255 --- /dev/null +++ b/configs/nucleo-f302r8/highpri/defconfig @@ -0,0 +1,65 @@ +# CONFIG_DEV_NULL is not set +# CONFIG_LIBC_LONG_LONG is not set +CONFIG_ADC=y +CONFIG_ANALOG=y +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="nucleo-f302r8" +CONFIG_ARCH_BOARD_NUCLEO_F302R8=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F302R8=y +CONFIG_ARCH_HIPRI_INTERRUPT=y +CONFIG_ARCH_RAMVECTORS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_BUILTIN_PROXY_STACKSIZE=512 +CONFIG_DISABLE_ENVIRON=y +CONFIG_DISABLE_MQUEUE=y +CONFIG_DISABLE_POLL=y +CONFIG_DISABLE_POSIX_TIMERS=y +CONFIG_FDCLONE_STDIO=y +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_FLOATINGPOINT=y +CONFIG_LIBM=y +CONFIG_LIB_BOARDCTL=y +CONFIG_MAX_TASKS=4 +CONFIG_MAX_WDOGPARMS=1 +CONFIG_NAME_MAX=16 +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NFILE_STREAMS=8 +CONFIG_NUCLEOF302R8_HIGHPRI=y +CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=512 +CONFIG_PREALLOC_TIMERS=2 +CONFIG_PREALLOC_WDOGS=1 +CONFIG_PTHREAD_STACK_DEFAULT=1024 +CONFIG_PTHREAD_STACK_MIN=1024 +CONFIG_PWM=y +CONFIG_RAM_SIZE=12288 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_STM32_ADC1=y +CONFIG_STM32_ADC1_DMA=y +CONFIG_STM32_ADC1_DMA_CFG=1 +CONFIG_STM32_ADC_LL_OPS=y +CONFIG_STM32_ADC_NOIRQ=y +CONFIG_STM32_DMA1=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_PWM_LL_OPS=y +CONFIG_STM32_PWR=y +CONFIG_STM32_TIM1=y +CONFIG_STM32_TIM1_PWM=y +CONFIG_STM32_USART2=y +CONFIG_SYSTEM_READLINE=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=512 +CONFIG_USART2_SERIAL_CONSOLE=y +CONFIG_USERMAIN_STACKSIZE=1024 +CONFIG_USER_ENTRYPOINT="highpri_main" +CONFIG_WDOG_INTRESERVE=0 diff --git a/configs/nucleo-f302r8/include/board.h b/configs/nucleo-f302r8/include/board.h index c0bf3dbadf..cfabe46267 100644 --- a/configs/nucleo-f302r8/include/board.h +++ b/configs/nucleo-f302r8/include/board.h @@ -238,4 +238,25 @@ #define GPIO_TIM2_CH2OUT GPIO_TIM2_CH2OUT_1 /* PA1 */ #define GPIO_TIM2_CH3OUT GPIO_TIM2_CH3OUT_1 /* PA9 */ +/* Configuration specific to high priority interrupts example: + * - TIM1 CC1 trigger for ADC if DMA transfer and TIM1 PWM + * - ADC DMA transfer on DMA1_CH1 + */ + +#ifdef CONFIG_NUCLEOF302R8_HIGHPRI + +#if defined(CONFIG_STM32_TIM1_PWM) && defined(CONFIG_STM32_ADC1_DMA) + +/* TIM1 - ADC trigger */ + +#define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC1 + +#endif /* CONFIG_STM32_TIM1_PWM */ +#endif /* CONFIG_NUCLEOF302R8_HIGHPRI */ + +/* DMA channels *************************************************************/ +/* ADC */ + +#define ADC1_DMA_CHAN DMACHAN_ADC1 /* DMA1_CH1 */ + #endif /* __CONFIG_NUCLEO_F302R8_INCLUDE_BOARD_H */ diff --git a/configs/nucleo-f302r8/scripts/ld.script b/configs/nucleo-f302r8/scripts/ld.script index be5c2fc1f7..5eaa3e36ee 100644 --- a/configs/nucleo-f302r8/scripts/ld.script +++ b/configs/nucleo-f302r8/scripts/ld.script @@ -86,6 +86,12 @@ SECTIONS _eronly = ABSOLUTE(.); + /* The RAM vector table (if present) should lie at the beginning of SRAM */ + + .ram_vectors : { + *(.ram_vectors) + } > sram + .data : { _sdata = ABSOLUTE(.); *(.data .data.*) diff --git a/configs/nucleo-f302r8/src/Makefile b/configs/nucleo-f302r8/src/Makefile index 83f6fe7c00..8aa26518a0 100644 --- a/configs/nucleo-f302r8/src/Makefile +++ b/configs/nucleo-f302r8/src/Makefile @@ -56,4 +56,8 @@ ifeq ($(CONFIG_PWM),y) CSRCS += stm32_pwm.c endif +ifeq ($(CONFIG_NUCLEOF302R8_HIGHPRI),y) +CSRCS += stm32_highpri.c +endif + include $(TOPDIR)/configs/Board.mk diff --git a/configs/nucleo-f302r8/src/stm32_highpri.c b/configs/nucleo-f302r8/src/stm32_highpri.c new file mode 100644 index 0000000000..bcfe1ccc24 --- /dev/null +++ b/configs/nucleo-f302r8/src/stm32_highpri.c @@ -0,0 +1,552 @@ +/**************************************************************************** + * configs/nucleo-f302r8/src/stm32_highpri.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "up_internal.h" +#include "ram_vectors.h" + +#include +#include +#include + +#include "stm32_pwm.h" +#include "stm32_adc.h" +#include "stm32_dma.h" + +#ifdef CONFIG_NUCLEOF302R8_HIGHPRI + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT +# error CONFIG_ARCH_HIPRI_INTERRUPT is required +#endif + +#ifndef CONFIG_ARCH_RAMVECTORS +# error CONFIG_ARCH_RAMVECTORS is required +#endif + +#ifndef CONFIG_ARCH_IRQPRIO +# error CONFIG_ARCH_IRQPRIO is required +#endif + +#ifndef CONFIG_ARCH_FPU +# warning Set CONFIG_ARCH_FPU for hardware FPU support +#endif + +#ifdef CONFIG_STM32_ADC1_DMA +# if defined(CONFIG_STM32_TIM1_PWM) +# define HIGHPRI_HAVE_TIM1 +# endif +# if (CONFIG_STM32_ADC1_DMA_CFG != 1) +# error ADC1 DMA must be configured in Circular Mode +# endif +# if !defined(HIGHPRI_HAVE_TIM1) +# error "Needs TIM1 to trigger ADC DMA" +# endif +#endif + +#ifdef HIGHPRI_HAVE_TIM1 +# ifndef ADC1_EXTSEL_VALUE +# error ADC1 EXTSEL have to be configured in board.h +# endif +#endif + +#if (CONFIG_STM32_ADC1_INJECTED_CHAN > 0) +# if (CONFIG_STM32_ADC1_INJECTED_CHAN > 2) +# error Max 2 injected channels supported for now +# else +# define HIGHPRI_HAVE_INJECTED +# endif +#endif + +#ifdef HIGHPRI_HAVE_INJECTED +# define INJ_NCHANNELS CONFIG_STM32_ADC1_INJECTED_CHAN +#else +# define INJ_NCHANNELS (0) +#endif + +#ifndef CONFIG_STM32_ADC1_DMA +# define REG_NCHANNELS (1) +#else +# define REG_NCHANNELS (3) +#endif + +#define ADC1_NCHANNELS (REG_NCHANNELS + INJ_NCHANNELS) + +#define DEV1_PORT (1) +#define DEV1_NCHANNELS ADC1_NCHANNELS +#define ADC_REF_VOLTAGE (3.3f) +#define ADC_VAL_MAX (4095) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* High priority example private data */ + +struct highpri_s +{ + FAR struct stm32_adc_dev_s *adc1; +#ifdef HIGHPRI_HAVE_TIM1 + struct stm32_pwm_dev_s *pwm; +#endif + volatile uint32_t cntr1; + volatile uint32_t cntr2; + volatile uint8_t current; + uint16_t r_val[REG_NCHANNELS]; + float r_volt[REG_NCHANNELS]; +#ifdef HIGHPRI_HAVE_INJECTED + uint16_t j_val[INJ_NCHANNELS]; + float j_volt[INJ_NCHANNELS]; +#endif + bool lock; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* ADC channel list */ + +static const uint8_t g_chanlist1[DEV1_NCHANNELS] = +{ + 1, +#ifdef CONFIG_STM32_ADC1_DMA + 2, + 11, +#endif +#if INJ_NCHANNELS > 0 + 7, +#endif +#if INJ_NCHANNELS > 1 + 6 +#endif +}; + +/* Configurations of pins used by ADC channel */ + +static const uint32_t g_pinlist1[DEV1_NCHANNELS] = +{ + GPIO_ADC1_IN1, /* PA0/A0 */ +#ifdef CONFIG_STM32_ADC1_DMA + GPIO_ADC1_IN2, /* PA1/A1 */ + GPIO_ADC1_IN11, /* PB0/A3 */ +#endif +#if INJ_NCHANNELS > 0 + GPIO_ADC1_IN7, /* PC1/A4 */ +#endif +#if INJ_NCHANNELS > 1 + GPIO_ADC1_IN6 /* PC0/A5 */ +#endif +}; + +static struct highpri_s g_highpri; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: adc12_handler + * + * Description: + * This is the handler for the high speed ADC interrupt. + * + ****************************************************************************/ + +#if !defined(CONFIG_STM32_ADC1_DMA) || defined(HIGHPRI_HAVE_INJECTED) +void adc12_handler(void) +{ + FAR struct stm32_adc_dev_s *adc = g_highpri.adc1; + float ref = ADC_REF_VOLTAGE; + float bit = ADC_VAL_MAX; + uint32_t pending; +#ifdef HIGHPRI_HAVE_INJECTED + int i = 0; +#endif + + /* Get pending ADC interrupts */ + + pending = ADC_INT_GET(adc); + + if (g_highpri.lock == true) + { + goto irq_out; + } + +#ifndef CONFIG_STM32_ADC1_DMA + /* Regular channel end of conversion */ + + if (pending & ADC_ISR_EOC) + { + /* Increase regular sequence counter */ + + g_highpri.cntr1 += 1; + + /* Get regular data */ + + g_highpri.r_val[g_highpri.current] = ADC_REGDATA_GET(adc); + + /* Do some floating point operations */ + + g_highpri.r_volt[g_highpri.current] = (float)g_highpri.r_val[g_highpri.current] * ref / bit; + + if (g_highpri.current >= REG_NCHANNELS-1) + { + g_highpri.current = 0; + } + else + { + g_highpri.current += 1; + } + } +#endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Injected channel end of sequence */ + + if (pending & ADC_ISR_JEOS) + { + /* Increase injected sequence counter */ + + g_highpri.cntr2 += 1; + + /* Get injected channels */ + + for (i = 0; i < INJ_NCHANNELS; i += 1) + { + g_highpri.j_val[i] = ADC_INJDATA_GET(adc, i); + } + + /* Do some floating point operations */ + + for (i = 0; i < INJ_NCHANNELS; i += 1) + { + g_highpri.j_volt[i] = (float)g_highpri.j_val[i] * ref / bit; + } + } +#endif + +irq_out: + /* Clear ADC pending interrupts */ + + ADC_INT_ACK(adc, pending); +} +#endif + +/**************************************************************************** + * Name: dmach1_handler + * + * Description: + * This is the handler for the high speed ADC interrupt using DMA transfer. + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_ADC1_DMA +void dma1ch1_handler(void) +{ + float ref = ADC_REF_VOLTAGE; + float bit = ADC_VAL_MAX; + uint32_t pending; + int i; + + pending = stm32_dma_intget(STM32_DMA1_CHAN1); + + if (g_highpri.lock == true) + { + goto irq_out; + } + + /* Increase regular sequence counter */ + + g_highpri.cntr1 += 1; + + for (i = 0; i < REG_NCHANNELS; i += 1) + { + /* Do some floating point operations */ + + g_highpri.r_volt[i] = (float)g_highpri.r_val[i] * ref / bit; + } + +irq_out: + /* Clear DMA pending interrupts */ + + stm32_dma_intack(STM32_DMA1_CHAN1, pending); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: highpri_main + * + * Description: + * Main entry point in into the high priority interrupt test. + * + ****************************************************************************/ + +int highpri_main(int argc, char *argv[]) +{ +#ifdef HIGHPRI_HAVE_TIM1 + struct stm32_pwm_dev_s *pwm1; +#endif + FAR struct adc_dev_s *adc1; + FAR struct highpri_s *highpri; + int ret; + int i; + + highpri = &g_highpri; + + /* Initialize highpri structure */ + + memset(highpri, 0, sizeof(struct highpri_s)); + + printf("\nhighpri_main: Started\n"); + + /* Configure the pins as analog inputs for the selected channels */ + + for (i = 0; i < DEV1_NCHANNELS; i++) + { + stm32_configgpio(g_pinlist1[i]); + } + + /* Initialize ADC driver */ + + adc1 = stm32_adcinitialize(DEV1_PORT, g_chanlist1, DEV1_NCHANNELS); + if (adc1 == NULL) + { + aerr("ERROR: Failed to get ADC interface 1\n"); + ret = EXIT_FAILURE; + goto errout; + } + + highpri->adc1 = (struct stm32_adc_dev_s *)adc1->ad_priv; + +#ifdef HIGHPRI_HAVE_TIM1 + /* Initialize TIM1 */ + + pwm1 = (FAR struct stm32_pwm_dev_s *) stm32_pwminitialize(1); + if (pwm1 == NULL) + { + printf("ERROR: Failed to get PWM1 interface\n"); + ret = EXIT_FAILURE; + goto errout; + } + + highpri->pwm = pwm1; + + /* Setup PWM device */ + + PWM_SETUP(pwm1); + + /* Set timer frequency */ + + PWM_FREQ_UPDATE(pwm1, 1000); + +#if ADC1_EXTSEL_VALUE == ADC1_EXTSEL_T1CC1 + /* Set CCR1 */ + + PWM_CCR_UPDATE(pwm1, 1, 0x0f00); + + /* Enable TIM1 CHAN1 */ + + PWM_OUTPUTS_ENABLE(pwm1, STM32_CHAN1, true); +#else +# error T1CC1 only supported for now +#endif + +#ifdef CONFIG_DEBUG_PWM_INFO + /* Print debug */ + + PWM_DUMP_REGS(pwm1); +#endif + +#endif /* HIGHPRI_HAVE_TIM1 */ + +#if !defined(CONFIG_STM32_ADC1_DMA) || defined(HIGHPRI_HAVE_INJECTED) + /* Attach ADC12 ram vector if no DMA or injected channels support */ + + ret = up_ramvec_attach(STM32_IRQ_ADC12, adc12_handler); + if (ret < 0) + { + fprintf(stderr, "highpri_main: ERROR: up_ramvec_attach failed: %d\n", ret); + ret = EXIT_FAILURE; + goto errout; + } + + /* Set the priority of the ADC12 interrupt vector */ + + ret = up_prioritize_irq(STM32_IRQ_ADC12, NVIC_SYSH_HIGH_PRIORITY); + if (ret < 0) + { + fprintf(stderr, "highpri_main: ERROR: up_prioritize_irq failed: %d\n", ret); + ret = EXIT_FAILURE; + goto errout; + } + + up_enable_irq(STM32_IRQ_ADC12); +#endif + +#ifdef CONFIG_STM32_ADC1_DMA + /* Attach DMA1 CH1 ram vector if DMA */ + + ret = up_ramvec_attach(STM32_IRQ_DMA1CH1, dma1ch1_handler); + if (ret < 0) + { + fprintf(stderr, "highpri_main: ERROR: up_ramvec_attach failed: %d\n", ret); + ret = EXIT_FAILURE; + goto errout; + } + + /* Set the priority of the DMA1CH1 interrupt vector */ + + ret = up_prioritize_irq(STM32_IRQ_DMA1CH1, NVIC_SYSH_HIGH_PRIORITY); + if (ret < 0) + { + fprintf(stderr, "highpri_main: ERROR: up_prioritize_irq failed: %d\n", ret); + ret = EXIT_FAILURE; + goto errout; + } + + up_enable_irq(STM32_IRQ_DMA1CH1); +#endif + + /* Setup ADC hardware */ + + adc1->ad_ops->ao_setup(adc1); + +#ifndef CONFIG_STM32_ADC1_DMA + /* Enable ADC regular convertion interrupts if no DMA */ + + ADC_INT_ENABLE(highpri->adc1, ADC_IER_EOC); +#else + /* Register ADC buffer for DMA transfer */ + + ADC_REGBUF_REGISTER(highpri->adc1, g_highpri.r_val, REG_NCHANNELS); +#endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Enable ADC injected sequence end interrupts */ + + ADC_INT_ENABLE(highpri->adc1, ADC_IER_JEOS); +#endif + +#ifdef HIGHPRI_HAVE_TIM1 + /* Enable timer counter after ADC configuration */ + + PWM_TIM_ENABLE(pwm1, true); +#endif + + while(1) + { +#ifndef CONFIG_STM32_ADC1_DMA + /* Software trigger for regular sequence */ + + adc1->ad_ops->ao_ioctl(adc1, IO_TRIGGER_REG, 0); + + usleep(100); +#endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Software trigger for injected sequence */ + + adc1->ad_ops->ao_ioctl(adc1, IO_TRIGGER_INJ, 0); + + usleep(100); +#endif + /* Lock global data */ + + g_highpri.lock = true; + +#ifndef CONFIG_STM32_ADC1_DMA + printf("%d [%d] %0.3fV\n", g_highpri.cntr1, g_highpri.current, + g_highpri.r_volt[g_highpri.current]); +#else + printf("%d ", g_highpri.cntr1); + + for (i = 0; i < REG_NCHANNELS; i += 1) + { + printf("r:[%d] %0.3fV, ", i, g_highpri.r_volt[i]); + } + + printf("\n"); +#endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Print data from injected channels */ + + printf("%d ", g_highpri.cntr2); + + for (i = 0; i < INJ_NCHANNELS; i += 1) + { + printf("j:[%d] %0.3fV, ", i, g_highpri.j_volt[i]); + } + + printf("\n"); +#endif + /* Unlock global data */ + + g_highpri.lock = false; + + sleep(1); + } + +errout: + return ret; +} + +#endif /* CONFIG_NUCLEOF302R8_HIGHPRI */ diff --git a/configs/nucleo-f303re/adc/defconfig b/configs/nucleo-f303re/adc/defconfig index c077173886..17053272bb 100644 --- a/configs/nucleo-f303re/adc/defconfig +++ b/configs/nucleo-f303re/adc/defconfig @@ -13,6 +13,7 @@ CONFIG_ARCH_STACKDUMP=y CONFIG_BOARD_LOOPSPERMSEC=6522 CONFIG_DISABLE_POLL=y CONFIG_EXAMPLES_ADC=y +CONFIG_EXAMPLES_ADC_GROUPSIZE=3 CONFIG_EXAMPLES_ADC_SWTRIG=y CONFIG_IDLETHREAD_STACKSIZE=2048 CONFIG_INTELHEX_BINARY=y diff --git a/configs/nucleo-f334r8/adc/defconfig b/configs/nucleo-f334r8/adc/defconfig index 641aa7d14e..0854ad281f 100644 --- a/configs/nucleo-f334r8/adc/defconfig +++ b/configs/nucleo-f334r8/adc/defconfig @@ -22,6 +22,7 @@ CONFIG_DISABLE_POSIX_TIMERS=y CONFIG_DISABLE_PTHREAD=y CONFIG_DISABLE_SIGNALS=y CONFIG_EXAMPLES_ADC=y +CONFIG_EXAMPLES_ADC_GROUPSIZE=3 CONFIG_EXAMPLES_ADC_SWTRIG=y CONFIG_FDCLONE_STDIO=y CONFIG_INTELHEX_BINARY=y diff --git a/configs/nucleo-f334r8/highpri/defconfig b/configs/nucleo-f334r8/highpri/defconfig index 2ebe478b69..5673b98fdd 100644 --- a/configs/nucleo-f334r8/highpri/defconfig +++ b/configs/nucleo-f334r8/highpri/defconfig @@ -1,6 +1,5 @@ # CONFIG_DEV_NULL is not set # CONFIG_LIBC_LONG_LONG is not set -# CONFIG_NSH_DISABLE_PRINTF is not set CONFIG_ADC=y CONFIG_ANALOG=y CONFIG_ARCH="arm" @@ -19,58 +18,16 @@ CONFIG_DISABLE_ENVIRON=y CONFIG_DISABLE_MQUEUE=y CONFIG_DISABLE_POLL=y CONFIG_DISABLE_POSIX_TIMERS=y -CONFIG_SYSTEM_NSH=y CONFIG_FDCLONE_STDIO=y CONFIG_INTELHEX_BINARY=y CONFIG_LIBC_FLOATINGPOINT=y CONFIG_LIBM=y +CONFIG_LIB_BOARDCTL=y CONFIG_MAX_TASKS=4 CONFIG_MAX_WDOGPARMS=1 CONFIG_NAME_MAX=16 CONFIG_NFILE_DESCRIPTORS=8 CONFIG_NFILE_STREAMS=8 -CONFIG_NSH_ARCHINIT=y -CONFIG_NSH_BUILTIN_APPS=y -CONFIG_NSH_DISABLE_BASENAME=y -CONFIG_NSH_DISABLE_CAT=y -CONFIG_NSH_DISABLE_CD=y -CONFIG_NSH_DISABLE_CMP=y -CONFIG_NSH_DISABLE_CP=y -CONFIG_NSH_DISABLE_DD=y -CONFIG_NSH_DISABLE_DF=y -CONFIG_NSH_DISABLE_DIRNAME=y -CONFIG_NSH_DISABLE_EXEC=y -CONFIG_NSH_DISABLE_EXIT=y -CONFIG_NSH_DISABLE_GET=y -CONFIG_NSH_DISABLE_HEXDUMP=y -CONFIG_NSH_DISABLE_KILL=y -CONFIG_NSH_DISABLE_LOSETUP=y -CONFIG_NSH_DISABLE_LS=y -CONFIG_NSH_DISABLE_MB=y -CONFIG_NSH_DISABLE_MH=y -CONFIG_NSH_DISABLE_MKDIR=y -CONFIG_NSH_DISABLE_MKRD=y -CONFIG_NSH_DISABLE_MOUNT=y -CONFIG_NSH_DISABLE_MV=y -CONFIG_NSH_DISABLE_MW=y -CONFIG_NSH_DISABLE_PUT=y -CONFIG_NSH_DISABLE_PWD=y -CONFIG_NSH_DISABLE_RM=y -CONFIG_NSH_DISABLE_RMDIR=y -CONFIG_NSH_DISABLE_SET=y -CONFIG_NSH_DISABLE_SH=y -CONFIG_NSH_DISABLE_SLEEP=y -CONFIG_NSH_DISABLE_TEST=y -CONFIG_NSH_DISABLE_TIME=y -CONFIG_NSH_DISABLE_UMOUNT=y -CONFIG_NSH_DISABLE_UNAME=y -CONFIG_NSH_DISABLE_UNSET=y -CONFIG_NSH_DISABLE_USLEEP=y -CONFIG_NSH_DISABLE_WGET=y -CONFIG_NSH_DISABLE_XD=y -CONFIG_NSH_FILEIOSIZE=256 -CONFIG_NSH_LINELEN=64 -CONFIG_NSH_READLINE=y CONFIG_NUCLEOF334R8_HIGHPRI=y CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=512 CONFIG_PREALLOC_TIMERS=2 @@ -88,6 +45,9 @@ CONFIG_START_MONTH=12 CONFIG_START_YEAR=2011 CONFIG_STM32_ADC1=y CONFIG_STM32_ADC1_DMA=y +CONFIG_STM32_ADC1_DMA_CFG=1 +CONFIG_STM32_ADC1_INJECTED_CHAN=1 +CONFIG_STM32_ADC_LL_OPS=y CONFIG_STM32_ADC_NOIRQ=y CONFIG_STM32_DMA1=y CONFIG_STM32_HRTIM1=y @@ -95,10 +55,12 @@ CONFIG_STM32_HRTIM_ADC1_TRG1=y CONFIG_STM32_HRTIM_ADC=y CONFIG_STM32_HRTIM_CLK_FROM_PLL=y CONFIG_STM32_HRTIM_DISABLE_CHARDRV=y +CONFIG_STM32_HRTIM_NO_ENABLE_TIMERS=y CONFIG_STM32_HRTIM_TIMA=y CONFIG_STM32_JTAG_SW_ENABLE=y CONFIG_STM32_PWR=y CONFIG_STM32_USART2=y +CONFIG_SYSTEM_READLINE=y CONFIG_TASK_NAME_SIZE=0 CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=512 CONFIG_USART2_SERIAL_CONSOLE=y diff --git a/configs/nucleo-f334r8/include/board.h b/configs/nucleo-f334r8/include/board.h index 4dc9d283b1..fe843b3040 100644 --- a/configs/nucleo-f334r8/include/board.h +++ b/configs/nucleo-f334r8/include/board.h @@ -250,24 +250,38 @@ #define OPAMP2_VPSEL OPAMP2_VPSEL_PB14 /* Configuration specific to high priority interrupts example: - * - HRTIM Timer A trigger for ADC if DMA transfer + * - HRTIM Timer A trigger for ADC if DMA transfer and HRTIM + * - TIM1 CC1 trigger for ADC if DMA transfer and TIM1 PWM * - ADC DMA transfer on DMA1_CH1 */ #ifdef CONFIG_NUCLEOF334R8_HIGHPRI -/* HRTIM */ +#if defined(CONFIG_STM32_HRTIM1) && defined(CONFIG_STM32_ADC1_DMA) + +/* HRTIM - ADC trigger */ #define HRTIM_TIMA_PRESCALER HRTIM_PRESCALER_128 #define HRTIM_TIMA_MODE HRTIM_MODE_CONT +#define HRTIM_TIMA_UPDATE 0 +#define HRTIM_TIMA_RESET 0 #define HRTIM_ADC_TRG1 HRTIM_ADCTRG13_APER +#endif /* CONFIG_STM32_HRTIM1 && CONFIG_STM32_ADC1_DMA*/ + +#if defined(CONFIG_STM32_TIM1_PWM) && defined(CONFIG_STM32_ADC1_DMA) + +/* TIM1 - ADC trigger */ + +#define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC1 + +#endif /* CONFIG_STM32_TIM1_PWM && CONFIG_STM32_ADC1_DMA */ +#endif /* CONFIG_NUCLEOF334R8_HIGHPRI */ + /* DMA channels *************************************************************/ /* ADC */ #define ADC1_DMA_CHAN DMACHAN_ADC1 /* DMA1_CH1 */ -#endif /* CONFIG_NUCLEOF334R8_HIGHPRI */ - #endif /* __CONFIG_NUCLEO_F334R8_INCLUDE_BOARD_H */ diff --git a/configs/nucleo-f334r8/src/stm32_appinit.c b/configs/nucleo-f334r8/src/stm32_appinit.c index cffca5ceeb..7f84f6deb2 100644 --- a/configs/nucleo-f334r8/src/stm32_appinit.c +++ b/configs/nucleo-f334r8/src/stm32_appinit.c @@ -96,7 +96,6 @@ int board_app_initialize(uintptr_t arg) { int ret; -#ifndef CONFIG_NUCLEOF334R8_HIGHPRI #ifdef HAVE_LEDS /* Register the LED driver */ @@ -146,7 +145,6 @@ int board_app_initialize(uintptr_t arg) { syslog(LOG_ERR, "ERROR: stm32_opamp_setup failed: %d\n", ret); } -#endif #endif UNUSED(ret); diff --git a/configs/nucleo-f334r8/src/stm32_highpri.c b/configs/nucleo-f334r8/src/stm32_highpri.c index 620181766d..74d64d7740 100644 --- a/configs/nucleo-f334r8/src/stm32_highpri.c +++ b/configs/nucleo-f334r8/src/stm32_highpri.c @@ -1,7 +1,7 @@ /**************************************************************************** * configs/nucleo-f334r8/src/stm32_highpri.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2018 Gregory Nutt. All rights reserved. * Author: Mateusz Szafoni * * Redistribution and use in source and binary forms, with or without @@ -54,10 +54,12 @@ #include "up_internal.h" #include "ram_vectors.h" +#include #include #include #include "stm32_hrtim.h" +#include "stm32_pwm.h" #include "stm32_adc.h" #include "stm32_dma.h" @@ -68,10 +70,6 @@ ****************************************************************************/ /* Configuration ************************************************************/ -#ifndef CONFIG_ARCH_CHIP_STM32F334R8 -# warning This only have been verified with CONFIG_ARCH_CHIP_STM32F334R8 -#endif - #ifndef CONFIG_ARCH_HIPRI_INTERRUPT # error CONFIG_ARCH_HIPRI_INTERRUPT is required #endif @@ -89,21 +87,60 @@ #endif #ifdef CONFIG_STM32_ADC1_DMA -# if !defined(CONFIG_STM32_HRTIM1) || !defined(CONFIG_STM32_HRTIM_TIMA) -# error "Needs HRTIM TIMA to trigger ADC" +# if defined(CONFIG_STM32_HRTIM1) && defined(CONFIG_STM32_HRTIM_TIMA) +# define HIGHPRI_HAVE_HRTIM +# endif +# if defined(CONFIG_STM32_TIM1_PWM) +# define HIGHPRI_HAVE_TIM1 +# endif +# if (CONFIG_STM32_ADC1_DMA_CFG != 1) +# error ADC1 DMA must be configured in Circular Mode +# endif +# if defined(HIGHPRI_HAVE_HRTIM) && defined(HIGHPRI_HAVE_TIM1) +# error HRTIM TIM A or TIM1 ! +# elif !defined(HIGHPRI_HAVE_HRTIM) && !defined(HIGHPRI_HAVE_TIM1) +# error "Needs HRTIM TIMA or TIM1 to trigger ADC DMA" # endif #endif -#ifndef CONFIG_STM32_ADC1_DMA -# define ADC1_NCHANNELS 1 -#else -# define ADC1_NCHANNELS 3 +#ifdef HIGHPRI_HAVE_HRTIM +# if !defined(CONFIG_STM32_HRTIM_ADC1_TRG1) || !defined(CONFIG_STM32_HRTIM_ADC) +# error +# endif #endif -#define DEV1_PORT 1 +#ifdef HIGHPRI_HAVE_TIM1 +# ifndef ADC1_EXTSEL_VALUE +# error ADC1 EXTSEL have to be configured in board.h +# endif +#endif + +#if (CONFIG_STM32_ADC1_INJECTED_CHAN > 0) +# if (CONFIG_STM32_ADC1_INJECTED_CHAN > 2) +# error Max 2 injected channels supported for now +# else +# define HIGHPRI_HAVE_INJECTED +# endif +#endif + +#ifdef HIGHPRI_HAVE_INJECTED +# define INJ_NCHANNELS CONFIG_STM32_ADC1_INJECTED_CHAN +#else +# define INJ_NCHANNELS (0) +#endif + +#ifndef CONFIG_STM32_ADC1_DMA +# define REG_NCHANNELS (1) +#else +# define REG_NCHANNELS (3) +#endif + +#define ADC1_NCHANNELS (REG_NCHANNELS + INJ_NCHANNELS) + +#define DEV1_PORT (1) #define DEV1_NCHANNELS ADC1_NCHANNELS -#define ADC_REF_VOLTAGE 3.3 -#define ADC_VAL_MAX 4095 +#define ADC_REF_VOLTAGE (3.3f) +#define ADC_VAL_MAX (4095) /**************************************************************************** * Private Types @@ -113,14 +150,23 @@ struct highpri_s { - FAR struct stm32_adc_dev_s *adc; -#ifdef CONFIG_STM32_ADC1_DMA + FAR struct stm32_adc_dev_s *adc1; +#ifdef HIGHPRI_HAVE_HRTIM FAR struct hrtim_dev_s *hrtim; #endif - volatile uint32_t cntr; +#ifdef HIGHPRI_HAVE_TIM1 + struct stm32_pwm_dev_s *pwm; +#endif + volatile uint32_t cntr1; + volatile uint32_t cntr2; volatile uint8_t current; - uint16_t val[DEV1_NCHANNELS]; - float volt[DEV1_NCHANNELS]; + uint16_t r_val[REG_NCHANNELS]; + float r_volt[REG_NCHANNELS]; +#ifdef HIGHPRI_HAVE_INJECTED + uint16_t j_val[INJ_NCHANNELS]; + float j_volt[INJ_NCHANNELS]; +#endif + bool lock; }; /**************************************************************************** @@ -134,7 +180,13 @@ static const uint8_t g_chanlist1[DEV1_NCHANNELS] = 1, #ifdef CONFIG_STM32_ADC1_DMA 2, - 11 + 11, +#endif +#if INJ_NCHANNELS > 0 + 7, +#endif +#if INJ_NCHANNELS > 1 + 6 #endif }; @@ -143,11 +195,16 @@ static const uint8_t g_chanlist1[DEV1_NCHANNELS] = static const uint32_t g_pinlist1[DEV1_NCHANNELS] = { GPIO_ADC1_IN1, /* PA0/A0 */ - #ifdef CONFIG_STM32_ADC1_DMA GPIO_ADC1_IN2, /* PA1/A1 */ GPIO_ADC1_IN11, /* PB0/A3 */ #endif +#if INJ_NCHANNELS > 0 + GPIO_ADC1_IN7, /* PC1/A4 */ +#endif +#if INJ_NCHANNELS > 1 + GPIO_ADC1_IN6 /* PC0/A5 */ +#endif }; static struct highpri_s g_highpri; @@ -164,27 +221,44 @@ static struct highpri_s g_highpri; * ****************************************************************************/ -#ifndef CONFIG_STM32_ADC1_DMA +#if !defined(CONFIG_STM32_ADC1_DMA) || defined(HIGHPRI_HAVE_INJECTED) void adc12_handler(void) { - FAR struct stm32_adc_dev_s *adc = g_highpri.adc; + FAR struct stm32_adc_dev_s *adc = g_highpri.adc1; float ref = ADC_REF_VOLTAGE; float bit = ADC_VAL_MAX; uint32_t pending; +#ifdef HIGHPRI_HAVE_INJECTED + int i = 0; +#endif - g_highpri.cntr += 1; + /* Get pending ADC interrupts */ - pending = adc->ops->int_get(adc); + pending = ADC_INT_GET(adc); - if (pending & ADC_INT_EOC) + if (g_highpri.lock == true) { - g_highpri.val[g_highpri.current] = adc->ops->val_get(adc); + goto irq_out; + } + +#ifndef CONFIG_STM32_ADC1_DMA + /* Regular channel end of conversion */ + + if (pending & ADC_ISR_EOC) + { + /* Increase regular sequence counter */ + + g_highpri.cntr1 += 1; + + /* Get regular data */ + + g_highpri.r_val[g_highpri.current] = ADC_REGDATA_GET(adc); /* Do some floating point operations */ - g_highpri.volt[g_highpri.current] = (float)g_highpri.val[g_highpri.current] * ref / bit; + g_highpri.r_volt[g_highpri.current] = (float)g_highpri.r_val[g_highpri.current] * ref / bit; - if (g_highpri.current >= DEV1_NCHANNELS-1) + if (g_highpri.current >= REG_NCHANNELS-1) { g_highpri.current = 0; } @@ -193,8 +267,37 @@ void adc12_handler(void) g_highpri.current += 1; } } +#endif - adc->ops->int_ack(adc, pending); +#ifdef HIGHPRI_HAVE_INJECTED + /* Injected channel end of sequence */ + + if (pending & ADC_ISR_JEOS) + { + /* Increase injected sequence counter */ + + g_highpri.cntr2 += 1; + + /* Get injected channels */ + + for (i = 0; i < INJ_NCHANNELS; i += 1) + { + g_highpri.j_val[i] = ADC_INJDATA_GET(adc, i); + } + + /* Do some floating point operations */ + + for (i = 0; i < INJ_NCHANNELS; i += 1) + { + g_highpri.j_volt[i] = (float)g_highpri.j_val[i] * ref / bit; + } + } +#endif + +irq_out: + /* Clear ADC pending interrupts */ + + ADC_INT_ACK(adc, pending); } #endif @@ -216,15 +319,25 @@ void dma1ch1_handler(void) pending = stm32_dma_intget(STM32_DMA1_CHAN1); - g_highpri.cntr += 1; + if (g_highpri.lock == true) + { + goto irq_out; + } - for (i = 0; i < 3; i += 1) + /* Increase regular sequence counter */ + + g_highpri.cntr1 += 1; + + for (i = 0; i < REG_NCHANNELS; i += 1) { /* Do some floating point operations */ - g_highpri.volt[i] = (float)g_highpri.val[i] * ref / bit; + g_highpri.r_volt[i] = (float)g_highpri.r_val[i] * ref / bit; } +irq_out: + /* Clear DMA pending interrupts */ + stm32_dma_intack(STM32_DMA1_CHAN1, pending); } #endif @@ -243,10 +356,13 @@ void dma1ch1_handler(void) int highpri_main(int argc, char *argv[]) { -#ifdef CONFIG_STM32_ADC1_DMA +#ifdef HIGHPRI_HAVE_HRTIM FAR struct hrtim_dev_s *hrtim; #endif - FAR struct adc_dev_s *adc; +#ifdef HIGHPRI_HAVE_TIM1 + struct stm32_pwm_dev_s *pwm1; +#endif + FAR struct adc_dev_s *adc1; FAR struct highpri_s *highpri; int ret; int i; @@ -268,17 +384,17 @@ int highpri_main(int argc, char *argv[]) /* Initialize ADC driver */ - adc = stm32_adcinitialize(DEV1_PORT, g_chanlist1, DEV1_NCHANNELS); - if (adc == NULL) + adc1 = stm32_adcinitialize(DEV1_PORT, g_chanlist1, DEV1_NCHANNELS); + if (adc1 == NULL) { aerr("ERROR: Failed to get ADC interface 1\n"); ret = EXIT_FAILURE; goto errout; } - highpri->adc = (struct stm32_adc_dev_s *)adc->ad_priv; + highpri->adc1 = (struct stm32_adc_dev_s *)adc1->ad_priv; -#ifdef CONFIG_STM32_ADC1_DMA +#ifdef HIGHPRI_HAVE_HRTIM /* Configure HRTIM */ hrtim = stm32_hrtiminitialize(); @@ -294,11 +410,51 @@ int highpri_main(int argc, char *argv[]) /* Set Timer A Period */ HRTIM_PER_SET(hrtim, HRTIM_TIMER_TIMA, 0xFFD0); +#endif /* HIGHPRI_HAVE_HRTIM */ + +#ifdef HIGHPRI_HAVE_TIM1 + /* Initialize TIM1 */ + + pwm1 = (FAR struct stm32_pwm_dev_s *) stm32_pwminitialize(1); + if (pwm1 == NULL) + { + printf("ERROR: Failed to get PWM1 interface\n"); + ret = EXIT_FAILURE; + goto errout; + } + + highpri->pwm = pwm1; + + /* Setup PWM device */ + + PWM_SETUP(pwm1); + + /* Set timer frequency */ + + PWM_FREQ_UPDATE(pwm1, 1000); + +#if ADC1_EXTSEL_VALUE == ADC1_EXTSEL_T1CC1 + /* Set CCR1 */ + + PWM_CCR_UPDATE(pwm1, 1, 0x0f00); + + /* Enable TIM1 CHAN1 */ + + PWM_OUTPUTS_ENABLE(pwm1, STM32_CHAN1, true); +#else +# error T1CC1 only supported for now #endif -#ifndef CONFIG_STM32_ADC1_DMA +#ifdef CONFIG_DEBUG_PWM_INFO + /* Print debug */ - /* Attach ADC12 ram vector if no DMA */ + PWM_DUMP_REGS(pwm1); +#endif + +#endif /* HIGHPRI_HAVE_TIM1 */ + +#if !defined(CONFIG_STM32_ADC1_DMA) || defined(HIGHPRI_HAVE_INJECTED) + /* Attach ADC12 ram vector if no DMA or injected channels support */ ret = up_ramvec_attach(STM32_IRQ_ADC12, adc12_handler); if (ret < 0) @@ -319,8 +475,9 @@ int highpri_main(int argc, char *argv[]) } up_enable_irq(STM32_IRQ_ADC12); -#else +#endif +#ifdef CONFIG_STM32_ADC1_DMA /* Attach DMA1 CH1 ram vector if DMA */ ret = up_ramvec_attach(STM32_IRQ_DMA1CH1, dma1ch1_handler); @@ -346,39 +503,87 @@ int highpri_main(int argc, char *argv[]) /* Setup ADC hardware */ - adc->ad_ops->ao_setup(adc); + adc1->ad_ops->ao_setup(adc1); #ifndef CONFIG_STM32_ADC1_DMA - /* Enable ADC interrupts if no DMA */ + /* Enable ADC regular convertion interrupts if no DMA */ - highpri->adc->ops->int_en(highpri->adc, ADC_INT_EOC); + ADC_INT_ENABLE(highpri->adc1, ADC_IER_EOC); #else /* Register ADC buffer for DMA transfer */ - highpri->adc->ops->regbuf_reg(highpri->adc, g_highpri.val, 3); + ADC_REGBUF_REGISTER(highpri->adc1, g_highpri.r_val, REG_NCHANNELS); +#endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Enable ADC injected sequence end interrupts */ + + ADC_INT_ENABLE(highpri->adc1, ADC_IER_JEOS); +#endif + +#ifdef HIGHPRI_HAVE_HRTIM + /* Enable HRTIM TIMA after ADC configuration */ + + HRTIM_TIM_ENABLE(highpri->hrtim, HRTIM_TIMER_TIMA, true); +#endif + +#ifdef HIGHPRI_HAVE_TIM1 + /* Enable timer counter after ADC configuration */ + + PWM_TIM_ENABLE(pwm1, true); #endif while(1) { #ifndef CONFIG_STM32_ADC1_DMA - /* Software triger */ + /* Software trigger for regular sequence */ - adc->ad_ops->ao_ioctl(adc, ANIOC_TRIGGER, 0); + adc1->ad_ops->ao_ioctl(adc1, IO_TRIGGER_REG, 0); usleep(100); +#endif - printf("%d [%d] %0.3fV\n", g_highpri.cntr, g_highpri.current, - g_highpri.volt[g_highpri.current]); +#ifdef HIGHPRI_HAVE_INJECTED + /* Software trigger for injected sequence */ + + adc1->ad_ops->ao_ioctl(adc1, IO_TRIGGER_INJ, 0); + + usleep(100); +#endif + /* Lock global data */ + + g_highpri.lock = true; + +#ifndef CONFIG_STM32_ADC1_DMA + printf("%d [%d] %0.3fV\n", g_highpri.cntr1, g_highpri.current, + g_highpri.r_volt[g_highpri.current]); #else - printf("%d ", g_highpri.cntr); + printf("%d ", g_highpri.cntr1); - for (i = 0; i < DEV1_NCHANNELS; i += 1) + for (i = 0; i < REG_NCHANNELS; i += 1) { - printf("[%d] %0.3fV, ", i, g_highpri.volt[i]); + printf("r:[%d] %0.3fV, ", i, g_highpri.r_volt[i]); } printf("\n"); #endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Print data from injected channels */ + + printf("%d ", g_highpri.cntr2); + + for (i = 0; i < INJ_NCHANNELS; i += 1) + { + printf("j:[%d] %0.3fV, ", i, g_highpri.j_volt[i]); + } + + printf("\n"); +#endif + /* Unlock global data */ + + g_highpri.lock = false; + sleep(1); } diff --git a/configs/stm32f334-disco/buckboost/defconfig b/configs/stm32f334-disco/buckboost/defconfig index 53251b7464..b8991f051e 100644 --- a/configs/stm32f334-disco/buckboost/defconfig +++ b/configs/stm32f334-disco/buckboost/defconfig @@ -104,7 +104,9 @@ CONFIG_START_MONTH=12 CONFIG_START_YEAR=2011 CONFIG_STDIO_BUFFER_SIZE=128 CONFIG_STM32_ADC1=y -CONFIG_STM32_ADC1_INJECTED=y +CONFIG_STM32_ADC1_INJECTED_CHAN=2 +CONFIG_STM32_ADC_CHANGE_SAMPLETIME=y +CONFIG_STM32_ADC_LL_OPS=y CONFIG_STM32_ADC_NOIRQ=y CONFIG_STM32_CCMEXCLUDE=y CONFIG_STM32_HRTIM1=y diff --git a/configs/stm32f334-disco/include/board.h b/configs/stm32f334-disco/include/board.h index 00fc30ad11..d8afff50bf 100644 --- a/configs/stm32f334-disco/include/board.h +++ b/configs/stm32f334-disco/include/board.h @@ -268,13 +268,6 @@ #if defined(CONFIG_EXAMPLES_SMPS) -/* ADC configuration ******************************************************/ - -#define ADC1_INJECTED_CHAN 2 -#define ADC1_EXTSEL_VALUE 0 -#define ADC1_SMP2 ADC_SMPR_61p5 -#define ADC1_SMP4 ADC_SMPR_61p5 - /* HRTIM configuration ******************************************************/ /* Timer A configuration - Buck operations */ diff --git a/configs/stm32f334-disco/src/stm32_smps.c b/configs/stm32f334-disco/src/stm32_smps.c index 11d01d4fda..89a9463038 100644 --- a/configs/stm32f334-disco/src/stm32_smps.c +++ b/configs/stm32f334-disco/src/stm32_smps.c @@ -206,7 +206,7 @@ enum converter_mode_e struct smps_lower_dev_s { FAR struct hrtim_dev_s *hrtim; /* PWM generation */ - FAR struct adc_dev_s *adc; /* input and output voltage sense */ + FAR struct stm32_adc_dev_s *adc; /* input and output voltage sense */ FAR struct comp_dev_s *comp; /* not used in this demo - only as reference */ FAR struct dac_dev_s *dac; /* not used in this demo - only as reference */ FAR struct opamp_dev_s *opamp; /* not used in this demo - only as reference */ @@ -360,8 +360,12 @@ static int smps_setup(FAR struct smps_dev_s *dev) FAR struct smps_lower_dev_s *lower = dev->lower; FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; FAR struct hrtim_dev_s *hrtim = NULL; - FAR struct adc_dev_s *adc = NULL; + FAR struct stm32_adc_dev_s *adc = NULL; FAR struct smps_priv_s *priv; + struct adc_channel_s channels[ADC1_NCHANNELS]; + struct adc_sample_time_s stime; + int ret = OK; + int i = 0; /* Initialize smps structure */ @@ -375,28 +379,49 @@ static int smps_setup(FAR struct smps_dev_s *dev) if (hrtim == NULL) { pwrerr("ERROR: Failed to get hrtim "); + ret = ERROR; + goto errout; } adc = lower->adc; if (adc == NULL) { pwrerr("ERROR: Failed to get ADC lower level interface"); + ret = ERROR; + goto errout; } + /* Update ADC sample time */ + + for (i = 0; i < ADC1_NCHANNELS; i+= 1) + { + channels[i].sample_time = ADC_SMPR_61p5; + channels[i].channel = g_adc1chan[i]; + } + + memset(&stime, 0, sizeof(struct adc_sample_time_s)); + + stime.channels_nbr = ADC1_NCHANNELS; + stime.channel = channels; + + ADC_SAMPLETIME_SET(adc, &stime); + ADC_SAMPLETIME_WRITE(adc); + /* TODO: create current limit table */ UNUSED(priv); - return OK; + +errout: + return ret; } static int smps_start(FAR struct smps_dev_s *dev) { FAR struct smps_lower_dev_s *lower = dev->lower; - FAR struct stm32_adc_dev_s *stm32_adc = - (FAR struct stm32_adc_dev_s *) lower->adc->ad_priv; - FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; - FAR struct smps_priv_s *priv = (struct smps_priv_s *)smps->priv; - FAR struct hrtim_dev_s *hrtim = lower->hrtim; + FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; + FAR struct smps_priv_s *priv = (struct smps_priv_s *)smps->priv; + FAR struct hrtim_dev_s *hrtim = lower->hrtim; + FAR struct stm32_adc_dev_s *adc = lower->adc; volatile uint64_t per = 0; uint64_t fclk = 0; int ret = OK; @@ -482,9 +507,17 @@ static int smps_start(FAR struct smps_dev_s *dev) HRTIM_ALL_OUTPUTS_ENABLE(hrtim, true); - /* Enable ADC interrupts */ + /* Enable ADC JEOS interrupts */ - stm32_adc->ops->int_en(stm32_adc, ADC_INT_JEOS); + ADC_INT_ENABLE(adc, ADC_INT_JEOS); + + /* Enable ADC12 interrups */ + + up_enable_irq(STM32_IRQ_ADC12); + + /* Start injected conversion */ + + ADC_INJ_STARTCONV(adc, true); errout: return ret; @@ -493,19 +526,26 @@ errout: static int smps_stop(FAR struct smps_dev_s *dev) { FAR struct smps_lower_dev_s *lower = dev->lower; - FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; - FAR struct smps_priv_s *priv = (struct smps_priv_s *)smps->priv; - FAR struct hrtim_dev_s *hrtim = lower->hrtim; - FAR struct stm32_adc_dev_s *stm32_adc = - (FAR struct stm32_adc_dev_s *) lower->adc->ad_priv; + FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; + FAR struct smps_priv_s *priv = (struct smps_priv_s *)smps->priv; + FAR struct hrtim_dev_s *hrtim = lower->hrtim; + FAR struct stm32_adc_dev_s *adc = lower->adc; /* Disable HRTIM outputs */ HRTIM_ALL_OUTPUTS_ENABLE(hrtim, false); - /* Disable ADC interrupts */ + /* Stop injected conversion */ - stm32_adc->ops->int_dis(stm32_adc, ADC_INT_JEOS); + ADC_INJ_STARTCONV(adc, false); + + /* Disable ADC JEOS interrupts */ + + ADC_INT_DISABLE(adc, ADC_INT_JEOS); + + /* Disable ADC12 interrups */ + + up_disable_irq(STM32_IRQ_ADC12); /* Reset running flag */ @@ -885,7 +925,6 @@ static void smps_conv_mode_set(struct smps_priv_s *priv, struct smps_lower_dev_s /* Enable outputs */ HRTIM_ALL_OUTPUTS_ENABLE(hrtim, true); - } /**************************************************************************** @@ -894,12 +933,11 @@ static void smps_conv_mode_set(struct smps_priv_s *priv, struct smps_lower_dev_s static void adc12_handler(void) { - FAR struct smps_dev_s *dev = &g_smps_dev; - FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; - FAR struct smps_priv_s *priv = (struct smps_priv_s *)smps->priv; + FAR struct smps_dev_s *dev = &g_smps_dev; + FAR struct smps_s *smps = (FAR struct smps_s *)dev->priv; + FAR struct smps_priv_s *priv = (struct smps_priv_s *)smps->priv; FAR struct smps_lower_dev_s *lower = dev->lower; - FAR struct stm32_adc_dev_s *adc = - (FAR struct stm32_adc_dev_s*)lower->adc->ad_priv; + FAR struct stm32_adc_dev_s *adc = lower->adc; uint32_t pending; float ref = ADC_REF_VOLTAGE; float bit = ADC_VAL_MAX; @@ -907,14 +945,14 @@ static void adc12_handler(void) float out; uint8_t mode; - pending = adc->ops->int_get(adc); + pending = ADC_INT_GET(adc); if (pending & ADC_INT_JEOC && priv->running == true) { /* Get raw ADC values */ - priv->v_out_raw = adc->ops->inj_get(adc, V_OUT_ADC_INJ_CHANNEL); - priv->v_in_raw = adc->ops->inj_get(adc, V_IN_ADC_INJ_CHANNEL); + priv->v_out_raw = ADC_INJDATA_GET(adc, V_OUT_ADC_INJ_CHANNEL); + priv->v_in_raw = ADC_INJDATA_GET(adc, V_IN_ADC_INJ_CHANNEL); /* Convert raw values to real values */ @@ -969,7 +1007,7 @@ static void adc12_handler(void) /* Clear pending */ - adc->ops->int_ack(adc, pending); + ADC_INT_ACK(adc, pending); } /**************************************************************************** @@ -1031,7 +1069,7 @@ int stm32_smps_setup(void) /* Initialize SMPS lower driver interfaces */ lower->hrtim = hrtim; - lower->adc = adc; + lower->adc = adc->ad_priv; lower->comp = NULL; lower->dac = NULL; lower->opamp = NULL; @@ -1056,8 +1094,6 @@ int stm32_smps_setup(void) goto errout; } - up_enable_irq(STM32_IRQ_ADC12); - /* Setup ADC hardware */ adc->ad_ops->ao_setup(adc); diff --git a/configs/stm32f429i-disco/Kconfig b/configs/stm32f429i-disco/Kconfig index e798358984..f605c015c4 100644 --- a/configs/stm32f429i-disco/Kconfig +++ b/configs/stm32f429i-disco/Kconfig @@ -237,4 +237,9 @@ endchoice endif # STM32F429I_DISCO_ILI9341_FBIFACE endif # STM32F429I_DISCO_ILI9341 + +config STM32F429I_DISCO_HIGHPRI + bool "High priority interrupt test" + default n + endif # ARCH_BOARD_STM32F429I_DISCO diff --git a/configs/stm32f429i-disco/highpri/defconfig b/configs/stm32f429i-disco/highpri/defconfig new file mode 100644 index 0000000000..dbe10430cc --- /dev/null +++ b/configs/stm32f429i-disco/highpri/defconfig @@ -0,0 +1,64 @@ +# CONFIG_ARCH_FPU is not set +# CONFIG_STM32_CCMEXCLUDE is not set +# CONFIG_STM32_FLASH_PREFETCH is not set +CONFIG_ADC=y +CONFIG_ANALOG=y +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="stm32f429i-disco" +CONFIG_ARCH_BOARD_STM32F429I_DISCO=y +CONFIG_ARCH_BUTTONS=y +CONFIG_ARCH_CHIP_STM32=y +CONFIG_ARCH_CHIP_STM32F429Z=y +CONFIG_ARCH_HIPRI_INTERRUPT=y +CONFIG_ARCH_RAMVECTORS=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=16717 +CONFIG_BUILTIN=y +CONFIG_DEBUG_NOOPT=y +CONFIG_DISABLE_POLL=y +CONFIG_HAVE_CXX=y +CONFIG_HEAP2_BASE=0xD0000000 +CONFIG_HEAP2_SIZE=8388608 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_FLOATINGPOINT=y +CONFIG_LIBM=y +CONFIG_MAX_TASKS=16 +CONFIG_MAX_WDOGPARMS=2 +CONFIG_MM_REGIONS=3 +CONFIG_NFILE_DESCRIPTORS=8 +CONFIG_NFILE_STREAMS=8 +CONFIG_PREALLOC_MQ_MSGS=4 +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PREALLOC_WDOGS=4 +CONFIG_PWM=y +CONFIG_RAM_SIZE=114688 +CONFIG_RAM_START=0x20000000 +CONFIG_RAW_BINARY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_START_DAY=6 +CONFIG_START_MONTH=12 +CONFIG_START_YEAR=2011 +CONFIG_STM32F429I_DISCO_HIGHPRI=y +CONFIG_STM32_ADC1=y +CONFIG_STM32_ADC1_DMA=y +CONFIG_STM32_ADC1_DMA_CFG=1 +CONFIG_STM32_ADC1_INJECTED_CHAN=1 +CONFIG_STM32_ADC_LL_OPS=y +CONFIG_STM32_ADC_NOIRQ=y +CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG=y +CONFIG_STM32_DMA2=y +CONFIG_STM32_FSMC=y +CONFIG_STM32_FSMC_SRAM=y +CONFIG_STM32_JTAG_SW_ENABLE=y +CONFIG_STM32_PWM_LL_OPS=y +CONFIG_STM32_PWR=y +CONFIG_STM32_TIM1=y +CONFIG_STM32_TIM1_PWM=y +CONFIG_STM32_USART1=y +CONFIG_SYSTEM_READLINE=y +CONFIG_TASK_NAME_SIZE=0 +CONFIG_USART1_SERIAL_CONSOLE=y +CONFIG_USER_ENTRYPOINT="highpri_main" +CONFIG_WDOG_INTRESERVE=0 diff --git a/configs/stm32f429i-disco/include/board.h b/configs/stm32f429i-disco/include/board.h index 9b177c6062..956aebb818 100644 --- a/configs/stm32f429i-disco/include/board.h +++ b/configs/stm32f429i-disco/include/board.h @@ -444,6 +444,22 @@ #endif /* CONFIG_STM32_LTDC */ +/* Configuration specific to high priority interrupts example: + * - TIM1 CC1 trigger for ADC if DMA transfer and TIM1 PWM + * - ADC DMA transfer on DMA1_CH1 + */ + +#ifdef CONFIG_STM32F429I_DISCO_HIGHPRI + +#if defined(CONFIG_STM32_TIM1_PWM) && defined(CONFIG_STM32_ADC1_DMA) + +/* TIM1 - ADC trigger */ + +#define ADC1_EXTSEL_VALUE ADC1_EXTSEL_T1CC1 + +#endif /* CONFIG_STM32_TIM1_PWM */ +#endif /* CONFIG_STM32F429I_DISCO_HIGHPRI */ + /* DMA *************************************************************************/ #define ADC1_DMA_CHAN DMAMAP_ADC1_1 diff --git a/configs/stm32f429i-disco/scripts/ld.script b/configs/stm32f429i-disco/scripts/ld.script index 545afbe7b5..17e0ac2929 100644 --- a/configs/stm32f429i-disco/scripts/ld.script +++ b/configs/stm32f429i-disco/scripts/ld.script @@ -94,6 +94,12 @@ SECTIONS _eronly = ABSOLUTE(.); + /* The RAM vector table (if present) should lie at the beginning of SRAM */ + + .ram_vectors : { + *(.ram_vectors) + } > sram + .data : { _sdata = ABSOLUTE(.); *(.data .data.*) diff --git a/configs/stm32f429i-disco/src/Makefile b/configs/stm32f429i-disco/src/Makefile index 802a39ea6d..3eec3d8eb3 100644 --- a/configs/stm32f429i-disco/src/Makefile +++ b/configs/stm32f429i-disco/src/Makefile @@ -95,4 +95,8 @@ ifeq ($(CONFIG_ADC),y) CSRCS += stm32_adc.c endif +ifeq ($(CONFIG_STM32F429I_DISCO_HIGHPRI),y) +CSRCS += stm32_highpri.c +endif + include $(TOPDIR)/configs/Board.mk diff --git a/configs/stm32f429i-disco/src/stm32_highpri.c b/configs/stm32f429i-disco/src/stm32_highpri.c new file mode 100644 index 0000000000..13b39e4543 --- /dev/null +++ b/configs/stm32f429i-disco/src/stm32_highpri.c @@ -0,0 +1,544 @@ +/**************************************************************************** + * configs/stm32f429i-disco/src/stm32_highpri.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "up_internal.h" +#include "ram_vectors.h" + +#include +#include +#include + +#include "stm32_pwm.h" +#include "stm32_adc.h" +#include "stm32_dma.h" + +#ifdef CONFIG_STM32F429I_DISCO_HIGHPRI + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT +# error CONFIG_ARCH_HIPRI_INTERRUPT is required +#endif + +#ifndef CONFIG_ARCH_RAMVECTORS +# error CONFIG_ARCH_RAMVECTORS is required +#endif + +#ifndef CONFIG_ARCH_IRQPRIO +# error CONFIG_ARCH_IRQPRIO is required +#endif + +#ifndef CONFIG_ARCH_FPU +# warning Set CONFIG_ARCH_FPU for hardware FPU support +#endif + +#ifdef CONFIG_STM32_ADC1_DMA +# if defined(CONFIG_STM32_TIM1_PWM) +# define HIGHPRI_HAVE_TIM1 +# endif +# if (CONFIG_STM32_ADC1_DMA_CFG != 1) +# error ADC1 DMA must be configured in Circular Mode +# endif +# if !defined(HIGHPRI_HAVE_TIM1) +# error "Needs TIM1 to trigger ADC DMA" +# endif +#endif + +#ifdef HIGHPRI_HAVE_TIM1 +# ifndef ADC1_EXTSEL_VALUE +# error ADC1 EXTSEL have to be configured in board.h +# endif +#endif + +#if (CONFIG_STM32_ADC1_INJECTED_CHAN > 0) +# if (CONFIG_STM32_ADC1_INJECTED_CHAN > 1) +# error Max 1 injected channels supported for now +# else +# define HIGHPRI_HAVE_INJECTED +# endif +#endif + +#ifdef HIGHPRI_HAVE_INJECTED +# define INJ_NCHANNELS CONFIG_STM32_ADC1_INJECTED_CHAN +#else +# define INJ_NCHANNELS (0) +#endif + +#ifndef CONFIG_STM32_ADC1_DMA +# define REG_NCHANNELS (1) +#else +# define REG_NCHANNELS (1) +#endif + +#define ADC1_NCHANNELS (REG_NCHANNELS + INJ_NCHANNELS) + +#define DEV1_PORT (1) +#define DEV1_NCHANNELS ADC1_NCHANNELS +#define ADC_REF_VOLTAGE (3.3f) +#define ADC_VAL_MAX (4095) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* High priority example private data */ + +struct highpri_s +{ + FAR struct stm32_adc_dev_s *adc1; +#ifdef HIGHPRI_HAVE_TIM1 + struct stm32_pwm_dev_s *pwm; +#endif + volatile uint32_t cntr1; + volatile uint32_t cntr2; + volatile uint8_t current; + uint16_t r_val[REG_NCHANNELS]; + float r_volt[REG_NCHANNELS]; +#ifdef HIGHPRI_HAVE_INJECTED + uint16_t j_val[INJ_NCHANNELS]; + float j_volt[INJ_NCHANNELS]; +#endif + bool lock; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* ADC channel list */ + +static const uint8_t g_chanlist1[DEV1_NCHANNELS] = +{ + 5, +#if INJ_NCHANNELS > 0 + 13, +#endif +}; + +/* Configurations of pins used by ADC channel */ + +static const uint32_t g_pinlist1[DEV1_NCHANNELS] = +{ + GPIO_ADC1_IN5, /* PA5 */ +#if INJ_NCHANNELS > 0 + GPIO_ADC1_IN13, /* PC3 */ +#endif +}; + +static struct highpri_s g_highpri; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: adc12_handler + * + * Description: + * This is the handler for the high speed ADC interrupt. + * + ****************************************************************************/ + +#if !defined(CONFIG_STM32_ADC1_DMA) || defined(HIGHPRI_HAVE_INJECTED) +void adc_handler(void) +{ + FAR struct stm32_adc_dev_s *adc = g_highpri.adc1; + float ref = ADC_REF_VOLTAGE; + float bit = ADC_VAL_MAX; + uint32_t pending; +#ifdef HIGHPRI_HAVE_INJECTED + int i = 0; +#endif + + /* Get pending ADC1 interrupts */ + + pending = ADC_INT_GET(adc); + + if (g_highpri.lock == true) + { + goto irq_out; + } + +#ifndef CONFIG_STM32_ADC1_DMA + /* Regular channel end of conversion */ + + if (pending & ADC_ISR_EOC) + { + /* Increase regular sequence counter */ + + g_highpri.cntr1 += 1; + + /* Get regular data */ + + g_highpri.r_val[g_highpri.current] = ADC_REGDATA_GET(adc); + + /* Do some floating point operations */ + + g_highpri.r_volt[g_highpri.current] = (float)g_highpri.r_val[g_highpri.current] * ref / bit; + + if (g_highpri.current >= REG_NCHANNELS-1) + { + g_highpri.current = 0; + } + else + { + g_highpri.current += 1; + } + } +#endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Injected channel end of sequence */ + + if (pending & ADC_ISR_JEOC) + { + /* Increase injected sequence counter */ + + g_highpri.cntr2 += 1; + + /* Get injected channels */ + + for (i = 0; i < INJ_NCHANNELS; i += 1) + { + g_highpri.j_val[i] = ADC_INJDATA_GET(adc, i); + } + + /* Do some floating point operations */ + + for (i = 0; i < INJ_NCHANNELS; i += 1) + { + g_highpri.j_volt[i] = (float)g_highpri.j_val[i] * ref / bit; + } + } +#endif + +irq_out: + /* Clear ADC pending interrupts */ + + ADC_INT_ACK(adc, pending); +} +#endif + +/**************************************************************************** + * Name: dma2s0_handler + * + * Description: + * This is the handler for the high speed ADC interrupt using DMA transfer. + * + ****************************************************************************/ + +#ifdef CONFIG_STM32_ADC1_DMA +void dma2s0_handler(void) +{ + float ref = ADC_REF_VOLTAGE; + float bit = ADC_VAL_MAX; + uint8_t pending; + int i; + + pending = stm32_dma_intget(DMA2, DMA_STREAM0); + + if (g_highpri.lock == true) + { + goto irq_out; + } + + /* Increase regular sequence counter */ + + g_highpri.cntr1 += 1; + + for (i = 0; i < REG_NCHANNELS; i += 1) + { + /* Do some floating point operations */ + + g_highpri.r_volt[i] = (float)g_highpri.r_val[i] * ref / bit; + } + +irq_out: + /* Clear DMA pending interrupts */ + + stm32_dma_intack(DMA2, DMA_STREAM0, pending); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: highpri_main + * + * Description: + * Main entry point in into the high priority interrupt test. + * + ****************************************************************************/ + +int highpri_main(int argc, char *argv[]) +{ +#ifdef HIGHPRI_HAVE_TIM1 + struct stm32_pwm_dev_s *pwm1; +#endif + FAR struct adc_dev_s *adc1; + FAR struct highpri_s *highpri; + int ret; + int i; + + highpri = &g_highpri; + + /* Initialize highpri structure */ + + memset(highpri, 0, sizeof(struct highpri_s)); + + printf("\nhighpri_main: Started\n"); + + /* Configure the pins as analog inputs for the selected channels */ + + for (i = 0; i < DEV1_NCHANNELS; i++) + { + stm32_configgpio(g_pinlist1[i]); + } + + /* Initialize ADC driver */ + + adc1 = stm32_adcinitialize(DEV1_PORT, g_chanlist1, DEV1_NCHANNELS); + if (adc1 == NULL) + { + aerr("ERROR: Failed to get ADC interface 1\n"); + ret = EXIT_FAILURE; + goto errout; + } + + highpri->adc1 = (struct stm32_adc_dev_s *)adc1->ad_priv; + +#ifdef HIGHPRI_HAVE_TIM1 + /* Initialize TIM1 */ + + pwm1 = (FAR struct stm32_pwm_dev_s *) stm32_pwminitialize(1); + if (pwm1 == NULL) + { + printf("ERROR: Failed to get PWM1 interface\n"); + ret = EXIT_FAILURE; + goto errout; + } + + highpri->pwm = pwm1; + + /* Setup PWM device */ + + PWM_SETUP(pwm1); + + /* Set timer frequency */ + + PWM_FREQ_UPDATE(pwm1, 1000); + +#if ADC1_EXTSEL_VALUE == ADC1_EXTSEL_T1CC1 + /* Set CCR1 */ + + PWM_CCR_UPDATE(pwm1, 1, 0x0f00); + + /* Enable TIM1 CHAN1 */ + + PWM_OUTPUTS_ENABLE(pwm1, STM32_CHAN1, true); +#else +# error T1CC1 only supported for now +#endif + +#ifdef CONFIG_DEBUG_PWM_INFO + /* Print debug */ + + PWM_DUMP_REGS(pwm1); +#endif + +#endif /* HIGHPRI_HAVE_TIM1 */ + +#if !defined(CONFIG_STM32_ADC1_DMA) || defined(HIGHPRI_HAVE_INJECTED) + /* Attach ADC ram vector if no DMA or injected channels support */ + + ret = up_ramvec_attach(STM32_IRQ_ADC, adc_handler); + if (ret < 0) + { + fprintf(stderr, "highpri_main: ERROR: up_ramvec_attach failed: %d\n", ret); + ret = EXIT_FAILURE; + goto errout; + } + + /* Set the priority of the ADC interrupt vector */ + + ret = up_prioritize_irq(STM32_IRQ_ADC, NVIC_SYSH_HIGH_PRIORITY); + if (ret < 0) + { + fprintf(stderr, "highpri_main: ERROR: up_prioritize_irq failed: %d\n", ret); + ret = EXIT_FAILURE; + goto errout; + } + + up_enable_irq(STM32_IRQ_ADC); +#endif + +#ifdef CONFIG_STM32_ADC1_DMA + /* Attach DMA2 STREAM0 ram vector if DMA */ + + ret = up_ramvec_attach(STM32_IRQ_DMA2S0, dma2s0_handler); + if (ret < 0) + { + fprintf(stderr, "highpri_main: ERROR: up_ramvec_attach failed: %d\n", ret); + ret = EXIT_FAILURE; + goto errout; + } + + /* Set the priority of the DMA2 STREAM0 interrupt vector */ + + ret = up_prioritize_irq(STM32_IRQ_DMA2S0, NVIC_SYSH_HIGH_PRIORITY); + if (ret < 0) + { + fprintf(stderr, "highpri_main: ERROR: up_prioritize_irq failed: %d\n", ret); + ret = EXIT_FAILURE; + goto errout; + } + + up_enable_irq(STM32_IRQ_DMA2S0); +#endif + + /* Setup ADC hardware */ + + adc1->ad_ops->ao_setup(adc1); + +#ifndef CONFIG_STM32_ADC1_DMA + /* Enable ADC regular convertion interrupts if no DMA */ + + ADC_INT_ENABLE(highpri->adc1, ADC_IER_EOC); +#else + /* Note: ADC and DMA must be reset after overrun occurs. + * For this example we assume that overrun will not occur. + * This is true only if DMA and ADC trigger are properly configured. + * DMA configuration must be done before ADC trigger starts! + */ + + /* Register ADC buffer for DMA transfer */ + + ADC_REGBUF_REGISTER(highpri->adc1, g_highpri.r_val, REG_NCHANNELS); +#endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Enable ADC injected channels end of conversion interrupts */ + + ADC_INT_ENABLE(highpri->adc1, ADC_IER_JEOC); +#endif + +#ifdef HIGHPRI_HAVE_TIM1 + /* Enable timer counter after ADC and DMA configuration */ + + PWM_TIM_ENABLE(pwm1, true); +#endif + + while(1) + { +#ifndef CONFIG_STM32_ADC1_DMA + /* Software trigger for regular sequence */ + + adc1->ad_ops->ao_ioctl(adc1, IO_TRIGGER_REG, 0); + + usleep(100); +#endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Software trigger for injected sequence */ + + adc1->ad_ops->ao_ioctl(adc1, IO_TRIGGER_INJ, 0); + + usleep(100); +#endif + /* Lock global data */ + + g_highpri.lock = true; + +#ifndef CONFIG_STM32_ADC1_DMA + printf("%d [%d] %0.3fV\n", g_highpri.cntr1, g_highpri.current, + g_highpri.r_volt[g_highpri.current]); +#else + printf("%d ", g_highpri.cntr1); + + for (i = 0; i < REG_NCHANNELS; i += 1) + { + printf("r:[%d] %0.3fV, ", i, g_highpri.r_volt[i]); + } + + printf("\n"); +#endif + +#ifdef HIGHPRI_HAVE_INJECTED + /* Print data from injected channels */ + + printf("%d ", g_highpri.cntr2); + + for (i = 0; i < INJ_NCHANNELS; i += 1) + { + printf("j:[%d] %0.3fV, ", i, g_highpri.j_volt[i]); + } + + printf("\n"); +#endif + /* Unlock global data */ + + g_highpri.lock = false; + + sleep(1); + } + +errout: + return ret; +} + +#endif /* CONFIG_STM32F429I_DISCO_HIGHPRI */