cancel
Showing results for 
Search instead for 
Did you mean: 

L073: ADC & DMA, strange buffer "shift" in CIRCULAR mode

LCE
Principal II

Heyho,

strange things happening that I'd like to understand for a STM32L073 (Nucleo for now).

Setup on a L073 @ 32MHz:

- ADC is clocked by PCLK/4
- ADC prescaler = 2 -> divide by 4 -> 2 MHz
- 12 bit right aligned
- ref V = VDDA = 3.3V
- hardware oversampling + shift is used (great feature!)
- 7 ADC channels sequenced
- DMA, with buffer for 8 samples per channel -> u16AdcDmaBuf[56]

 

In non-circular mode (CIRC neither set in DMA- nor in AD-registers), after each DMA's transfer complete interrupt, DMA and ADC are restarted, everything is as it should be, and as it is set in the sequencing registers.

Here's what the DMA buffer looks like, and all this makes sense:
buffer[0] = 2031 is the DAC output set to 2047,
buffer[1] & buffer[2] = 4095 are connected to VDDA -> 4095 ok,
buffer[5] is internal VREF = 1.2V -> perfect,
buffer[6] is internal temperature sensor -> ~24°C -> perfect

1) ADC & DMA: not circular

DmaBuf
[00] 2031 4095 4095 1926 3083 1524 0604
[07] 2031 4095 4095 1926 3083 1524 0604
[14] 2031 4095 4095 1927 3081 1525 0604
[21] 2031 4095 4095 1925 3081 1525 0605
[28] 2031 4095 4095 1926 3081 1525 0605
[35] 2031 4095 4095 1926 3081 1525 0605
[42] 2031 4095 4095 1926 3081 1525 0605
[49] 2031 4095 4095 1926 3081 1526 0605
     DAC2 PWR5 PWR3 SNSA SNS5 REFI TMPI

registers:
ADC1->
ISR 0000000B
IER 00000000
CR  10000005
         REGEN
         START
         EN
CFGR1 = 00003001
         CONT
         OVRMOD
         right aligned
         DMAEN

DMA1_Channel1->
CCR 0000358B
         EN
         TCIE
         TEIE
         MINC
         MSIZE = 1 = 16b
         PSIZE = 1 = 16b

 

Now (all before ADC / DMA start) I turn on circular mode in ADC1->CFGR1 |= DMACFG, 
and in DMA1_Channel1->CCR |= CIRC.
And now I still get some nice AD values, but the buffer has shifted by 1, compare to above:

2) ADC & DMA: CIRCular mode

DmaBuf
[00] 0602 2031 4095 4095 1926 3085 1525
[07] 0602 2031 4095 4095 1926 3084 1525
[14] 0602 2031 4095 4095 1925 3083 1525
[21] 0602 2031 4095 4095 1927 3084 1525
[28] 0602 2031 4095 4095 1926 3084 1525
[35] 0602 2031 4095 4095 1926 3084 1525
[42] 0602 2031 4095 4095 1926 3083 1525
[49] 0602 2031 4095 4095 1926 3084 1525
     DAC2 PWR5 PWR3 SNSA SNS5 REFI TMPI

registers:
ADC1->
ISR 0000000B
IER 00000000
CR  10000005
         REGEN
         START
         EN
CFGR1 = 00002003
         CONT
         right
         12b
         DMACFG = CIRC
         DMAEN

DMA1_Channel1->
CCR 000035AB
         EN
         TCIE
         TEIE
         CIRCular
         MINC
         MSIZE = 1 = 16b
         PSIZE = 1 = 16b

 

Note: register dumps are from running application

What am I missing? Been checking all registers, DS, RM, feels like I have overseen one bit or so...

 

Thanks in advance!

15 REPLIES 15
LCE
Principal II

ADC is started last:


...

/* +++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* start prep & start */

	/* DMA1_Channel1_IRQn interrupt configuration */
	NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_IRQ_PRIO_DMA_ADC);
	NVIC_EnableIRQ(DMA1_Channel1_IRQn);

	/* enable DMA */
	DMA1_Channel1->CCR |= DMA_CCR_EN;

	/* enable VREFINT & temperature sensor */
	ADC1_COMMON->CCR |= ( ADC_CCR_TSEN | ADC_CCR_VREFEN );

	/* ADC enable */
	ADC1->CR |= ADC_CR_ADEN;
	/* ADC START */
	ADC1->CR |= ADC_CR_ADSTART;
}

​

 

LCE
Principal II

offline for today, thanks so far !

LCE
Principal II

To make sure it's not the DMA memory buffer access, I added the transfer half complete interrupt (HT).

At HT buffer[0] is copied, at TC (transfer complete) buffer[last] is copied.

No change, still buffer "shift".

LCE
Principal II

So here's the ADC_Init().

With 
ADC_CONT_OVERWR = 1
I get the bad buffer shift.

/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* ADC init function
 */
void ADC_Init(void)
{
	/* peripheral clock enable */
	uint32_t u32TmpReg;
	RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
	u32TmpReg = ( RCC->APB2ENR & RCC_APB2ENR_ADC1EN );
	(void)u32TmpReg;

/* +++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* ADC Init */

	/* reset control register */
	ADC1->CR = 0;
	/* clock prescaler divides by 4 */
	ADC1_COMMON->CCR = ADC_CCR_PRESC_1;
	/* clear interrupt status */
	ADC1->ISR = ( ADC_ISR_EOCAL | ADC_ISR_AWD | ADC_ISR_OVR | ADC_ISR_EOSEQ |
					ADC_ISR_EOC | ADC_ISR_EOSMP | ADC_ISR_ADRDY );
	/* interrupts disabled */
	ADC1->IER = 0;

#if ADC_CONT_OVERWR
	/* continuous mode, overwrite, right aligned, 12bit,
	 *	DMA circular -> auto restart ADC
	 */
	ADC1->CFGR1 = ( ADC_CFGR1_CONT | ADC_CFGR1_OVRMOD | ADC_CFGR1_DMACFG | ADC_CFGR1_DMAEN );
#else	/* not ADC_CONT_OVERWR */
	/* continuous mode, overwrite, right aligned, 12bit,
	 *	DMA NOT circular -> needs to restart ADC
	 */
	ADC1->CFGR1 = ( ADC_CFGR1_CONT | ADC_CFGR1_OVRMOD | ADC_CFGR1_DMAEN );
#endif	/* ADC_CONT_OVERWR */

	/* clock: synchronous 1/4 PCLK,
	 *	+ oversampling
	 */
	ADC1->CFGR2 = ( ADC_CFGR2_CKMODE_1 |
					ADC_CFGR2_OVSE | ADC_CFGR2_OVSS_64 );

	/* sampling time */
	ADC1->SMPR = ADC_SMPR_7_5;

	/* ++++++++++++++++++++++++++++++++++++++++++ */
	/* channel sequencer */
	/* enable channel 1 (force), VREFINT, temperature sensor, ... */
	ADC1->CHSELR = ( 	ADC_CHSELR_CHSEL0  | ADC_CHSELR_CHSEL6  | ADC_CHSELR_CHSEL7  |
						ADC_CHSELR_CHSEL8  | ADC_CHSELR_CHSEL9  |
						ADC_CHSELR_CHSEL17 | ADC_CHSELR_CHSEL18 );

	/* ++++++++++++++++++++++++++++++++++++++++++ */
	/* enable ADC internal voltage regulator */
	ADC1->CR = ADC_CR_ADVREGEN;

	/* delay for ADC internal voltage regulator stabilization */
	uint32_t u32WaitVregCnt = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
	while( u32WaitVregCnt != 0 ) u32WaitVregCnt--;

	/* ADC calibration
	 *	- before ADC enable
	 *	- before DMA enable
	 */
	ADC1->CR |= ADC_CR_ADCAL;

	uint8_t u8AdcError = 0;
	uint32_t u32TickStart = LL_GetTick();

	while( (ADC1->CR & ADC_CR_ADCAL) != 0 )
	{
		/* timeout check */
		if( (LL_GetTick() - u32TickStart) > ADC_TIMEOUT_CAL_MS )
		{
			u8AdcError = 1;
			break;
		}
	}

	if( 0 == u8AdcError )
	{
		/* reset EOCAL bit */
		ADC1->ISR |= ADC_ISR_EOCAL;
		u8ErrorPwr &= ~ERROR_PWR_ADC;
	}
	else
	{
		#if DEBUG_ADC
			uart_printf("#E ADC_Init() CAL, DMA off\n\r");
		#endif 	/* DEBUG_ADC */
		u8ErrorPwr |= ERROR_PWR_ADC;
		return;
	}

/* +++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* DMA settings and start */

	DMA1_Channel1->CCR = 0;

	/* DMA channel selection register, set channel 1, request 0 = ADC => clear C1S */
	DMA1_CSELR->CSELR &= ~DMA_CSELR_C1S;

	/* set DMA channel memory address register */
	DMA1_Channel1->CMAR = (uint32_t)&u16AdcDmaBuf[0];
	/* set DMA channel peripheral address register */
	DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
	/* set DMA channel number of data register */
	DMA1_Channel1->CNDTR = (uint32_t)ADC_DMA_BUF_SIZE;

	/* set DMA channel configuration register */
	/*	PL		Priority Level = very high
	 *	MSIZE	memory size 16 bit
	 *	PSIZE	peripheral size 16 bit
	 *	MINC	memory increment mode
	 *	CIRC	circular
	 *		NOTE: even if ADC ist not set to CIRC DMA, we can save some settings
	 *				if DMA is CIRC
	 *	*IE		interrupt enables
	 *		TEIE	transfer error
	 *		TCIE	transfer complete
	 *		HTIE	half transfer complete
	 */
	DMA1_Channel1->CCR = ( 	DMA_CCR_PL |
							DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 |
							DMA_CCR_MINC |
#if ADC_DMA_CIRC
							DMA_CCR_CIRC |
#endif	/* ADC_DMA_CIRC */
							DMA_CCR_TEIE | DMA_CCR_TCIE | DMA_CCR_HTIE );

	/* clear DMA channel 1 interrupt flags */
	DMA1->IFCR = DMA_IFCR_CGIF1;

	/* reset variables */
	u8AdcDmaTc	 	= 0;
	u32AdcDmaErrCnt = 0;
	u32AdcDmaTcCnt 	= 0;

/* +++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* start prep & start */

	/* DMA1_Channel1_IRQn interrupt configuration */
	NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_IRQ_PRIO_DMA_ADC);
	NVIC_EnableIRQ(DMA1_Channel1_IRQn);

	/* enable DMA */
	DMA1_Channel1->CCR |= DMA_CCR_EN;

	/* enable VREFINT & temperature sensor */
	ADC1_COMMON->CCR |= ( ADC_CCR_TSEN | ADC_CCR_VREFEN );
	ADC1_COMMON->CCR |= ADC_CCR_LFMEN;

	/* ADC enable */
	ADC1->CR |= ADC_CR_ADEN;

	/* ADC ready ? */
	u32TickStart = LL_GetTick();
	while( (ADC1->ISR & ADC_ISR_ADRDY) != 0 )
	{
		/* timeout check */
		if( (LL_GetTick() - u32TickStart) > ADC_TIMEOUT_RDY_MS )
		{
			u8AdcError++;
			break;
		}
	}

	if( u8AdcError != 0 )
	{
		#if DEBUG_ADC
			uart_printf("#E ADC_Init() RDY\n\r");
		#endif 	/* DEBUG_ADC */
		u8ErrorPwr |= ERROR_PWR_ADC;
		return;
	}

	/* ADC START */
	ADC1->CR |= ADC_CR_ADSTART;
}

 

 

In the code above you are setting ADC DMAEN and DMACFG bits BEFORE calibration. This might be the problem. Do it AFTER calibration is completed.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
LCE
Principal II

Bingo! Thanks @gbm , that was it.

Not only DMA controller enable after calibration, but also the DMA enable bit in the ADC register.

 

Edit: still interesting that the problem only occurred with setting the ADC_CFGR1_DMACFG bit (-> circular) in ADC1->CFGR1. Anyway...