cancel
Showing results for 
Search instead for 
Did you mean: 

Change Pin mode from analog to digital in run time. See my code below..

NMait.1
Associate II

I want to use pin to work as output pin for some time and then Analog pin for some time.

how can I change the mode of pin in run time.

	GPIO_InitTypeDef GPIO_InitStruct = {0};
	ADC_ChannelConfTypeDef sConfig = {0};
 
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
 
	GPIO_InitStruct.Pin = GPIO_PIN_0;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
	GPIO_InitStruct.Pin = GPIO_PIN_3;
	GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /** 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_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  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_3;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

8 REPLIES 8
Uwe Bonnes
Principal II

If you use HAL, carefully check the HAL code for side effects. I do so by directly manipulating the GPIO registers.

NMait.1
Associate II

Can you please give me example code ?

I want to use same 2 pins as digital for time and analog for some time.

I used following command for mode configuration, and kept the rest same -

GPIOC->MODER |= 0x01;

NMait.1
Associate II

Which registers I need to modify to convert pin from analog to digital and digital to analog ?

Which STM32?

GPIO_MODER, as you've done.

There are two bits per pin, Out is 0b01 and Analog is 0b11. So, switching from Out to Analog is

GPIOC->MODER |= 0x02;

and back to Out

GPIOC->MODER &= ~0x02;

JW

NMait.1
Associate II

I am using STM32F746BG.

I made following changes in code for conversion, and kept the ADC function same.

Still I am not getting required output.

To make PC0 Digital -

GPIOC->MODER &= ~((1<<0) | (1<<1));

GPIOC->MODER |= (1<<0);

GPIOC->OTYPER &= ~(1<<0);

GPIOC->OSPEEDR &= ~((1<<0) | (1<<1));

GPIOC->PUPDR |= (1<<0);

To make PB3 Analog-

GPIOA->MODER |= ((1<<7) | (1<<6));

GPIOA->OTYPER &= ~(1<<3);

GPIOA->PUPDR &= ~((1<<7) | (1<<6));

To make PB3 Digital-

GPIOA->MODER &= ~((1<<6) | (1<<7));

GPIOA->MODER |= (1<<6);

GPIOA->OTYPER &= ~(1<<3);

GPIOA->OSPEEDR &= ~((1<<6) | (1<<7));

GPIOA->PUPDR |= (1<<3);

To make PC0 Analog-

GPIOC->MODER |= ((1<<1) | (1<<0));

GPIOC->OTYPER &= ~(1<<0);

GPIOC->PUPDR &= ~((1<<1) | (1<<0));

OTYPER and OSPEEDR will be ignored during Analog mode, so you don't need to change them.

PUPDR has two bits, so

GPIOA->PUPDR |= (1<<3);

is incorrect for PA3.

You say To make PB3 Analog- but you then access GPIOA registers.

At the end of the day, if something does not work as expected, read out the relevant registers content and check if they are set as expected.

JW

NMait.1
Associate II
void GET_X(void)
{
	uint16_t AD_RES = 10;
	ADC_ChannelConfTypeDef sConfig = {0};
 
	GPIOB->MODER &= ~((1<<0) | (1<<1));
	GPIOB->MODER |= (1<<0);
	GPIOB->OTYPER &= ~(1<<0);
	GPIOB->OSPEEDR &= ~((1<<0) | (1<<1));
	GPIOB->PUPDR &= ~ (1<<0);
	GPIOB->ODR |= 1<<0;
 
	GPIOA->MODER |= ((1<<7) | (1<<6));
	GPIOA->OTYPER &= ~(1<<3);
	GPIOA->PUPDR &= ~((1<<7) | (1<<6));
 
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
	 HAL_ADC_Start(&hadc1);
	 HAL_ADC_PollForConversion(&hadc1, 1);
	 AD_RES = HAL_ADC_GetValue(&hadc1);
	 HAL_ADC_Stop(&hadc1);
}
 
 
void GET_Y(void)
{
	uint16_t AD_RES = 20;
	ADC_ChannelConfTypeDef sConfig = {0};
 
	GPIOA->MODER &= ~((1<<6) | (1<<7));
	GPIOA->MODER |= (1<<6);
	GPIOA->OTYPER &= ~(1<<3);
	GPIOA->OSPEEDR &= ~((1<<6) | (1<<7));
	GPIOA->PUPDR |= (1<<3);
	GPIOA->ODR |= (1<<3);
 
	GPIOB->MODER |= ((1<<1) | (1<<0));
	GPIOB->OTYPER &= ~(1<<0);
	GPIOB->PUPDR &= ~((1<<1) | (1<<0));
  
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  sConfig.Channel = ADC_CHANNEL_8;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
	 HAL_ADC_Start(&hadc1);
	 HAL_ADC_PollForConversion(&hadc1, 1);
	 AD_RES = HAL_ADC_GetValue(&hadc1);
	 HAL_ADC_Stop(&hadc1);
}
 
void GET_XY(void)
{
	GET_X();
	  osDelay(500);
	GET_Y();
	  osDelay(500);
}

I tried with above code.

I m not able to get second analog channel value.

NMait.1
Associate II

By reading the values on ADC2 i am able to get both ADC values.

But the readings are not stable, however the input is stable.

How can i get stable readings ?