I have an STM32F411 Black Pill board, and I am trying to simulate a rotary encoder with this.
I want to generate two PWM signals, which are always 90 degrees out of phase, but have variable frequency. I tried the approach at How can I have Variable Frequency PWM with STM32? using two timers but this fails for some reason. The second channel (TIM2) ends up being a constant low.
I am able to get an output at constant frequency, but trying to change it doesn't work for the TIM2 channel.
Configuration
- System clock (HCLK): 100 MHz
- Both timers run at this frequency (APB1 and APB2)
TIM1
- Channel 1: PWM Generation CH1
- Channel 2: Output Compare No Output
- Prescaler: 999, AutoReload register: 999 (resulting in 100 Hz PWM)
- Output compare mode: Active Level on match
TIM2
- Slave mode: Trigger Mode
- Trigger source: ITR0
- Channel 1: PWM Generation CH1
- Prescaler: 999, AutoReload register: 999 (resulting in 100 Hz PWM)
Code main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
TIM1->ARR = 999;
TIM2->ARR = 999;
TIM1->CCR1 = 499;
TIM1->CCR2 = 249;
TIM2->CCR1 = 499;
HAL_GPIO_WritePin(LED_BUILTIN_GPIO_Port, LED_BUILTIN_Pin, GPIO_PIN_SET);
HAL_Delay(1000);
TIM1->ARR = 499;
TIM2->ARR = 499;
TIM1->CCR1 = 249;
TIM1->CCR2 = 124;
TIM2->CCR1 = 249;
HAL_GPIO_WritePin(LED_BUILTIN_GPIO_Port, LED_BUILTIN_Pin, GPIO_PIN_RESET);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
Expected screenshot
Logic analyzer screenshot
Blue is TIM1 CH1, orange is TIM2 CH1

EDIT 1: Narrowed down the issue
Just as a debugging step, I tried to just vary the phase shift by varying TIM1->CCR2. This doesn't work. The graph is at a constant phase difference as shown in the diagram below.
EDIT 1 Code main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_GPIO_WritePin(LED_BUILTIN_GPIO_Port, LED_BUILTIN_Pin, GPIO_PIN_SET);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
for (size_t i = 249; i < 999; i++)
{
TIM1->CCR2 = i;
HAL_Delay(10);
}
HAL_GPIO_WritePin(LED_BUILTIN_GPIO_Port, LED_BUILTIN_Pin, GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(LED_BUILTIN_GPIO_Port, LED_BUILTIN_Pin, GPIO_PIN_SET);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
EDIT 1 Graph from logic analyzer
Blue is TIM1 CH1, orange is TIM2 CH1
EDIT 2: Simon's method
Tried to change just the frequency of the PWM signals. This doesn't work.
EDIT 2 Code main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
HAL_TIM_OC_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_GPIO_WritePin(LED_BUILTIN_GPIO_Port, LED_BUILTIN_Pin, GPIO_PIN_SET);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
TIM1->ARR = 999;
TIM2->ARR = 999;
HAL_GPIO_TogglePin(LED_BUILTIN_GPIO_Port, LED_BUILTIN_Pin);
HAL_Delay(1000);
TIM1->ARR = 499;
TIM2->ARR = 499;
HAL_GPIO_TogglePin(LED_BUILTIN_GPIO_Port, LED_BUILTIN_Pin);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}



Firstly try without slave mode to trigger the second timer. The way to do so i like that:
Depending of generated frequency the delay that is the result of asynchronous start may or may not be crucial.
If it turns out that the delay of triggering timers is a thing just use the same trigger source to start generation to trigger both timers.