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

 

15 REPLIES 15

Although the one second timing is not the best implementation of a one-second timer

 Not the best? why? because it's a test? or because it's more difficult to implement?

You need either (as said by @raptorhal2 ) to disable the Continuous Conversion Mode or enable DMA Circular mode and use Timer to trigger the ADC conversion each 1 second. 

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.

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

I didn't see this. The printf under the condition "if (dmaTransferStatus == DMA_COMPLETED)"  is to test this, and it prints once a second in tests.

>Disable continuous mode to regain control of what is happening

It woks! Thank you so much.

>Not the best? why? because it's a test? or because it's more difficult to implement?

Sorry, I meant my implementation of the one-second timer is not the best.

>You need either (as said by @raptorhal2 ) to disable the Continuous Conversion Mode or enable DMA Circular mode

Yes, I followed @raptorhal2's suggestion to disable the Continuous Conversion Mode and it works. 

I will test the DMA Circular mode later as I really need the Continuous Conversion Mode to work.

Thank you very much!

I tested Continuous Conversion Mode + DMA Circular mode, and expected that the ADC perform conversion again and again so that whenever I need I could read the result (e.g. every application loop), but it does not print out any ADC result for me, probably there are too many interrupts issued in a chain, and CubeMX does not allow me to disable the DMA interrupt.

<I really need the Continuous Conversion Mode to work.>

Then disable any end of conversion detection. Start the conversion and read the buffer when you need the data.

>Then disable any end of conversion detection

I think this could only be done by modifying adc.c as I didn't find the way in CubeMX