stm32stm32cubeidenucleocmsis

STM32L073RZ ADC Channel switching not working?


I have used three channels 6,7,8 to read data of 100 samples each. Hence I cannot use sequence continuous mode to read data. I have to switch the channel after reading 100 samples of one channel. For simplicity, I just reduced the sample to 1 and written the following code.

  MX_ADC_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */

  HAL_TIM_Base_Start(&htim2);

  select_adc_channel(6);
  HAL_ADC_Start_IT(&hadc);
  HAL_Delay(250);
  uint8_t adc=HAL_ADC_GetValue(&hadc);
  HAL_ADC_Stop_IT(&hadc);

  select_adc_channel(7);
  HAL_ADC_Start_IT(&hadc);
  HAL_Delay(250);
  adc=HAL_ADC_GetValue(&hadc);
  HAL_ADC_Stop_IT(&hadc);

  select_adc_channel(8);
  HAL_ADC_Start_IT(&hadc);
  HAL_Delay(250);
  adc=HAL_ADC_GetValue(&hadc);
  HAL_ADC_Stop_IT(&hadc);

MX_ADC_Init() code

static void MX_ADC_Init(void)
{

  /* USER CODE BEGIN ADC_Init 0 */

  /* USER CODE END ADC_Init 0 */

  ADC_ChannelConfTypeDef sConfig = {0};

  /* USER CODE BEGIN ADC_Init 1 */

  /* USER CODE END ADC_Init 1 */

  /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  */
  hadc.Instance = ADC1;
  hadc.Init.OversamplingMode = DISABLE;
  hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
  hadc.Init.Resolution = ADC_RESOLUTION_8B;
  hadc.Init.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
  hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
  hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc.Init.ContinuousConvMode = DISABLE;
  hadc.Init.DiscontinuousConvMode = DISABLE;
  hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
  hadc.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;
  hadc.Init.DMAContinuousRequests = DISABLE;
  hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc.Init.LowPowerAutoWait = DISABLE;
  hadc.Init.LowPowerFrequencyMode = DISABLE;
  hadc.Init.LowPowerAutoPowerOff = DISABLE;
  if (HAL_ADC_Init(&hadc) != HAL_OK)
  {
    Error_Handler();
  }
}

select_adc_channel() code

void select_adc_channel(uint8_t channel)
{
    ADC_ChannelConfTypeDef sConfig = {0};

    switch(channel)
    {
        case 0: sConfig.Channel = ADC_CHANNEL_0;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 6: sConfig.Channel = ADC_CHANNEL_6;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 7: sConfig.Channel = ADC_CHANNEL_7;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 8: sConfig.Channel = ADC_CHANNEL_8;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;
        case 9: sConfig.Channel = ADC_CHANNEL_9;
                sConfig.Rank = 1;
                if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
                {
                   Error_Handler();
                }
                break;

    }
}

As per the circuit, 6, 7, and 8th channels should read 78, 130, 190 adc values.But the above code, only gives 78 value for all 3 channels.

Then changed the reading order to 7, 6, and 8. so the reading become 130, 78, and 78.

what is happening after channel 6 is selected?


Solution

  • Whenever you switch ADC channels, you'll need to configure the 'old' channel to have ADC_RANK_NONE, otherwise it will still be considered a valid, enabled channel.

    Here's some code from a project I did which switched the ADC between two channels:

    static void configure_channel_as( uint32_t channel, uint32_t rank )
    {
        ADC_ChannelConfTypeDef sConfig = { 0 };
    
        sConfig.Channel      = channel;
        sConfig.Rank         = rank;
        sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
        if ( HAL_ADC_ConfigChannel ( &hadc, &sConfig ) != HAL_OK )
        {
            dprintf ( "Failed to configure channel 6\r\n" );
        }
    }
    
    void adc_configure_for_head( void )
    {
        configure_channel_as ( ADC_CHANNEL_0, ADC_RANK_CHANNEL_NUMBER );
        configure_channel_as ( ADC_CHANNEL_6, ADC_RANK_NONE );
    }
    
    void adc_configure_for_voltage( void )
    {
        configure_channel_as ( ADC_CHANNEL_6, ADC_RANK_CHANNEL_NUMBER );
        configure_channel_as ( ADC_CHANNEL_0, ADC_RANK_NONE );
    }
    

    You'll need to do something similar for the 'old' channel whenever you switch.