cancel
Showing results for 
Search instead for 
Did you mean: 

How the ADC works in F103RC

Chao
Senior

I've been confused for days and am unable to make the ADC work on F103RC and have to seek for help.

The test consists of ADC1 with 6 channels, an UART for printf and an I/O port that drives an LED. 

The ADC configuration:

Chao_0-1711202637902.png

Chao_2-1711202730095.png

 

Chao_1-1711202678933.png

Chao_3-1711202780449.png

Chao_4-1711202849091.png

The test code:

 

/* USER CODE BEGIN PD */
#define	 DMA_NOT_COMPLETED	0
#define	 DMA_COMPLETED		1
#define	 DMA_NOT_STARTED	2
#define	 VREFINT_CHAN		0
#define	 TEMP_SENSOR_CHAN	1
/* USER CODE END PD */
/* USER CODE BEGIN PV */
uint8_t dmaTransferStatus = DMA_NOT_STARTED;
uint16_t convertedData[2] = { 0 };
int Vrefint =0;
int Tmcu = 0;
int Vsense = 0;
int tick = 0;
uint32_t startTick;
/* USER CODE END PV */
/* USER CODE BEGIN PFP */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
/* USER CODE END PFP */
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_UART5_Init();
  /* USER CODE BEGIN 2 */
  HAL_ADCEx_Calibration_Start(&hadc1);
  HAL_ADC_Start_DMA(&hadc1, (uint32_t *)convertedData, 2);
  startTick = HAL_GetTick();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if (dmaTransferStatus == DMA_COMPLETED)
	  {
		  Vrefint = convertedData[VREFINT_CHAN] * 3300 / 4096;
		  Vsense = convertedData[TEMP_SENSOR_CHAN] * 3300 / 4096;
		  Tmcu = (1430 - Vsense) / 4.3 + 25;
		  dmaTransferStatus = DMA_NOT_STARTED;
		  printf("tick = %ds - Vrefint = %d  Tmcu = %d\n", tick, Vrefint, Tmcu);
	  }
	  if ((HAL_GetTick() - startTick) > 1000)
	  {
		  tick++;
		  startTick = HAL_GetTick();
//		  if (dmaTransferStatus == DMA_NOT_STARTED)
		  {
			  convertedData[VREFINT_CHAN] = 0;
			  convertedData[TEMP_SENSOR_CHAN] = 0;
			  HAL_ADC_Start_DMA(&hadc1, (uint32_t *)convertedData, 2);
			  dmaTransferStatus = DMA_NOT_COMPLETED;
		  }
		  HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_15);
	  }
  }
  /* USER CODE END 3 */
}
static void MX_ADC1_Init(void)
{
  ADC_ChannelConfTypeDef sConfig = {0};
  hadc1.Instance = ADC1;
  hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 6;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  sConfig.Channel = ADC_CHANNEL_VREFINT;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
  sConfig.Rank = ADC_REGULAR_RANK_2;
  sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = ADC_REGULAR_RANK_3;
  sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfig.Rank = ADC_REGULAR_RANK_4;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfig.Rank = ADC_REGULAR_RANK_5;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfig.Rank = ADC_REGULAR_RANK_6;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
}
static void MX_DMA_Init(void)
{
  __HAL_RCC_DMA1_CLK_ENABLE();

  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
  dmaTransferStatus = DMA_COMPLETED;
}
PUTCHAR_PROTOTYPE
{
  HAL_UART_Transmit(&huart5, (uint8_t *)&ch, 1, 0xFFFF);

  return ch;
}
/* USER CODE END 4 */

 

When call HAL_ADC_Start_DMA(&hadc1, (uint32_t *)convertedData, 2), It complets a conversion every 3 seconds:

tick = 0s - Vrefint = 1185 Tmcu = 34
tick = 3s - Vrefint = 1185 Tmcu = 34
tick = 6s - Vrefint = 1185 Tmcu = 34
tick = 9s - Vrefint = 1185 Tmcu = 34
tick = 12s - Vrefint = 1185 Tmcu = 34
tick = 15s - Vrefint = 1185 Tmcu = 34
tick = 18s - Vrefint = 1185 Tmcu = 34

Is this because the ADC only calls its complete- callback function when all 6 channels complete their conversions, so it needs to be triggered 3 times(each time two channnels get triggered), and the results presented are actually correct?

When call HAL_ADC_Start_DMA(&hadc1, (uint32_t *)convertedData, 6), the ADC calls its complete- callback function every second, and gave the following result which I completely don't have any clue:

tick = 0s - Vrefint = 1184 Tmcu = 34
tick = 1s - Vrefint = 1747 Tmcu = -28
tick = 2s - Vrefint = 1745 Tmcu = 81
tick = 3s - Vrefint = 1185 Tmcu = 34
tick = 4s - Vrefint = 1738 Tmcu = -26
tick = 5s - Vrefint = 1639 Tmcu = 81
tick = 6s - Vrefint = 1184 Tmcu = 34
tick = 7s - Vrefint = 1739 Tmcu = -26
tick = 8s - Vrefint = 1638 Tmcu = 81
tick = 9s - Vrefint = 1185 Tmcu = 34
tick = 10s - Vrefint = 1746 Tmcu = -27
tick = 11s - Vrefint = 1598 Tmcu = 81
tick = 12s - Vrefint = 1185 Tmcu = 34
tick = 13s - Vrefint = 1737 Tmcu = -25
tick = 14s - Vrefint = 1636 Tmcu = 81
tick = 15s - Vrefint = 1185 Tmcu = 34
tick = 16s - Vrefint = 1612 Tmcu = -41
tick = 17s - Vrefint = 1590 Tmcu = 81
tick = 18s - Vrefint = 1185 Tmcu = 34
tick = 19s - Vrefint = 1735 Tmcu = -25
tick = 20s - Vrefint = 1598 Tmcu = 81
tick = 21s - Vrefint = 1185 Tmcu = 34
tick = 22s - Vrefint = 1612 Tmcu = -41
tick = 23s - Vrefint = 1590 Tmcu = 81
tick = 24s - Vrefint = 1185 Tmcu = 34
tick = 25s - Vrefint = 1611 Tmcu = -41
tick = 26s - Vrefint = 1639 Tmcu = 81
tick = 27s - Vrefint = 1185 Tmcu = 34
tick = 28s - Vrefint = 1611 Tmcu = -41
tick = 29s - Vrefint = 1597 Tmcu = 81
tick = 30s - Vrefint = 1185 Tmcu = 34

The above result has a fixed pattern:

1. it repeats every 6 seconds

2. in the 6-second data patterns, the results from the 1st second and the 4th second are expected results

Uncomment the code at line 54, the result does not change.

Anyone could let me know anything wrong with my configuration or in my code? And what's happenning in the tests?

Any suggestions or replies would be highly appreciated.

Regards

Chao

 

1 ACCEPTED SOLUTION

Accepted Solutions

The ADC is set to continuous mode, so the callback will set the dmaTransfer status very very frequently.

Disable continuous mode to regain control of what is happening.

View solution in original post

15 REPLIES 15
raptorhal2
Lead

Did you change to convertedData[6] ?

SofLit
ST Employee

Hello,

First, you need to describe what do you want to achieve as the issue is not clear.

Second, you can share your project including the ioc file so community members can help you efficiently.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

I am not sure what you meant by "Did you change to convertedData[6] ", if you meant whether or not the code was changed to HAL_ADC_Start_DMA(&hadc1, (uint32_t *)convertedData, 6) from HAL_ADC_Start_DMA(&hadc1, (uint32_t *)convertedData, 2) and ran, then yes, the second test was done with this change.

What I want to achieve is to get the ADC conversion result once every second by triggering the ADC once each second. The conversion results of all 6 channels are collected when DMA transfer completes (except for the Vrefint channel and temp sensor channel, other 4 channels are not connected to any signals in the test). I don't get the right values from convertedData[0] and convertedData[1] for the Vrefint and internal temperature.

Please see attached for the ioc file and the whole project (SimpleF103RCT6.rar).

I meant did you change the storage buffer size from [2] to [6].

What I want to achieve is to get the ADC conversion result once every second by triggering the ADC once each second.


First better to use a timer to trigger the ADC to start this sequence each 1 second and when the ADC conversion completes do what you want to do (computation etc ..)

So this is not a good way to do that:

	  if ((HAL_GetTick() - startTick) > 1000)
	  {
		  tick++;
		  startTick = HAL_GetTick();
//		  if (dmaTransferStatus == DMA_NOT_STARTED)
		  {
			  convertedData[VREFINT_CHAN] = 0;
			  convertedData[TEMP_SENSOR_CHAN] = 0;
			  HAL_ADC_Start_DMA(&hadc1, (uint32_t *)convertedData, 2);
			  dmaTransferStatus = DMA_NOT_COMPLETED;
		  }

Second see this thread, I've already posted a project working with STM32L152 device. The ADC is triggered by TIM2 and a sequence of 3 channel conversions is performed.

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Oh, sorry.

In the above given test (the second test), the storage buffer size was indeed not changed to [6], however I just did a new test with the storage buffer size changed to convertedData[6], and got the same result:

Chao_0-1711220489128.png

It keeps reading out the same 6-second data pattern. the Vrefint should always be read out 1184mv or 1185mv, but I got only 2 correct readings every 6 seconds, why it's 6? what's its relationship with 6 channels?), why the readings are wrong for the other 4 seconds?

With STM32G070RB, there is an option EOCSelection that can be set to ADC_EOC_SEQ_CONV

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

This setting would instruct the ADC to do the conversions one by one on all channels as a sequence with one trigger, and calls the complete-callback function after having finished the conversions on all channels.

But with F103RC, I did not find the description on sequence conversion in reference manual, and CubeMX does not provide such an option neither.

I didn't spend too much effort to make the ADC of 6 channels work on Nucleo-G070RB board.

Thanks. I'll have a look at it.

Although the one second timing is not the best implementation of a one-second timer, but it could be enough for a simple  ADC test, as it works in my ADC tests on Nucleo-G070RB board. As stated in my reply to raptorhal2 earlier, the wrong reading is periodical, it repeats every 6 seconds, I don't know whether or not it's associated with the number (6)  of conversion channels.

I just increased the number of channels from 6 to 8, and the ADC readings look in the same pattern as in 6-channel test: repeat every 6 seconds:

Chao_1-1711223473886.png

But when changed the number of channels to 4, the ADC readings seem different:

Chao_2-1711224043717.png

 

 

 

 

The ADC is set to continuous mode, so the callback will set the dmaTransfer status very very frequently.

Disable continuous mode to regain control of what is happening.