Skip to main content
MMust.5
Senior
July 23, 2023
Solved

The sequence from the ADC_SQR3 register does not work.

My goal now is to understand how ADC works.
I know that with the HAL_ADC_Start_DMA function, I can easily read data from multiple pins.
Now I want to set up data transfer from pins in semi-automatic mode, without the HAL_ADC_Start_DMA function.
I know how to do it when sConfig.Rank == 1
 
My task is to transfer data from several pins when sConfig.Rank is greater than 1.
In Cube MX this parameter is called: Number of Conversion.
-----------------------------------------------
Scan Conversion Mode enabled.
In the while loop, I set up the sequence in the ADC_SQR3 register:
 
Channel Five, First Rank
sConfig.Channel = ADC_CHANNEL_5;
sConfig.Rank = 1;
 
Channel six, second rank
sConfig.Channel = ADC_CHANNEL_6;
sConfig.Rank = 2;
 
(The code is a little more complicated of course, I write the most important thing so as not to complicate.)
A sequence appears in the ADC_SQR3 register.
But when I then write HAL_ADC_PollForConversion(&hadc1, 1000);
That conversion occurs only for the first Rank, in this case for the fifth channel. 
The second Rank is not converted. Why?
png.png
 
Full code:

 

static void MX_ADC1_Init(void)
{
 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
 hadc1.Init.Resolution = ADC_RESOLUTION_12B;
 hadc1.Init.ScanConvMode = ENABLE;
 hadc1.Init.ContinuousConvMode = DISABLE;
 hadc1.Init.DiscontinuousConvMode = DISABLE;
 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc1.Init.NbrOfConversion = 3;
 hadc1.Init.DMAContinuousRequests = ENABLE;
 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
 Error_Handler();
 }
}

 void ADC_Select_CH0 (void)
{
 ADC_ChannelConfTypeDef sConfig = {0};
 sConfig.Channel = ADC_CHANNEL_5;
 sConfig.Rank = 1;
 sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
}

 void ADC_Select_CH1 (void)
{
 ADC_ChannelConfTypeDef sConfig = {0};
 sConfig.Channel = ADC_CHANNEL_6;
 sConfig.Rank = 2;
 sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }
}
uint16_t a[10]={0};
while (1)
{
 ADC_Select_CH5();
 ADC_Select_CH6();
 HAL_ADC_Start(&hadc1);
 HAL_ADC_PollForConversion(&hadc1, 1000);
 a[0] = HAL_ADC_GetValue(&hadc1);
 HAL_ADC_Stop(&hadc1);
}

 

 
 
This topic has been closed for replies.
MMust.5
MMust.5Best answer
Senior
July 25, 2023
I don't understand how I did it, but I did it.
Previously, I ran with the same settings, but it did not work.
I think it's an unstable system.
I think that in order for everything to work stably, it is necessary to rewrite the HAL_ADC_PollForConversion function.

 

#include "main.h"
#include <stdio.h>
uint16_t a[5]={0};
while (1)
 {
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
a[0]=HAL_ADC_GetValue(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
a[1]=HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);

printf("%d\n", a[0]);
printf("%d\n", a[1]);
 }


static void MX_ADC1_Init(void)
{
 ADC_ChannelConfTypeDef sConfig = {0};
 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
 hadc1.Init.Resolution = ADC_RESOLUTION_12B;
 hadc1.Init.ScanConvMode = ENABLE;
 hadc1.Init.ContinuousConvMode = DISABLE;
 hadc1.Init.DiscontinuousConvMode = DISABLE;
 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc1.Init.NbrOfConversion = 2;
 hadc1.Init.DMAContinuousRequests = ENABLE;
 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
 Error_Handler();
 }

 sConfig.Channel = ADC_CHANNEL_7;
 sConfig.Rank = 1;
 sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 sConfig.Channel = ADC_CHANNEL_8;
 sConfig.Rank = 2;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

}

 

This code works for me and takes data from two Ranks.
But I think it is necessary to rewrite the HAL_ADC_PollForConversion function.
In the HAL_ADC_PollForConversion function, the ADC_SR_EOC bit is enabled after the conversion is completed.
If such settings are set hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; then all Ranks are converted in order, and after each Rank is converted, the ADC_SR_EOC bit is set.
And after the end of the conversion, you must immediately start the next conversion.
In my code above, I probably somehow accidentally manage to make it in these gaps, but I don't think this code is reliable.
But it works.
png.png

 

15 replies

AScha.3
Super User
July 23, 2023

maybe because you set end of conversion -> single conversion

AScha3_0-1690122394934.png

try

AScha3_1-1690122421849.png

 

If you feel a post has answered your question, please click on " Best Answer ".
MMust.5
MMust.5Author
Senior
July 23, 2023
No, that's not the reason.
I changed this setting.
The problem is that only the first Rank from the ADC_SQR3 register is measured.
Second Rank is never measured for some reason.
My task is also to measure the second Rank from the ADC_SQR3 register. 
waclawek.jan
Super User
July 24, 2023

 

Which STM32?

> My goal now is to understand how ADC works.

Then don't use Cube/HAL. It hides the details. Read the ADC chapter in manual, and write your own code.

> only the first Rank from the ADC_SQR3 register is measured.

 How do you know?

Where do you set the sequence length?

JW

MMust.5
MMust.5Author
Senior
July 24, 2023

>Where do you set the sequence length?

hadc1.Init.NbrOfConversion = 2;

waclawek.jan
Super User
July 24, 2023

Which STM32?

> only the first Rank from the ADC_SQR3 register is measured.

 How do you know?

>> Where do you set the sequence length?
> hadc1.Init.NbrOfConversion = 2;

Well, I don't see it in ADC_SQR1.L, in the list of registers you've given.

As I've said, if you want to learn how ADC works, don't use Cube/HAL, write your own code based on reading and understanding the manual.

JW

MMust.5
MMust.5Author
Senior
July 24, 2023

Thank you.
The SQR1 register actually contained the number 1.
I put 2, but it still didn't help.
ADC1->SQR1=2097152;
2097152==0010 0000 0000 0000 0000 0000
I have STM32F407VGT6

png.png

LCE
Principal III
July 24, 2023

In my H723 ADC setup I'm using the HAL defines for setting the rank, because there's some bit shifting involved, but I don't know if that applies to the F4 as well.

sConfig.Rank = ADC_REGULAR_RANK_2;

MMust.5
MMust.5Author
Senior
July 24, 2023

This definitely works in STM32F407.
sConfig.Rank = 2;
Here is an example if I set ONLY the second Rank.

png.png

MMust.5
MMust.5Author
Senior
July 24, 2023

The problem is that the DR register is 16 bit and when I write like this
a[0] = HAL_ADC_GetValue(&hadc1);
then I load the result from only one Rank.
How to download the result from the second Rank

And when I write this
HAL_ADC_Start(&hadc1);
then the conversion always starts from the first Rank

Maybe the second Rank is being converted, but I just don't know how to save the result of the conversion.

waclawek.jan
Super User
July 24, 2023

Note, that ADC starts the second conversion immediately after the first on ends, so if your check-conversion-end and readout functions take longer than the second conversion, the first conversion's result is already lost and you are reading only the second conversion's result.

JW

MMust.5
MMust.5Author
Senior
July 24, 2023

I can never read the result of the second transformation.

waclawek.jan
Super User
July 24, 2023

This may be consequence of overrun, too. The RM is not entirely clear whether in case of overrun the old result is retained or it's overwritten with the new one.

Check the OVR bit in ADC_SR.

JW

MMust.5
MMust.5AuthorBest answer
Senior
July 25, 2023
I don't understand how I did it, but I did it.
Previously, I ran with the same settings, but it did not work.
I think it's an unstable system.
I think that in order for everything to work stably, it is necessary to rewrite the HAL_ADC_PollForConversion function.

 

#include "main.h"
#include <stdio.h>
uint16_t a[5]={0};
while (1)
 {
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
a[0]=HAL_ADC_GetValue(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
a[1]=HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);

printf("%d\n", a[0]);
printf("%d\n", a[1]);
 }


static void MX_ADC1_Init(void)
{
 ADC_ChannelConfTypeDef sConfig = {0};
 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
 hadc1.Init.Resolution = ADC_RESOLUTION_12B;
 hadc1.Init.ScanConvMode = ENABLE;
 hadc1.Init.ContinuousConvMode = DISABLE;
 hadc1.Init.DiscontinuousConvMode = DISABLE;
 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc1.Init.NbrOfConversion = 2;
 hadc1.Init.DMAContinuousRequests = ENABLE;
 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;

 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
 Error_Handler();
 }

 sConfig.Channel = ADC_CHANNEL_7;
 sConfig.Rank = 1;
 sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

 sConfig.Channel = ADC_CHANNEL_8;
 sConfig.Rank = 2;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
 Error_Handler();
 }

}

 

This code works for me and takes data from two Ranks.
But I think it is necessary to rewrite the HAL_ADC_PollForConversion function.
In the HAL_ADC_PollForConversion function, the ADC_SR_EOC bit is enabled after the conversion is completed.
If such settings are set hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; then all Ranks are converted in order, and after each Rank is converted, the ADC_SR_EOC bit is set.
And after the end of the conversion, you must immediately start the next conversion.
In my code above, I probably somehow accidentally manage to make it in these gaps, but I don't think this code is reliable.
But it works.
png.png

 

LCE
Principal III
July 25, 2023

Sooner or later you should throw out any polling stuff anyway...

On a H735 I have 7 sequenced ADC channels running all the time in the background with circular DMA for monitoring several power supplies. Every 100 ms or so the buffer is checked, with least priority.