Skip to main content
Visitor II
July 9, 2024
Question

STM32G474, AN5306 , OPAMP Timer controlled multiplexer mode feature, gain problem with secondary channel.

  • July 9, 2024
  • 1 reply
  • 863 views

Hello, we intend to implement a time-dependent channel change via the operational amplifier in voltage follower mode, as described in AN5306 - Rev 1 Page 31, 5.1. However, when checking the output, there is an unwanted gain (x2) on channel 2. Any idea where it comes from or what could be set incorrectly?

 

Switching between channels using a timer and MUX works as expected, but the second channel has a gain of 2, although in voltage follower mode this should not be the case.

For testing, 1 volt was connected to both channels and it was expected that 1 volt would come out at the output, despite the change via the MUX, but it changes between 1 volt and 2 volts because the second channel has this unwanted gain.

 

CubeMX Configuration: OPA

Oleknistrator_0-1720534460340.png

Timer:

Oleknistrator_1-1720534519111.png

Pins:

Oleknistrator_2-1720534567366.png

 

code settings:

 

/**

* @brief System Clock Configuration

* @retval None

*/

void SystemClock_Config(void)

{

RCC_OscInitTypeDef RCC_OscInitStruct = {0};

RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};



/** Configure the main internal regulator output voltage

*/

HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);



/** Initializes the RCC Oscillators according to the specified parameters

* in the RCC_OscInitTypeDef structure.

*/

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 = RCC_PLLM_DIV4;

RCC_OscInitStruct.PLL.PLLN = 85;

RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;

RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;

RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;

if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

{

Error_Handler();

}



/** Initializes the CPU, AHB and APB buses 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_DIV1;

RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;



if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)

{

Error_Handler();

}

}



/**

* @brief OPAMP6 Initialization Function

* None

* @retval None

*/

static void MX_OPAMP6_Init(void)

{



/* USER CODE BEGIN OPAMP6_Init 0 */



/* USER CODE END OPAMP6_Init 0 */



/* USER CODE BEGIN OPAMP6_Init 1 */



/* USER CODE END OPAMP6_Init 1 */

hopamp6.Instance = OPAMP6;

hopamp6.Init.PowerMode = OPAMP_POWERMODE_NORMALSPEED;

hopamp6.Init.Mode = OPAMP_FOLLOWER_MODE;

hopamp6.Init.NonInvertingInput = OPAMP_NONINVERTINGINPUT_IO2;

hopamp6.Init.InternalOutput = DISABLE;

hopamp6.Init.TimerControlledMuxmode = OPAMP_TIMERCONTROLLEDMUXMODE_TIM8_CH6;

hopamp6.Init.NonInvertingInputSecondary = OPAMP_SEC_NONINVERTINGINPUT_IO0;

hopamp6.Init.UserTrimming = OPAMP_TRIMMING_FACTORY;

if (HAL_OPAMP_Init(&hopamp6) != HAL_OK)

{

Error_Handler();

}

/* USER CODE BEGIN OPAMP6_Init 2 */



/* USER CODE END OPAMP6_Init 2 */



}



/**

* @brief TIM8 Initialization Function

* None

* @retval None

*/

static void MX_TIM8_Init(void)

{



/* USER CODE BEGIN TIM8_Init 0 */



/* USER CODE END TIM8_Init 0 */



TIM_ClockConfigTypeDef sClockSourceConfig = {0};

TIM_MasterConfigTypeDef sMasterConfig = {0};

TIM_OC_InitTypeDef sConfigOC = {0};

TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};



/* USER CODE BEGIN TIM8_Init 1 */



/* USER CODE END TIM8_Init 1 */

htim8.Instance = TIM8;

htim8.Init.Prescaler = 16999;

htim8.Init.CounterMode = TIM_COUNTERMODE_UP;

htim8.Init.Period = 99;

htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

htim8.Init.RepetitionCounter = 0;

htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

if (HAL_TIM_Base_Init(&htim8) != HAL_OK)

{

Error_Handler();

}

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK)

{

Error_Handler();

}

if (HAL_TIM_OC_Init(&htim8) != HAL_OK)

{

Error_Handler();

}

sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;

sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)

{

Error_Handler();

}

sConfigOC.OCMode = TIM_OCMODE_TOGGLE;

sConfigOC.Pulse = 50;

sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;

sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;

if (HAL_TIM_OC_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_6) != HAL_OK)

{

Error_Handler();

}

sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;

sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;

sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;

sBreakDeadTimeConfig.DeadTime = 0;

sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;

sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;

sBreakDeadTimeConfig.BreakFilter = 0;

sBreakDeadTimeConfig.BreakAFMode = TIM_BREAK_AFMODE_INPUT;

sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE;

sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH;

sBreakDeadTimeConfig.Break2Filter = 0;

sBreakDeadTimeConfig.Break2AFMode = TIM_BREAK_AFMODE_INPUT;

sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;

if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)

{

Error_Handler();

}

/* USER CODE BEGIN TIM8_Init 2 */



/* USER CODE END TIM8_Init 2 */



}

 

 

main.c 

 

...

HAL_TIM_OC_Start(&htim8, TIM_CHANNEL_6);

HAL_OPAMP_Start(&hopamp6);

while(1)

 

 

 

 

 

 

 

 

 

    This topic has been closed for replies.

    1 reply

    Visitor II
    January 2, 2026

    Hi,

    In my case, it seems to be a library or CubeMX issue. CubeMX appears to not generate the required code for the secondary input, so the VMS_SEL bit in the OPAMPx_TCMR register is never set to 1. As a result, the OPAMP remains stuck in PGA mode, and with PGA_GAIN = 00000, the effective gain is 2.

    According to the reference manual:

    Bit 0 – VMS_SEL: OPAMP1 inverting input secondary selection

    This bit is set and cleared by software. It is used to select the OPAMPx inverting input when the controlled mux mode is enabled (T1CM_EN = 1 or T8CM_EN = 1 or T20CM_EN = 1).

    When standalone mode is used (VM_SEL = "00" or "01"):
    0: Input from VINM0
    1: Input from VINM1

    When PGA (VM_SEL = "10") or Follower mode (VM_SEL = "11") is used:
    0: Resistor feedback output selected (PGA mode)
    1: VOUT selected as input minus (Follower mode)

    So, the simple solution to make the secondary input work in follower mode is to explicitly set VMS_SEL to 1:

    OPAMP1->TCMR |= OPAMP_TCMR_VMSSEL;

    Hopefully, ST will fix this issue in future versions of the OPAMP libraries and CubeMX code generation.