Skip to main content
Visitor II
May 30, 2025
Question

Square wave FSK issue using PWM ouput

  • May 30, 2025
  • 1 reply
  • 404 views

Hi All,

I am trying to impliment a frequency shift keying (FSK) routine to represent a each bit of a byte as FSK.

My routine is kind of working (see the IRQ for TIM3 below). My FSK is :

Bit 0 & Start : 3600Hz 

Bit 1 & Stop : 1200Hz

This ensures that timing is alway 833.3us, and transisitons only occur at the end of a full cycle (avoiding glitches).

In this example pictured I am sending a 'U' to be encoded (this has a binary value of '0b01010101') so its easy to see the FSK changes.

What I've noticed is that when I change from bit from 0 (3600Hz) to 1 (1200Hz) the output polarity keeps the previous polarity level. This makes it look like last pulse of the 3600Hz waveform is streatched.Screenshot 2025-05-30 124318.jpg

My question is, How can I change the polarity of the PWM ouput on each sucessive bit?

Here is my IRQ code:

 

extern volatile uint8_t transmitting;
extern volatile uint8_t transmit_data;
extern volatile uint8_t bit_count;
extern volatile uint8_t bit_index;
extern volatile uint8_t current_bit;
extern volatile uint8_t Finished_TX; //MD


// Working FSK with Start/Stop bits - To be tested
void TIM3_IRQHandler(void) {
 if (__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_UPDATE) != RESET) {
 __HAL_TIM_CLEAR_IT(&htim3, TIM_IT_UPDATE); // Ensure interrupt flag is cleared
 HAL_TIM_IRQHandler(&htim3); // Keep HAL processing

 if (transmitting)
 {
 	//Toggle pin D07
 	HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_7);

 bit_count--; // Reduce cycle count

 if (bit_count == 0)
 { // Time to switch to next bit
 if (bit_index == -1)
 { // Start bit (Before data transmission)
 bit_count = 3; // 3 cycles @ 3600Hz
 ///bit_count = 4; // 3 cycles @ 3600Hz
 htim3.Instance->ARR = (48000000 / 3600) - 1;
 htim3.Instance->CCR1 = (htim3.Instance->ARR * 50) / 100;
 //htim3.Instance->CCR1 = (htim3.Instance->ARR * 57) / 100;

 bit_index++; // Move to first data bit
 }
 else if (bit_index < 8)
 { // Process next bit in character
 current_bit = (transmit_data >> bit_index) & 0x01;
 bit_count = current_bit ? 1 : 3; // '1' → 1200Hz (1 cycle), '0' → 3600Hz (3 cycles)
 ///bit_count = current_bit ? 1 : 4; // '1' → 1200Hz (1 cycle), '0' → 3600Hz (3 cycles)




 htim3.Instance->ARR = current_bit ? (48000000 / 1200) - 1 : (48000000 / 3600) - 1;
 htim3.Instance->CCR1 = (htim3.Instance->ARR * 50) / 100;
 //htim3.Instance->CCR1 = (htim3.Instance->ARR * 57) / 100;

 bit_index++; // Move to next bit
 }
 else
 { // Stop bit handling after last data bit
 bit_count = 1;
 htim3.Instance->ARR = (48000000 / 1200) - 1; // Stop bit at 1200Hz
 htim3.Instance->CCR1 = (htim3.Instance->ARR * 50) / 100;
 //htim3.Instance->CCR1 = (htim3.Instance->ARR * 57) / 100;

 transmitting = 0; // Ensure transmission reset
 bit_index = -1; // Prepare for next transmission
 Finished_TX = 1;

 printf("Transmission complete!\n");

 // Force timer update to ensure it stays at 1200Hz idle
 __HAL_TIM_SET_AUTORELOAD(&htim3, htim3.Instance->ARR);
 __HAL_TIM_ENABLE_IT(&htim3, TIM_IT_UPDATE);
 }
 }
 }

 // Ensure TIM3 interrupts remain enabled
 __HAL_TIM_ENABLE_IT(&htim3, TIM_IT_UPDATE);
 }
}
    This topic has been closed for replies.

    1 reply

    ST Employee
    May 30, 2025

    Hello @mikeyd0407

    This behavior is likely due to that the timer's output compare does not reset its phase or polarity when the frequency (ARR value) is updated, try forcing the timer to reset its counter by adding this line in your IRQ handler:

    htim3.Instance->ARR = current_bit ? (48000000 / 1200) - 1 : (48000000 / 3600) - 1;
    htim3.Instance->CCR1 = (htim3.Instance->ARR * 50) / 100;
    htim3.Instance->CNT = 0; // Reset the timer counter to zero

    Hope that helps! 

    Visitor II
    June 2, 2025

    Hi Sarra.S,

     

    I tried your suggestion, but unfortunately it doesn't eem to change the polarity. Any other ideas?

     

    Kind regards

     

    Michael