cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_ADC_ConvHalfCpltCallback called twice

KD�?b
Associate II

Hello

I try to sample sound at 48kHz using ADC. I use the DMA circular mode. I am using HAL libraries and discovered that HAL_ADC_ConvHalfCpltCallback is called twice sometimes. I get 32 samples from adc, when I get half of them I send them and then when i get HAL_ADC_ConvCpltCallback I send another 16 samples. I did a test with counter, I debugged and saw that sometimes halfCplt callback is called twice. I should get a straight line but that is what I get.

0693W000005BryuQAC.jpgMy code

while (1)
  {
		if (readyToSend1 == true)
			{
				NRF24_write(dataToSend1,32);
				for(int i=0;i<16;i++)
				{
				test[n]=dataToSend1[i];
				if(n<1000)n++;
				}
					readyToSend1 = false;
			}
			
		if (readyToSend2 == true)
			{
				NRF24_write(dataToSend2,32);
					for(int i=0;i<16;i++)
				{
				test[n]=dataToSend2[i];
				if(n<1000)n++;
				}
				readyToSend2 = false;
			}
		
 
	}	
 
 
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
	{
		for (int i=0;i<16;i++)
			{
			dataToSend1[i] = counter;
			counter++;
                        if(counter==1000) 
                        counter=0;
			}		
	readyToSend1 = true;	
	}
 
	void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
	{
 
	for (int i=0;i<16;i++)
			{
				dataToSend2[i] = counter;
				counter++;
                                 if(counter==1000)     
                                counter=0;	
			}		
        readyToSend2 = true;		
	}
 
static void MX_TIM2_Init(void)
{
 
  /* USER CODE BEGIN TIM2_Init 0 */
 
  /* USER CODE END TIM2_Init 0 */
 
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
 
  /* USER CODE BEGIN TIM2_Init 1 */
 
  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 499;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 1;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */
 
  /* USER CODE END TIM2_Init 2 */
 
}
 
 
 
static void MX_ADC1_Init(void)
{
 
  /* USER CODE BEGIN ADC1_Init 0 */
 
  /* USER CODE END ADC1_Init 0 */
 
  ADC_ChannelConfTypeDef sConfig = {0};
 
  /* USER CODE BEGIN ADC1_Init 1 */
 
  /* USER CODE END ADC1_Init 1 */
  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV8;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 
  */
  sConfig.Channel = ADC_CHANNEL_1;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ADC1_Init 2 */
 
  /* USER CODE END ADC1_Init 2 */
 
}
 
 
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Configure the main internal regulator output voltage 
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 96;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}

I would appreciate some help, thank you in advance.

EDIT: I send this info using RF, is it possible that this function takes to much time? If I rewrite my code using only HAL_ADC_ConvCpltCallback, when debugging I see that ADC works well but when test[n]=dataToSend1[i] i get 0 values.

3 REPLIES 3
TDK
Guru

It looks like your data transmission can't keep up with the rate you're sampling.

Reduce the sample rate by an order of magnitude and try again.

As a sanity check, do a calculation of your required data rate and do a test to see how fast you can actually transmit data. Ensure you have enough

You could also do checks to ensure readyToSend2 is set to false, which indicates the transfer is complete, before you set it back to true. If that check fails, your transmission couldn't keep up.

Timers don't stop during debug (by default) so inspecting code via debug may not be useful.

If you feel a post has answered your question, please click "Accept as Solution".
KD�?b
Associate II

I modifed my code

uint8_t readyToSendHalf = 0;
uint8_t readyToSendFull = 0;
uint16_t dataToSendHalf[16]={0};
uint16_t dataToSendFull[16]={0};
uint16_t adcValues[32];
uint16_t test[1000]={0};
 
 while (1)
  {
	if (readyToSendHalf == 1)
		{			
			for(int i = 0;i<16;i++)
			{
				test[n] = dataToSendHalf[i];
				if (n<1000) n++;
			}
			NRF24_write(dataToSendHalf,32);
			readyToSendHalf = 0;
		}
		
         if (readyToSendFull == 1)
		{			
			for(int i = 0;i<16;i++)
			{
				test[n] = dataToSendFull[i];
				if (n<1000) n++;
			}
			NRF24_write(dataToSendFull,32);
			readyToSendFull = 0;
		}			
	}	// endwhile(1)
...
...
...
	void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
	{
	for (int i=0;i<16;i++)
			{
				dataToSendHalf[i] = counter;				
				counter++;if(counter==1000) counter=0;		
			}				
        readyToSendHalf = 1;		
	}
 
	void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
	{
	for (int i=0;i<16;i++)
			{
				dataToSendFull[i] = counter;			
				counter++;if(counter==1000) counter=0;				
			}			
        readyToSendFull = 1;		
	}

I did some maths. My NRF24L01 is set to transmit data at 2Mbps, this is theoritically max. I sample audio at 48 kHz, for now I just sample one channel so the bitrate is 768 000 bps. I reduced the sampling rate to 4,8 kHz and it did not help. I noticed that when I comment out NRF24_write, it works well.

0693W000005BxO9QAK.jpgI send the data without the acknowledgment, maxium data send at one time is 32 bytes that is why I send packages of 16x 2 Bytes samples. Does it mean that fuction responsible for sending data takes to much time? I checked when debugging ,internal sec register and measured the time of executing NRF24_write function.

The time is 0,01s, I do not know if it is correct in keil uVision. That would mean the bitrate is only 25 kbps. I checked also the flags but as I said it looks like while(1) loop is omitted sometimes when debugging, but you said that debugging may not be useful..

KD�?b
Associate II

I got it working with 48 khz sampling using TIM2 and nrf24_write function but I am concerned. It only works when I set adc sampling time to 480 cycles. I got 12 bit resolution. The PCLK2 is 48 Mhz and the prescaler is 8 so the ADCCKL is 6 Mhz. So the sampling time of one sample is (480+12)*1/6 Mhz = 82 us. Sampling rate at 48 khz means the ADC runs every 20us. So I must be ommiting some samples, am I right? It works with the write function but I think that because of the longer sampling time the function finishes before next callback. But still that seems like I was ommiting like 3 samples. Reducing sampling time to i.e. 56 samples or setting ADCCKL makes problem occur again.