STM32F411CEU6 ADC data offset does not work
HI,
i am using STM32F411 for a digital signal processing intensive application where the ADC is used for continuous acquisition at 1.6MSPS (via DMA), the firmware was developped on STM32L476 for convenience but the final version uses STM32F411CEU6 because the STM32L4 serie is too expensive.
Now i am facing a big problem, there is apparently no way to set the offset on ADC data as it is done on the STM32L4. The ADC is used to sample an IF at ±700KHz, of course in order to sample this IF i intruduced a DC bias so that the IF signal doesnt no swing under 0.0V, and obviously i have to set a corresponding offset on the ADC data so that when the DC biased wavefor is at zero crossing the ADC value is 0. IN my case the offset value is 1950. ON ths STM32L4 setting this offset was as simple as setting the two following parameters in teh ADC channel setup:
sConfig.OffsetNumber = ADC_OFFSET_1;
sConfig.Offset = 1950;But sadly on STM32F411, even if the field sConfig.Offset is present, it has no effect and is clearly no implemented.
By deesperation i tried to copy and run some of the functions found in L4 HAL library but of course none worked.
/* Internal register offset for ADC group injected offset configuration */
/* (offset placed into a spare area of literal definition) */
#define __ADC_MASK_SHIFT(__BITS__, __MASK__) \
(((__BITS__) & (__MASK__)) >> POSITION_VAL((__MASK__)))
#define __ADC_PTR_REG_OFFSET(__REG__, __REG_OFFFSET__) \
((uint32_t *)((uint32_t) ((uint32_t)(&(__REG__)) + ((__REG_OFFFSET__) << 2U))))
#define ADC_JOFR1_REGOFFSET 0x00000000U
#define ADC_JOFR2_REGOFFSET 0x00001000U
#define ADC_JOFR3_REGOFFSET 0x00002000U
#define ADC_JOFR4_REGOFFSET 0x00003000U
#define ADC_INJ_JDRX_REGOFFSET_MASK (ADC_JDR1_REGOFFSET | ADC_JDR2_REGOFFSET | ADC_JDR3_REGOFFSET | ADC_JDR4_REGOFFSET)
#define ADC_INJ_JOFRX_REGOFFSET_MASK (ADC_JOFR1_REGOFFSET | ADC_JOFR2_REGOFFSET | ADC_JOFR3_REGOFFSET | ADC_JOFR4_REGOFFSET)
#define ADC_INJ_RANK_ID_JSQR_MASK (ADC_CHANNEL_ID_NUMBER_MASK_POSBIT0)
__STATIC_INLINE void LL_ADC_INJ_SetOffset(ADC_TypeDef *ADCx, uint32_t Rank, uint32_t OffsetLevel)
{
register uint32_t *preg = __ADC_PTR_REG_OFFSET(ADCx->JOFR1, __ADC_MASK_SHIFT(Rank, ADC_INJ_JOFRX_REGOFFSET_MASK));
MODIFY_REG(*preg,
ADC_JOFR1_JOFFSET1,
OffsetLevel);
}
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset)
{
__IO uint32_t tmp = 0;
/* Check the parameters */
assert_param(IS_ADC_ALL_PERIPH(ADCx));
assert_param(IS_ADC_INJECTED_CHANNEL(ADC_InjectedChannel));
assert_param(IS_ADC_OFFSET(Offset));
tmp = (uint32_t)ADCx;
tmp += ADC_InjectedChannel;
/* Set the selected injected channel data offset */
*(__IO uint32_t *) tmp = (uint32_t)Offset;
}
#define ADC_InjectedChannel_3 ((uint8_t)0x1C)I really hope that there is a way to set this offset and that it can work.
One could argue that I can still apply the offset on the whole buffer after acquisition, unfortunately i use extensively DSP library for heavy signal processing along with DMA double buffering and the ressource usage is 98% (that is, 98% of the MCU time is used during acquisition via DMA) so there is absolutely no way to apply recursively an offset on each and every 8K samples (per half DMA buffer) before they are processed by the DSP, the whole process is realtime, the acquisition is continuous and DSP processing takes 98% of the MCU time before the next buffer has to be processed so there is no margin.
In the HAL and STM32CubeMX i can see there is an offset for injected channels, but i am not sure how i can use my ADC as injected channel, provided that it must be in continuous DMA acquisition. I use one single channel.
Any information will be very welcome.
