Showing results for 
Search instead for 
Did you mean: 

STM32U575 ADC4 is sampling only zero values from pins on GPIOB


Hello everybody

Unfortunately I'm stuck with the problem when using the ADC4 of the STM32U575 VIT6Q revision 01:
Everything works as with the already implemented ADC1, the initialization, starting conversions, the EOC interrupts and reading the data register (ADC4_DR) but I only get 0 out of it, when reading from GPIOB pins.

I've tested the following configurations on the respective GPIO pins (all configured the same, in analog mode):

  • ADC4_IN14 on the internal VBAT signal: working (so ADC4 is actually sampling and delivering values correctly)
  • ADC4_IN9 on PA4: working (so ADC4 principally also works on GPIO pins)
  • ADC4_IN1 on PC0: working
  • ADC4_IN2 on PC1: working
  • ADC4_IN18 on PB0: not working
  • ADC4_IN19 on PB1: not working
  • digital input on PB1: working (so the pin is actually getting a valid signal 0 or 1, depending on the applied voltage)
  • ADC1_IN7 on PA2: working
  • ADC1_IN16 on PB1: working (so the analog frontend of GPIOB is working with ADC1)

By working i mean delivering values other than 0 (when connecting the inputs to GND, the values are around 60...70 out of 4096 resp. 4095 @ 3.3V with the configured 12 bit resolution, so these are plausible values). Not working means the values read from ADC4_DR are constantly 0.


I'm aware of the TZSC feature, whereas "unsecure" peripherals are disconnected by HW when accessing secure GPIOs, according to section "3.13.1 GPIOs TrustZone security" in the "STM32U575xx datasheet" (DS13737 Rev 6), and "Table 10. Non-secure peripheral functions that are not connected to secure I/Os" in the "STM32U575/585 Reference manual" (RM0456 Rev 3). However, the TZSC option bit in FLASH_OPTR is set to zero, meaning that the TrustZone security is disabled. Also, ADC1 and ADC4 are basically working but just not the combination ADC4 with GPIOB.

The "STM32U575xx and STM32U585xx device errata" (ES0499 - Rev 😎 does not mention any problems of this nature regarding ADC4, GPIO or GTZC.


My initialization routine is as follows, using the defined "objects" below:



 * @brief Configuration of the motor interface Adc device
static const AdcDevice_members_t tMotorInterfaceAdcMembers = {
	.ptRuntimeData				= &tMotorInterfaceAdcRuntimeData,
	.ptAdcPeripheral			= ADC1,
	.eAdcIrqN					= ADC1_IRQn,
	.u32AdcChannel				= ADC_CHANNEL_7

 * @brief Configuration of the force sensor monitoring Adc device
static const AdcDevice_members_t tForceSensorMonitoringAdcMembers = {
	.ptRuntimeData				= &tForceSensorMonitoringAdcRuntimeData,
	.ptAdcPeripheral			= ADC4,
	.eAdcIrqN					= ADC4_IRQn,
	.u32AdcChannel				= ADC_CHANNEL_19

void Adc_vInit (const Adc_device_t ptDevice, const Adc_callbackRoutine_t pxHandler)
	AdcDevice_runtimeData_t* const ptRuntimeData = ptDevice->ptRuntimeData;
	ADC_HandleTypeDef* const ptAdcHandle = &ptRuntimeData->tAdcHandle;
	uint32_t u32SamplingTimeCommon = 0u;
	uint32_t u32SamplingTime = 0u;
	uint32_t u32SequencerRank = 0u;

	// register the specified handler
	ptRuntimeData->pxRegisteredHandler = pxHandler;

	// initialize the remaining members of the runtime data
	ptRuntimeData->u32LatestConversionData = 0;

	// enable the VDDA voltage monitor of the associated ADC peripheral
	// wait until the VDDA voltage is enabled
	while ((PWR->SVMSR & PWR_SVMSR_VDDA1RDY) == 0u);
	// declare VDDA independent analog supply as valid

	// enable the clock source of the associated ADC peripheral
	switch ((uint32_t)ptDevice->ptAdcPeripheral)
		case (uint32_t)ADC1:
			 * @remark 20 ADC clock cycles for 12 bit ADC resolution.
			 * Refer to section 29.4.22 "Programmable resolution (RES) - fast conversion mode"
			 * on p.1021 within the "STM32U575/585 Reference manual" (RM0456 Rev 3)
			u32SamplingTimeCommon = ADC_SAMPLETIME_20CYCLES;

			u32SamplingTime = ADC_SAMPLETIME_20CYCLES;
			u32SequencerRank = ADC_REGULAR_RANK_1;

		case (uint32_t)ADC4:
			 * @remark 12.5 ADC clock cycles for 12 bit ADC resolution.
			 * Refer to section 30.4.18 "Programmable resolution (RES) - fast conversion mode"
			 * on p.1101 within the "STM32U575/585 Reference manual" (RM0456 Rev 3)
			u32SamplingTimeCommon = ADC4_SAMPLETIME_12CYCLES_5;

			u32SamplingTime = ADC4_SAMPLINGTIME_COMMON_1;
			u32SequencerRank = ADC4_REGULAR_RANK_1;

			Err_HANDLE_REUSABLE_ERROR((uint32_t)ptDevice->ptAdcPeripheral, "Unsupported ADC peripheral");

	// initialize the associated ADC peripheral
	ptAdcHandle->Instance						= ptDevice->ptAdcPeripheral;
	ptAdcHandle->Init.ClockPrescaler			= ADC_CLOCK_ASYNC_DIV4;		// clock divider = 4
	ptAdcHandle->Init.Resolution				= ADC_RESOLUTION_12B;		// 12 bit ADC resolution
	ptAdcHandle->Init.GainCompensation			= 0u;
	ptAdcHandle->Init.ScanConvMode				= ADC_SCAN_DISABLE;
	ptAdcHandle->Init.DataAlign					= ADC_DATAALIGN_RIGHT;
	ptAdcHandle->Init.EOCSelection				= ADC_EOC_SINGLE_CONV;		// end of single conversion
	ptAdcHandle->Init.LowPowerAutoWait			= DISABLE;
	ptAdcHandle->Init.LowPowerAutoPowerOff		= ADC_LOW_POWER_NONE;
	ptAdcHandle->Init.ContinuousConvMode		= DISABLE;
	ptAdcHandle->Init.NbrOfConversion			= 1u;
	ptAdcHandle->Init.DiscontinuousConvMode		= DISABLE;
	ptAdcHandle->Init.NbrOfDiscConversion		= 1u;
	ptAdcHandle->Init.ExternalTrigConv			= ADC_SOFTWARE_START;		// software triggered
	ptAdcHandle->Init.ExternalTrigConvEdge		= ADC_EXTERNALTRIGCONVEDGE_NONE;
	ptAdcHandle->Init.ConversionDataManagement	= ADC_CONVERSIONDATA_DR;	// conversion data is stored in DR register
	ptAdcHandle->Init.DMAContinuousRequests		= DISABLE;
	ptAdcHandle->Init.Overrun					= ADC_OVR_DATA_OVERWRITTEN;	// overwrite obsolete data
	ptAdcHandle->Init.SamplingTimeCommon1		= u32SamplingTimeCommon;
	ptAdcHandle->Init.SamplingTimeCommon2		= u32SamplingTimeCommon;
	ptAdcHandle->Init.LeftBitShift				= ADC_LEFTBITSHIFT_NONE;
	ptAdcHandle->Init.OversamplingMode			= DISABLE;
	ptAdcHandle->Init.Oversampling.Ratio					= ADC_OVERSAMPLING_RATIO_2;
	ptAdcHandle->Init.Oversampling.RightBitShift			= ADC_RIGHTBITSHIFT_NONE;
	ptAdcHandle->Init.Oversampling.TriggeredMode			= ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
	ptAdcHandle->Init.Oversampling.OversamplingStopReset	= ADC_REGOVERSAMPLING_CONTINUED_MODE;
	ptAdcHandle->Init.TriggerFrequencyMode		= ADC_TRIGGER_FREQ_LOW;
	ptAdcHandle->Init.VrefProtection			= ADC_VREF_PPROT_NONE;
	ASSERT_TRUE(HAL_ADC_Init(ptAdcHandle) == HAL_OK,
				"Failed to initialize Adc");
	// wait until the ADC voltage regulator is enabled
	while ((ptDevice->ptAdcPeripheral->ISR & ADC_ISR_LDORDY) == 0u);

	ADC_ChannelConfTypeDef tAdcChannelConfig = {0};
	tAdcChannelConfig.Channel					= ptDevice->u32AdcChannel;
	tAdcChannelConfig.Rank						= u32SequencerRank;
	tAdcChannelConfig.SamplingTime				= u32SamplingTime;
	tAdcChannelConfig.SingleDiff				= ADC_SINGLE_ENDED;			// single ended (non-differencial)
	tAdcChannelConfig.OffsetNumber				= ADC_OFFSET_NONE;
	tAdcChannelConfig.Offset					= 0x000u;
	tAdcChannelConfig.OffsetRightShift			= DISABLE;
	tAdcChannelConfig.OffsetSignedSaturation	= DISABLE;
	tAdcChannelConfig.OffsetSaturation			= DISABLE;
	tAdcChannelConfig.OffsetSign				= ADC_OFFSET_SIGN_POSITIVE;
	ASSERT_TRUE(HAL_ADC_ConfigChannel(ptAdcHandle, &tAdcChannelConfig) == HAL_OK,
				"Failed to configure channel of Adc");




Does anybody encountered similar problems or has any clue what I'm still missing?


Thanks in advance for the help and best regards



Accepted Solutions

Nevermind, a colleague found the change that solved the problem:

Instead of

ptAdcHandle->Init.ScanConvMode				= ADC_SCAN_DISABLE;


ptAdcHandle->Init.ScanConvMode				= ADC_SCAN_DIRECTION_FORWARD;



View solution in original post


Nevermind, a colleague found the change that solved the problem:

Instead of

ptAdcHandle->Init.ScanConvMode				= ADC_SCAN_DISABLE;


ptAdcHandle->Init.ScanConvMode				= ADC_SCAN_DIRECTION_FORWARD;