Skip to main content
SLevi.1
Associate III
January 25, 2026
Question

Using ADCCTRL to read an external voltage

  • January 25, 2026
  • 2 replies
  • 200 views

Starting with the BLE_Heartrate example, I want to measure a voltage on PA8 of STM32WBA65. The BLE_Heartrate project already has the option of using ADCCTRL to read the internal temperature so as to calibrate the BLE power.

I have added PA8 as ADC_Channel1 in CubeMX. Do I need to call MX_ADC4_Init or not?

How do I achieve a read of PA8 in my timed task? The call to ADCCTRL_RequestRawValue always returns without error, but the value read is always 1 or 2. There is definitely 1.0v on this pin.

My code (copied from the temp_measurement.c of WPAN) is:

static ADCCTRL_Handle_t LLADCRequest_Handle =
{
 .Uid = 0x00,
 .State = ADCCTRL_HANDLE_NOT_REG,
 .InitConf =
 {
 .ConvParams =
 {
 .TriggerFrequencyMode = LL_ADC_TRIGGER_FREQ_LOW,
 .Resolution = LL_ADC_RESOLUTION_12B,
 .DataAlign = LL_ADC_DATA_ALIGN_RIGHT,
 .TriggerStart = LL_ADC_REG_TRIG_SOFTWARE,
 .TriggerEdge = LL_ADC_REG_TRIG_EXT_RISING,
 .ConversionMode = LL_ADC_REG_CONV_SINGLE,
 .DmaTransfer = LL_ADC_REG_DMA_TRANSFER_NONE,
 .Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN,
 .SamplingTimeCommon1 = LL_ADC_SAMPLINGTIME_814CYCLES_5,
 .SamplingTimeCommon2 = LL_ADC_SAMPLINGTIME_1CYCLE_5
 },
 .SeqParams =
 {
 .Setup = LL_ADC_REG_SEQ_CONFIGURABLE,
 .Length = LL_ADC_REG_SEQ_SCAN_DISABLE,
 .DiscMode = LL_ADC_REG_SEQ_DISCONT_DISABLE
 },
 .LowPowerParams =
 {
 .AutoPowerOff = DISABLE,
 .AutonomousDPD = LL_ADC_LP_AUTONOMOUS_DPD_DISABLE
 }
 },
 .ChannelConf =
 {
 .Channel = LL_ADC_CHANNEL_0,//LL_ADC_CHANNEL_TEMPSENSOR,
 .Rank = LL_ADC_REG_RANK_2,
 .SamplingTime = LL_ADC_SAMPLINGTIME_COMMON_1
 }
};
	uint16_t battery = 3700;


ADCCTRL_Cmd_Status_t eReturn = ADCCTRL_RegisterHandle (&LLADCRequest_Handle);
		 UTIL_SEQ_PauseTask(1U << CFG_TASK_TEMP_MEAS);
		 /* Enter limited critical section : disable all the interrupts with priority higher than RCC one
		 * Concerns link layer interrupts (high and SW low) or any other high priority user system interrupt
		 */
		 UTILS_ENTER_LIMITED_CRITICAL_SECTION(RCC_INTR_PRIO<<4);

		/* Request ADC IP activation */
		ADCCTRL_Cmd_Status_t ret = ADCCTRL_RequestIpState(&LLADCRequest_Handle, ADC_ON);

		/* Get temperature from ADC dedicated channel */
//				 ADCCTRL_RequestTemperature (&LLADCRequest_Handle,
//				 &temperature_value);
		ret = ADCCTRL_RequestRawValue (&LLADCRequest_Handle, &battery);

		/* Request ADC IP deactivation */
		ret = ADCCTRL_RequestIpState(&LLADCRequest_Handle, ADC_OFF);

		 /* Exit limited critical section */
		 UTILS_EXIT_LIMITED_CRITICAL_SECTION();

		 // Resume BLE temp task
		 UTIL_SEQ_ResumeTask(1U << CFG_TASK_TEMP_MEAS);

 

2 replies

SLevi.1
SLevi.1Author
Associate III
February 7, 2026

So are we to assume no-one at ST has any knowledge of the ADCCTRL code?

TDK
Super User
February 8, 2026

Does the unmodified example work as intended?

> .Rank = LL_ADC_REG_RANK_2,

Instead of adding a new channel, it may be easier to replace the existing channel with the new one. Reading multiple channels typically requires DMA which would require quite a few changes to the code.

"If you feel a post has answered your question, please click ""Accept as Solution""."