Merged in raiden00/nuttx_pe (pull request #767)

Improvements in STM32 ADC, minor changes in STM32 PWM, DMA, HRTIM and add some highpri ADC examples

arch/arch/src/stm32/stm32_adc: fix RCC reset logic

arch/arch/src/stm32/stm32_adc: move sample time change functions to low-level ADC ops

arch/arch/src/stm32/stm32_adc: configurable ADC DMA mode (one shot mode, circular mode)

arch/arch/src/stm32/stm32_pwm: remove llops_get interface. We can use structure casting to get pwm low-level ops

arch/arch/src/stm32/stm32_pwm: add timer enable/disable and frequency update to low-level ops

arch/src/arm/stm32: remove redundant stm32f33xxx_dma.c

arch/arm/src/stm32/stm32f40xxx_dma.c: add interfaces to interact with highp priority DMA interupts

arch/src/arm/stm32/stm32_hrtim: do not enable timers on startup if option from Kconfig selected and add interface to enable/disable timers

arch/src/arm/stm32/stm32_hrtim: fix some warnings

configs/nucleo-f334r8/highpri: update configuration due to changes in stm32_adc

configs/stm32f334-disco/buckboost: update configuration due to changes in stm32_adc

configs/nucleo-f334r8/highpri: add support for ADC injected sequence, add triggering from TIM1

configs/nucleo-f302r8/highpri: add high priority ADC interrupts example

configs/stm32f429i-disco/highpri: add high priority ADC interrupts example

Approved-by: GregoryN <gnutt@nuttx.org>
This commit is contained in:
Mateusz Szafoni 2018-11-23 23:33:45 +00:00 committed by GregoryN
parent 75f152a0b6
commit fc46135ebc
41 changed files with 3566 additions and 3798 deletions

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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 */

View file

@ -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);

View file

@ -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 */

View file

@ -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)
}

View file

@ -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 */

View file

@ -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)

File diff suppressed because it is too large Load diff

View file

@ -1,731 +0,0 @@
/****************************************************************************
* arch/arm/src/stm32/stm32f33xxx_dma.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Authors: Gregory Nutt <gnutt@nuttx.org>
* Mateusz Szafoni <raiden00@railab.me>
*
* 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 <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <semaphore.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#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 */

View file

@ -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 */

View file

@ -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

View file

@ -5,4 +5,8 @@
if ARCH_BOARD_NUCLEO_F302R8
config NUCLEOF302R8_HIGHPRI
bool "High priority interrupt test"
default n
endif

View file

@ -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

View file

@ -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 */

View file

@ -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.*)

View file

@ -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

View file

@ -0,0 +1,552 @@
/****************************************************************************
* configs/nucleo-f302r8/src/stm32_highpri.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Mateusz Szafoni <raiden00@railab.me>
*
* 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 <nuttx/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <nuttx/arch.h>
#include <nuttx/signal.h>
#include <arch/irq.h>
#include <arch/chip/chip.h>
#include <arch/board/board.h>
#include "up_internal.h"
#include "ram_vectors.h"
#include <nuttx/drivers/pwm.h>
#include <nuttx/analog/adc.h>
#include <nuttx/analog/ioctl.h>
#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 */

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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);

View file

@ -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 <raiden00@railab.me>
*
* Redistribution and use in source and binary forms, with or without
@ -54,10 +54,12 @@
#include "up_internal.h"
#include "ram_vectors.h"
#include <nuttx/drivers/pwm.h>
#include <nuttx/analog/adc.h>
#include <nuttx/analog/ioctl.h>
#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);
}

View file

@ -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

View file

@ -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 */

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.*)

View file

@ -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

View file

@ -0,0 +1,544 @@
/****************************************************************************
* configs/stm32f429i-disco/src/stm32_highpri.c
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Mateusz Szafoni <raiden00@railab.me>
*
* 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 <nuttx/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <nuttx/arch.h>
#include <nuttx/signal.h>
#include <arch/irq.h>
#include <arch/chip/chip.h>
#include <arch/board/board.h>
#include "up_internal.h"
#include "ram_vectors.h"
#include <nuttx/drivers/pwm.h>
#include <nuttx/analog/adc.h>
#include <nuttx/analog/ioctl.h>
#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 */