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
Hailing SKY
Associate II

@Community member​ Yes, I am using CubeMX.

T J
Lead

I didn't see this line in my code, not sure why you need it:

 hadc1.Init.NbrOfConversion = 4; // change to 6 for the 6-channel case

T J
Lead

do you need to stop the DMA ?

I just leave it running

HAL_ADC_Stop_DMA(&hadc1);

Hailing SKY
Associate II

@Community member​  I am using the multi-channel scan mode. ADC1 is in charge of IN0 - IN4 for the 4-channel case. Therefore, it has 4 conversions for each scan.

T J
Lead

0-4 = 5 ?

Hailing SKY
Associate II

@Community member​  Sorry, I should say ranking 1 - 4. As you can see from the code, the ADC channels are ADC_CHANNEL_1, 6, 7, 8 in the 4-channel case.

Hailing SKY
Associate II

@Community member​ I stoped the DMA because the MCU has finished all the transfer before that command. It should be ok I think.

T J
Lead

Maybe you could change all references to '4' or '6' to an ENUM like I did above..

I calculate the ADC_ChannelCount  needed with ENUM
typedef enum {
    AD1,
    AD9,
    VTemp_Ad16,
    VRef_Ad17,
    //VBat_Ad18,              // not used on F042 
    ADC_ChannelCount,     //   <- here
} ADCresultsAveColumn_t;
 

Hailing SKY
Associate II

@Community member​ @Community member​ I eventally gave up using the DMA+SCAN mode. I used the basic Single Channel + Signal Coversion mode, and mannually scan all the 6 channels in a FOR loop. I have succeeded in doing so..

T J
Lead

:(