cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4 ADC + DMA Multiple Channels (> 6 Channels) not working

Hailing SKY
Associate II

Dear All,

I am using the ADC + DMA function in STM32L476 to record data from multiple sensing inputs (12 channels in total). I have succeeded to record 4 channels using ADC1_IN1, IN6, IN7 and IN8, but when I increased the channel number to 6, the results are wrong.

The CH1 data were overwritten by the data from CH6, and there was nothing for the location where data from CH6 should be.

Here are my codes (partial). Please let me know your ideas.

The attached code is for NUCLEO - L476RG board.

#define BUF_SIZE (4000) // data length for each channel
#define CHANNEL_COUNT (4) // change to 6 in the 6-channel case
 
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
 
/* Private variables ---------------------------------------------------------*/
uint8_t datastore1[BUF_SIZE]={0};
uint8_t datastore2[BUF_SIZE]={0};
uint8_t datastore3[BUF_SIZE]={0};
uint8_t datastore4[BUF_SIZE]={0};
// uint8_t datastore5[BUF_SIZE]={0};
// uint8_t datastore6[BUF_SIZE]={0};
uint8_t adcValue[CHANNEL_COUNT*BUF_SIZE]={0};
uint8_t indi_led = 0;
uint8_t indi_int = 0;
 
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_ADC1_Init(void);
 
int main(void)
{
 
 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
 HAL_Init();
 SystemClock_Config();
 
 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 MX_DMA_Init();
 // MX_USART1_UART_Init();
 MX_ADC1_Init();
 
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 { // if interruptted, indi_int = 1
 if (indi_int == 1)
 {
 // HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); // PE7 interrupt
 // HAL_Delay(3000);
 indi_int = 0;
 HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_SET);
 HAL_ADC_Start_DMA(&hadc1,(uint32_t*)adcValue,BUF_SIZE*CHANNEL_COUNT); // start conversion
 HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, GPIO_PIN_SET);
 }
 
 if (indi_led == 1)
 {
 HAL_UART_Transmit(&huart1,(uint8_t*)datastore1,BUF_SIZE,3000);
 HAL_UART_Transmit(&huart1,(uint8_t*)datastore2,BUF_SIZE,3000);
  HAL_UART_Transmit(&huart1,(uint8_t*)datastore3,BUF_SIZE,3000);
  indi_led = 0;
  HAL_UART_Transmit(&huart1,(uint8_t*)datastore4,BUF_SIZE,3000);
  // HAL_UART_Transmit(&huart1,(uint8_t*)datastore5,BUF_SIZE,3000);
  // HAL_UART_Transmit(&huart1,(uint8_t*)datastore6,BUF_SIZE,3000);
 HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, GPIO_PIN_RESET);	
 HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_RESET);
 indi_int = 0;
 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
 }
 }
}
 
// transfer data from adcValue to the varibles for each channel
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
	uint16_t tem_index=0;
	uint16_t data_num=0;
	for(tem_index=0;tem_index<BUF_SIZE/2;tem_index++)
	{
 //HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, GPIO_PIN_SET);
 data_num=tem_index*4; // 6 for 6-channel
 datastore1[tem_index]=adcValue[data_num];
 datastore2[tem_index]=adcValue[data_num+1];
 datastore3[tem_index]=adcValue[data_num+2];
 datastore4[tem_index]=adcValue[data_num+3];
 //datastore5[tem_index]=adcValue[data_num+4];
 //datastore6[tem_index]=adcValue[data_num+5];
	}
}
 
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	uint16_t tem_index=BUF_SIZE/2;
	uint16_t data_num=0;
	for(tem_index=BUF_SIZE/2;tem_index<BUF_SIZE;tem_index++)
	{
 data_num=tem_index*4; // 6 for 6-channel
 datastore1[tem_index]=adcValue[data_num];
 datastore2[tem_index]=adcValue[data_num+1];
 datastore3[tem_index]=adcValue[data_num+2];
 datastore4[tem_index]=adcValue[data_num+3];
 //datastore5[tem_index]=adcValue[data_num+4];
 //datastore6[tem_index]=adcValue[data_num+5];
 //HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); 
 HAL_ADC_Stop_DMA(&hadc1);
 indi_led = 1;
	}
}
 
/* ADC1 init function */
static void MX_ADC1_Init(void)
{
 ADC_MultiModeTypeDef multimode;
 ADC_ChannelConfTypeDef sConfig;
 
  /**Common config 
  */
 hadc1.Instance = ADC1;
 hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
 hadc1.Init.Resolution = ADC_RESOLUTION_8B;
 hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
 hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
 hadc1.Init.LowPowerAutoWait = DISABLE;
 hadc1.Init.ContinuousConvMode = ENABLE;
 hadc1.Init.NbrOfConversion = 4; // change to 6 for the 6-channel case
 hadc1.Init.DiscontinuousConvMode = DISABLE;
 hadc1.Init.NbrOfDiscConversion = 1;
 hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 hadc1.Init.DMAContinuousRequests = ENABLE;
 hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
 hadc1.Init.OversamplingMode = DISABLE;
 
 if (HAL_ADC_Init(&hadc1) != HAL_OK)
 {
  _Error_Handler(__FILE__, __LINE__);
 }
 
  /**Configure the ADC multi-mode 
  */
 multimode.Mode = ADC_MODE_INDEPENDENT;
 if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
 {
  _Error_Handler(__FILE__, __LINE__);
 }
 
  /**Configure Regular Channel 
  */
 sConfig.Channel = ADC_CHANNEL_1;
 sConfig.Rank = 1;
 sConfig.SamplingTime = ADC_SAMPLETIME_24CYCLES_5;
 sConfig.SingleDiff = ADC_SINGLE_ENDED;
 sConfig.OffsetNumber = ADC_OFFSET_NONE;
 sConfig.Offset = 0;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
  _Error_Handler(__FILE__, __LINE__);
 }
 
  /**Configure Regular Channel 
  */
 sConfig.Channel = ADC_CHANNEL_6;
 sConfig.Rank = 2;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
  _Error_Handler(__FILE__, __LINE__);
 }
 
  /**Configure Regular Channel 
  */
 sConfig.Channel = ADC_CHANNEL_7;
 sConfig.Rank = 3;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
  _Error_Handler(__FILE__, __LINE__);
 }
 
   /**Configure Regular Channel 
  */
 sConfig.Channel = ADC_CHANNEL_8;
 sConfig.Rank = 4;
 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 {
  _Error_Handler(__FILE__, __LINE__);
 }
 
  /**Configure Regular Channel 
  */
 //sConfig.Channel = ADC_CHANNEL_9;
 //sConfig.Rank = 5;
// if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
 //{
 // _Error_Handler(__FILE__, __LINE__);
 //}
 
  /**Configure Regular Channel 
  */
// sConfig.Channel = ADC_CHANNEL_10;
// sConfig.Rank = 6;
// if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
// {
 // _Error_Handler(__FILE__, __LINE__);
 //}
}

32 REPLIES 32
T J
Lead

I couldn't get it going for a day too...

then I used the timer to trigger the DMA,

works very well. and endlessly.

Just like in an OS,

You can just check the buffers anytime you like.

the DMA has freshly filled them...

Juras-RPM-Tech
Associate II

you have to check NbrOfConversion is == to the size of your adc conversion buffer, if buffer is smaller it will circulate the data.

You can confirm that with livewatch

Juras-RPM-Tech
Associate II

also check number of channels enabled is equal to the buffer size