Skip to main content
Senior
March 23, 2024
Solved

How the ADC works in F103RC

  • March 23, 2024
  • 2 replies
  • 3259 views

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

 

This topic has been closed for replies.
Best answer by raptorhal2

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.

2 replies

raptorhal2
Lead
March 23, 2024

Did you change to convertedData[6] ?

ChaoAuthor
Senior
March 23, 2024

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.

raptorhal2
Lead
March 23, 2024

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

mƎALLEm
Technical Moderator
March 23, 2024

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."
ChaoAuthor
Senior
March 23, 2024

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).

mƎALLEm
Technical Moderator
March 23, 2024

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."