Strange modulation on teensy 4.1

I'm working with a teensy 4.1 and will operate a led module that has a maximum input of pwm frequency at 1khz, And need to modulate a square wave at 110 hz, The problem im facing is that the led fluctualte with a 1 second pulse. A little bit up and down. Its not stable, before i get up to 2khz(Testing with a regular Led). When using a arduino uno where i use interrupt to set hardware interrupt i get stable, and wonder if its possible to achiive the same kind of thing, and also if somebody can explain why this is happening. I will share the code below. Its a test program that you can set vakues in the serial monitor live.
Hope somebody has a good answer to this. I've also tried using the micros function and that works even worse.
Thanks
Best regards
Finn Andre Hotvedt

#include <Arduino.h>
#include <IntervalTimer.h>
// ----- Global Parameters (set via Serial commands) -----
const int pwmPin = 2; // PWM output pin (adjust as needed)
float pwmFreq = 1000; // Default PWM frequency in Hz
int dutyPercent = 50; // Default duty cycle (0–100%)
float modFreq = 111; // Default modulation frequency in Hz (0 = no modulation)
int amplitude = 100; // Default amplitude (0–100%)
// Derived variables (calculated from duty and amplitude)
// These are used by the timer interrupt to update the output.
volatile int pwmValue = 0;
volatile bool modState = false; // toggles in the interrupt
IntervalTimer modTimer; // Timer used for modulation updates
// This function is called by the timer interrupt.
void updatePwmOutput() {
// Toggle the modulation state
modState = !modState;
if (modFreq > 0) {
// During the "high" phase output the PWM value; else, off.
analogWrite(pwmPin, modState ? pwmValue : 0);
} else {
// No modulation: always output the PWM value.
analogWrite(pwmPin, pwmValue);
}
}
// (Re)start the modulation timer with a period based on modFreq.
// If modFreq == 0, the timer is stopped.
void updateModTimer() {
// Stop any running timer
modTimer.end();
if (modFreq > 0) {
// Calculate half period (in microseconds) for a square wave modulation.
unsigned long halfPeriod = 1000000UL / (2 * modFreq);
modTimer.begin(updatePwmOutput, halfPeriod);
} else {
// With no modulation, ensure the output remains constant.
analogWrite(pwmPin, pwmValue);
}
}
// Recalculate the PWM output value from dutyPercent and amplitude.
void updatePwmValue() {
int raw = (dutyPercent * 4095) / 100; // 12-bit PWM value based on duty
pwmValue = (raw * amplitude) / 100; // Scale by amplitude percentage
}
void setup() {
Serial.begin(115200);
while (!Serial) ; // Wait for serial monitor

pinMode(pwmPin, OUTPUT);
// Set the PWM frequency on pwmPin.
analogWriteFrequency(pwmPin, pwmFreq);
updatePwmValue();

// Start the modulation timer if modulation is enabled.
updateModTimer();

Serial.println(F("Enter commands in one of these formats:"));
Serial.println(F(" PWM <pwmFreq> <dutyPercent> <modFreq> <amp>"));
Serial.println(F(" e.g., PWM 900 50 111 80"));
Serial.println(F(" DUTY <dutyPercent>"));
Serial.println(F(" e.g., DUTY 80"));
Serial.println(F(" AMP <amp>"));
Serial.println(F(" e.g., AMP 90"));
Serial.println();
}
void loop() {
// Check for Serial input and parse commands.
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim();

if (command.startsWith("PWM")) {
int firstSpace = command.indexOf(' ');
if (firstSpace > 0) {
String params = command.substring(firstSpace + 1);
params.trim();
int space1 = params.indexOf(' ');
int space2 = params.indexOf(' ', space1 + 1);
int space3 = params.indexOf(' ', space2 + 1);
if (space1 > 0 && space2 > 0 && space3 > 0) {
String freqStr = params.substring(0, space1);
String dutyStr = params.substring(space1 + 1, space2);
String modStr = params.substring(space2 + 1, space3);
String ampStr = params.substring(space3 + 1);

float newPwmFreq = freqStr.toFloat();
int newDuty = dutyStr.toInt();
float newModFreq = modStr.toFloat();
int newAmp = ampStr.toInt();

if (newPwmFreq > 0 && newDuty >= 0 && newDuty <= 100 &&
newModFreq >= 0 && newAmp >= 0 && newAmp <= 100) {
pwmFreq = newPwmFreq;
dutyPercent = newDuty;
modFreq = newModFreq;
amplitude = newAmp;
// Update PWM frequency.
analogWriteFrequency(pwmPin, pwmFreq);
updatePwmValue();
updateModTimer();

Serial.print(F("Updated: PWM Freq = "));
Serial.print(pwmFreq);
Serial.print(F(" Hz, Duty = "));
Serial.print(dutyPercent);
Serial.print(F("%, Mod Freq = "));
Serial.print(modFreq);
Serial.print(F(" Hz, Amp = "));
Serial.print(amplitude);
Serial.println(F("%"));
} else {
Serial.println(F("Invalid parameters. Check: pwmFreq > 0, duty & amp 0-100, modFreq >= 0."));
}
} else {
Serial.println(F("Invalid format. Use: PWM <pwmFreq> <dutyPercent> <modFreq> <amp>"));
}
}
}
else if (command.startsWith("DUTY")) {
int firstSpace = command.indexOf(' ');
if (firstSpace > 0) {
String dutyStr = command.substring(firstSpace + 1);
dutyStr.trim();
int newDuty = dutyStr.toInt();
if (newDuty >= 0 && newDuty <= 100) {
dutyPercent = newDuty;
updatePwmValue();
Serial.print(F("Updated Duty: "));
Serial.print(dutyPercent);
Serial.println(F("%"));
} else {
Serial.println(F("Invalid duty cycle. Must be 0-100."));
}
}
}
else if (command.startsWith("AMP")) {
int firstSpace = command.indexOf(' ');
if (firstSpace > 0) {
String ampStr = command.substring(firstSpace + 1);
ampStr.trim();
int newAmp = ampStr.toInt();
if (newAmp >= 0 && newAmp <= 100) {
amplitude = newAmp;
updatePwmValue();
Serial.print(F("Updated Amplitude: "));
Serial.print(amplitude);
Serial.println(F("%"));
} else {
Serial.println(F("Invalid amplitude. Must be 0-100."));
}
}
}
}
}
 
When you post code on this forum can you please use the </> button.
Doing so maintains the code formatting and makes it easier for others to understand your code and be able to better help you.
Below is the code.

Code:
#include <Arduino.h>
#include <IntervalTimer.h>
// ----- Global Parameters (set via Serial commands) -----
const int pwmPin = 2; // PWM output pin (adjust as needed)
float pwmFreq = 1000; // Default PWM frequency in Hz
int dutyPercent = 50; // Default duty cycle (0–100%)
float modFreq = 111; // Default modulation frequency in Hz (0 = no modulation)
int amplitude = 100; // Default amplitude (0–100%)
// Derived variables (calculated from duty and amplitude)
// These are used by the timer interrupt to update the output.
volatile int pwmValue = 0;
volatile bool modState = false; // toggles in the interrupt
IntervalTimer modTimer; // Timer used for modulation updates
// This function is called by the timer interrupt.
void updatePwmOutput() {
    // Toggle the modulation state
    modState = !modState;
    if (modFreq > 0) {
        // During the "high" phase output the PWM value; else, off.
        analogWrite(pwmPin, modState ? pwmValue : 0);
    }
    else {
        // No modulation: always output the PWM value.
        analogWrite(pwmPin, pwmValue);
    }
}
// (Re)start the modulation timer with a period based on modFreq.
// If modFreq == 0, the timer is stopped.
void updateModTimer() {
    // Stop any running timer
    modTimer.end();
    if (modFreq > 0) {
        // Calculate half period (in microseconds) for a square wave modulation.
        unsigned long halfPeriod = 1000000UL / (2 * modFreq);
        modTimer.begin(updatePwmOutput, halfPeriod);
    }
    else {
        // With no modulation, ensure the output remains constant.
        analogWrite(pwmPin, pwmValue);
    }
}
// Recalculate the PWM output value from dutyPercent and amplitude.
void updatePwmValue() {
    int raw = (dutyPercent * 4095) / 100; // 12-bit PWM value based on duty
    pwmValue = (raw * amplitude) / 100; // Scale by amplitude percentage
}
void setup() {
    Serial.begin(115200);
    while (!Serial); // Wait for serial monitor

    pinMode(pwmPin, OUTPUT);
    // Set the PWM frequency on pwmPin.
    analogWriteFrequency(pwmPin, pwmFreq);
    updatePwmValue();

    // Start the modulation timer if modulation is enabled.
    updateModTimer();

    Serial.println(F("Enter commands in one of these formats:"));
    Serial.println(F(" PWM <pwmFreq> <dutyPercent> <modFreq> <amp>"));
    Serial.println(F(" e.g., PWM 900 50 111 80"));
    Serial.println(F(" DUTY <dutyPercent>"));
    Serial.println(F(" e.g., DUTY 80"));
    Serial.println(F(" AMP <amp>"));
    Serial.println(F(" e.g., AMP 90"));
    Serial.println();
}
void loop() {
    // Check for Serial input and parse commands.
    if (Serial.available()) {
        String command = Serial.readStringUntil('\n');
        command.trim();

        if (command.startsWith("PWM")) {
            int firstSpace = command.indexOf(' ');
            if (firstSpace > 0) {
                String params = command.substring(firstSpace + 1);
                params.trim();
                int space1 = params.indexOf(' ');
                int space2 = params.indexOf(' ', space1 + 1);
                int space3 = params.indexOf(' ', space2 + 1);
                if (space1 > 0 && space2 > 0 && space3 > 0) {
                    String freqStr = params.substring(0, space1);
                    String dutyStr = params.substring(space1 + 1, space2);
                    String modStr = params.substring(space2 + 1, space3);
                    String ampStr = params.substring(space3 + 1);

                    float newPwmFreq = freqStr.toFloat();
                    int newDuty = dutyStr.toInt();
                    float newModFreq = modStr.toFloat();
                    int newAmp = ampStr.toInt();

                    if (newPwmFreq > 0 && newDuty >= 0 && newDuty <= 100 &&
                        newModFreq >= 0 && newAmp >= 0 && newAmp <= 100) {
                        pwmFreq = newPwmFreq;
                        dutyPercent = newDuty;
                        modFreq = newModFreq;
                        amplitude = newAmp;
                        // Update PWM frequency.
                        analogWriteFrequency(pwmPin, pwmFreq);
                        updatePwmValue();
                        updateModTimer();

                        Serial.print(F("Updated: PWM Freq = "));
                        Serial.print(pwmFreq);
                        Serial.print(F(" Hz, Duty = "));
                        Serial.print(dutyPercent);
                        Serial.print(F("%, Mod Freq = "));
                        Serial.print(modFreq);
                        Serial.print(F(" Hz, Amp = "));
                        Serial.print(amplitude);
                        Serial.println(F("%"));
                    }
                    else {
                        Serial.println(F("Invalid parameters. Check: pwmFreq > 0, duty & amp 0-100, modFreq >= 0."));
                    }
                }
                else {
                    Serial.println(F("Invalid format. Use: PWM <pwmFreq> <dutyPercent> <modFreq> <amp>"));
                }
            }
        }
        else if (command.startsWith("DUTY")) {
            int firstSpace = command.indexOf(' ');
            if (firstSpace > 0) {
                String dutyStr = command.substring(firstSpace + 1);
                dutyStr.trim();
                int newDuty = dutyStr.toInt();
                if (newDuty >= 0 && newDuty <= 100) {
                    dutyPercent = newDuty;
                    updatePwmValue();
                    Serial.print(F("Updated Duty: "));
                    Serial.print(dutyPercent);
                    Serial.println(F("%"));
                }
                else {
                    Serial.println(F("Invalid duty cycle. Must be 0-100."));
                }
            }
        }
        else if (command.startsWith("AMP")) {
            int firstSpace = command.indexOf(' ');
            if (firstSpace > 0) {
                String ampStr = command.substring(firstSpace + 1);
                ampStr.trim();
                int newAmp = ampStr.toInt();
                if (newAmp >= 0 && newAmp <= 100) {
                    amplitude = newAmp;
                    updatePwmValue();
                    Serial.print(F("Updated Amplitude: "));
                    Serial.print(amplitude);
                    Serial.println(F("%"));
                }
                else {
                    Serial.println(F("Invalid amplitude. Must be 0-100."));
                }
            }
        }
    }
}
 
To short down the issue I can say that it can NOT perform smooth
Square wave 110 Hz
Pwm frequency 1000hz
Duty cycle 50 %
Amplitude 100 %

Very unstable until you reach pwm frequency of 2000hz
 
You are seeing beating between the 110Hz and 1000Hz frequencies I suspect. Perhaps reset the PWM counter everytime the modulation waveform turns on? Not sure if there is a way to do this from library calls though.
 
Hi, Thanks for answer MarkT
Ive tried adding that to the program but no luck there either.
Its very strange that the led changes the "call it amplitude" so steady, like a 1 second pulse switching from 80% to 100% and then to 80. Very very stabile up and dowm.


Code:
#include <Arduino.h>
#include <IntervalTimer.h>
#include "imxrt.h"  // For accessing FlexPWM registers

// ----- Global Parameters (set via Serial commands) -----
const int pwmPin = 2;              // PWM output pin (must be routed to FlexPWM1.SM[0])
float pwmFreq = 1000;              // Default PWM frequency in Hz
int dutyPercent = 50;              // Default duty cycle (0–100%)
float modFreq = 111;               // Default modulation frequency in Hz (0 = no modulation)
int amplitude = 100;               // Default amplitude (0–100%)

// Derived PWM value (0–4095) computed from duty and amplitude
volatile int pwmValue = 0;
// This flag toggles every modulation half period.
volatile bool modState = false;

IntervalTimer modTimer;            // Timer used for modulation updates

// This interrupt function is called every half modulation period.
// It resets the PWM counter to re-sync the PWM cycle with the modulation and toggles the output.
void updatePwmOutput() {
  // Reset the PWM counter for FlexPWM1 submodule 0.
  // This forces the PWM cycle to restart from 0.
  IMXRT_FLEXPWM1.SM[0].CNT = 0;
 
  // Toggle the modulation state.
  modState = !modState;
  if (modFreq > 0) {
    // During the "high" phase, output the computed PWM value; during the "low" phase, output 0.
    analogWrite(pwmPin, modState ? pwmValue : 0);
  } else {
    // If modulation is disabled, always output the computed PWM value.
    analogWrite(pwmPin, pwmValue);
  }
}

// (Re)start the modulation timer with a period based on modFreq.
// If modFreq == 0, the timer is stopped.
void updateModTimer() {
  modTimer.end();
  if (modFreq > 0) {
    // Calculate half period in microseconds for a square wave modulation.
    unsigned long halfPeriod = 1000000UL / (2 * modFreq);
    modTimer.begin(updatePwmOutput, halfPeriod);
  } else {
    // With no modulation, ensure the output remains constant.
    analogWrite(pwmPin, pwmValue);
  }
}

// Recalculate the PWM output value from dutyPercent and amplitude.
void updatePwmValue() {
  int raw = (dutyPercent * 4095) / 100;  // 12-bit PWM value based on duty cycle
  pwmValue = (raw * amplitude) / 100;      // Scale by amplitude percentage
}

void setup() {
  Serial.begin(115200);
  while (!Serial) ;  // Wait for Serial Monitor

  pinMode(pwmPin, OUTPUT);
  // Set the PWM frequency on pwmPin.
  analogWriteFrequency(pwmPin, pwmFreq);
  updatePwmValue();
  updateModTimer();
 
  Serial.println(F("PWM with Counter Reset Demo"));
  Serial.println(F("Enter commands in one of these formats:"));
  Serial.println(F("  PWM <pwmFreq> <dutyPercent> <modFreq> <amp>"));
  Serial.println(F("     e.g., PWM 900 50 111 80"));
  Serial.println(F("  DUTY <dutyPercent>"));
  Serial.println(F("     e.g., DUTY 80"));
  Serial.println(F("  AMP <amp>"));
  Serial.println(F("     e.g., AMP 90"));
  Serial.println();
}

void loop() {
  // ----- Check for Serial Input and Parse Commands -----
  if (Serial.available()) {
    String command = Serial.readStringUntil('\n');
    command.trim();
    
    if (command.startsWith("PWM")) {
      int firstSpace = command.indexOf(' ');
      if (firstSpace > 0) {
        String params = command.substring(firstSpace + 1);
        params.trim();
        int space1 = params.indexOf(' ');
        int space2 = params.indexOf(' ', space1 + 1);
        int space3 = params.indexOf(' ', space2 + 1);
        if (space1 > 0 && space2 > 0 && space3 > 0) {
          String freqStr = params.substring(0, space1);
          String dutyStr = params.substring(space1 + 1, space2);
          String modStr  = params.substring(space2 + 1, space3);
          String ampStr  = params.substring(space3 + 1);
          
          float newPwmFreq = freqStr.toFloat();
          int newDuty = dutyStr.toInt();
          float newModFreq = modStr.toFloat();
          int newAmp = ampStr.toInt();
          
          if (newPwmFreq > 0 && newDuty >= 0 && newDuty <= 100 &&
              newModFreq >= 0 && newAmp >= 0 && newAmp <= 100) {
            pwmFreq = newPwmFreq;
            dutyPercent = newDuty;
            modFreq = newModFreq;
            amplitude = newAmp;
            // Update the PWM frequency.
            analogWriteFrequency(pwmPin, pwmFreq);
            updatePwmValue();
            updateModTimer();
            
            Serial.print(F("Updated: PWM Freq = "));
            Serial.print(pwmFreq);
            Serial.print(F(" Hz, Duty = "));
            Serial.print(dutyPercent);
            Serial.print(F("%, Mod Freq = "));
            Serial.print(modFreq);
            Serial.print(F(" Hz, Amp = "));
            Serial.print(amplitude);
            Serial.println(F("%"));
          } else {
            Serial.println(F("Invalid parameters. Check: pwmFreq > 0, duty & amp 0-100, modFreq >= 0."));
          }
        } else {
          Serial.println(F("Invalid format. Use: PWM <pwmFreq> <dutyPercent> <modFreq> <amp>"));
        }
      }
    }
    else if (command.startsWith("DUTY")) {
      int firstSpace = command.indexOf(' ');
      if (firstSpace > 0) {
        String dutyStr = command.substring(firstSpace + 1);
        dutyStr.trim();
        int newDuty = dutyStr.toInt();
        if (newDuty >= 0 && newDuty <= 100) {
          dutyPercent = newDuty;
          updatePwmValue();
          Serial.print(F("Updated Duty: "));
          Serial.print(dutyPercent);
          Serial.println(F("%"));
        } else {
          Serial.println(F("Invalid duty cycle. Must be 0-100."));
        }
      }
    }
    else if (command.startsWith("AMP")) {
      int firstSpace = command.indexOf(' ');
      if (firstSpace > 0) {
        String ampStr = command.substring(firstSpace + 1);
        ampStr.trim();
        int newAmp = ampStr.toInt();
        if (newAmp >= 0 && newAmp <= 100) {
          amplitude = newAmp;
          updatePwmValue();
          Serial.print(F("Updated Amplitude: "));
          Serial.print(amplitude);
          Serial.println(F("%"));
        } else {
          Serial.println(F("Invalid amplitude. Must be 0-100."));
        }
      }
    }
  }
}
 
I haven't tried to run your code, just reviewed it. In your calculation of pwmValue, you assume 12-bit PWM. The default is 8-bit (0-255), so you should add the line below to setup().

Code:
analogWriteResolution(12);  // analogWrite value 0 to 4095, or 4096 for high

These are excerpts from your code. With the values shown, pwmValue = 2048, so that's as if you are writing 0 unless you change Resolution to 12 bits.

Code:
// Recalculate the PWM output value from dutyPercent and amplitude.
float pwmFreq = 1000;              // Default PWM frequency in Hz
int dutyPercent = 50;              // Default duty cycle (0–100%)
float modFreq = 111;               // Default modulation frequency in Hz (0 = no modulation)
int amplitude = 100;               // Default amplitude (0–100%)

void updatePwmValue() {
  int raw = (dutyPercent * 4095) / 100;  // 12-bit PWM value based on duty cycle
  pwmValue = (raw * amplitude) / 100;      // Scale by amplitude percentage
}

// During the "high" phase, output the computed PWM value; during the "low" phase, output 0.
analogWrite(pwmPin, modState ? pwmValue : 0);
 
Thanks for tip, but unfortunately its just the same. shared below with the resolution writing.
It almost that we can conclude that teensy can not be used with pwm frequency below 2000hz. This only for squarewave or saw. Sine is working fine.
even at 50hz of modulaton you see unstability. but when raising the pwm frequncy from 1khz to 2khz, you see see all kind of small flickering dissapeared.
If running sine wave its stabile but square and saw wave we have this issue.

Code:
#include <Arduino.h>
#include <IntervalTimer.h>
#include "imxrt.h"  // For accessing FlexPWM registers on Teensy 4.1

// ----- Global Parameters (adjustable via Serial commands) -----
const int pwmPin = 2;              // PWM output pin (must be routed to FlexPWM1.SM[0])
float pwmFreq = 1000;              // Default PWM frequency in Hz
int dutyPercent = 50;              // Default duty cycle (0–100%)
float modFreq = 111;               // Default modulation frequency in Hz (0 = no modulation)
int amplitude = 100;               // Default amplitude (0–100%)

// Derived PWM value (0–4095) computed from duty and amplitude.
volatile int pwmValue = 0;
// This flag toggles every half modulation period.
volatile bool modState = false;

IntervalTimer modTimer;            // Timer used for modulation updates

//---------------------------------------------------------------------
// updatePwmOutput() is called by the timer interrupt at every half-
 // modulation period. It resets the PWM counter (to re-sync the PWM
 // cycle with the modulation) and then toggles the output.
//---------------------------------------------------------------------
void updatePwmOutput() {
  // Reset the PWM counter for FlexPWM1 submodule 0.
  // This forces the PWM cycle to restart from 0.
  IMXRT_FLEXPWM1.SM[0].CNT = 0;
 
  // Toggle modulation state.
  modState = !modState;
 
  // If modulation is enabled, output the PWM value during the "high"
  // phase and 0 during the "low" phase. Otherwise, output the PWM value.
  if (modFreq > 0) {
    analogWrite(pwmPin, modState ? pwmValue : 0);
  } else {
    analogWrite(pwmPin, pwmValue);
  }
}

//---------------------------------------------------------------------
// updateModTimer() stops any running timer and, if modulation is
// enabled (modFreq > 0), starts the timer to call updatePwmOutput()
// every half modulation period (in microseconds).
//---------------------------------------------------------------------
void updateModTimer() {
  modTimer.end();  // Stop any running timer
  if (modFreq > 0) {
    unsigned long halfPeriod = 1000000UL / (2 * modFreq);
    modTimer.begin(updatePwmOutput, halfPeriod);
  } else {
    // With no modulation, ensure the output remains constant.
    analogWrite(pwmPin, pwmValue);
  }
}

//---------------------------------------------------------------------
// updatePwmValue() recalculates the PWM output value from dutyPercent
// and amplitude. (For 12-bit resolution, the full scale is 4095.)
//---------------------------------------------------------------------
void updatePwmValue() {
  int raw = (dutyPercent * 4095) / 100;  // Calculate raw PWM value
  pwmValue = (raw * amplitude) / 100;      // Scale by amplitude percentage
}

//---------------------------------------------------------------------
// setup() initializes Serial, sets the PWM resolution, configures the
// PWM frequency on the chosen pin, and starts the modulation timer.
//---------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  while (!Serial) ;  // Wait for Serial Monitor
 
  // Set PWM resolution to 12-bit (0 to 4095)
  analogWriteResolution(12);
 
  pinMode(pwmPin, OUTPUT);
  // Set the PWM frequency on pwmPin.
  analogWriteFrequency(pwmPin, pwmFreq);
 
  updatePwmValue();
  updateModTimer();
 
  Serial.println(F("PWM with Counter Reset Demo"));
  Serial.println(F("Enter commands in one of these formats:"));
  Serial.println(F("  PWM <pwmFreq> <dutyPercent> <modFreq> <amp>"));
  Serial.println(F("     e.g., PWM 900 50 111 80"));
  Serial.println(F("  DUTY <dutyPercent>"));
  Serial.println(F("     e.g., DUTY 80"));
  Serial.println(F("  AMP <amp>"));
  Serial.println(F("     e.g., AMP 90"));
  Serial.println();
}

//---------------------------------------------------------------------
// loop() checks for Serial commands and updates parameters accordingly.
//---------------------------------------------------------------------
void loop() {
  if (Serial.available()) {
    String command = Serial.readStringUntil('\n');
    command.trim();
    
    // Full command: PWM <pwmFreq> <dutyPercent> <modFreq> <amp>
    if (command.startsWith("PWM")) {
      int firstSpace = command.indexOf(' ');
      if (firstSpace > 0) {
        String params = command.substring(firstSpace + 1);
        params.trim();
        int space1 = params.indexOf(' ');
        int space2 = params.indexOf(' ', space1 + 1);
        int space3 = params.indexOf(' ', space2 + 1);
        if (space1 > 0 && space2 > 0 && space3 > 0) {
          String freqStr = params.substring(0, space1);
          String dutyStr = params.substring(space1 + 1, space2);
          String modStr  = params.substring(space2 + 1, space3);
          String ampStr  = params.substring(space3 + 1);
          
          float newPwmFreq = freqStr.toFloat();
          int newDuty = dutyStr.toInt();
          float newModFreq = modStr.toFloat();
          int newAmp = ampStr.toInt();
          
          // Validate the parameters.
          if (newPwmFreq > 0 && newDuty >= 0 && newDuty <= 100 &&
              newModFreq >= 0 && newAmp >= 0 && newAmp <= 100) {
            pwmFreq = newPwmFreq;
            dutyPercent = newDuty;
            modFreq = newModFreq;
            amplitude = newAmp;
            // Update the PWM frequency.
            analogWriteFrequency(pwmPin, pwmFreq);
            updatePwmValue();
            updateModTimer();
            
            Serial.print(F("Updated: PWM Freq = "));
            Serial.print(pwmFreq);
            Serial.print(F(" Hz, Duty = "));
            Serial.print(dutyPercent);
            Serial.print(F("%, Mod Freq = "));
            Serial.print(modFreq);
            Serial.print(F(" Hz, Amp = "));
            Serial.print(amplitude);
            Serial.println(F("%"));
          } else {
            Serial.println(F("Invalid parameters. Check: pwmFreq > 0, duty & amp 0-100, modFreq >= 0."));
          }
        } else {
          Serial.println(F("Invalid format. Use: PWM <pwmFreq> <dutyPercent> <modFreq> <amp>"));
        }
      }
    }
    // Command to update duty cycle only: DUTY <dutyPercent>
    else if (command.startsWith("DUTY")) {
      int firstSpace = command.indexOf(' ');
      if (firstSpace > 0) {
        String dutyStr = command.substring(firstSpace + 1);
        dutyStr.trim();
        int newDuty = dutyStr.toInt();
        if (newDuty >= 0 && newDuty <= 100) {
          dutyPercent = newDuty;
          updatePwmValue();
          Serial.print(F("Updated Duty: "));
          Serial.print(dutyPercent);
          Serial.println(F("%"));
        } else {
          Serial.println(F("Invalid duty cycle. Must be 0-100."));
        }
      }
    }
    // Command to update amplitude only: AMP <amp>
    else if (command.startsWith("AMP")) {
      int firstSpace = command.indexOf(' ');
      if (firstSpace > 0) {
        String ampStr = command.substring(firstSpace + 1);
        ampStr.trim();
        int newAmp = ampStr.toInt();
        if (newAmp >= 0 && newAmp <= 100) {
          amplitude = newAmp;
          updatePwmValue();
          Serial.print(F("Updated Amplitude: "));
          Serial.print(amplitude);
          Serial.println(F("%"));
        } else {
          Serial.println(F("Invalid amplitude. Must be 0-100."));
        }
      }
    }
  }
}
 
Back
Top