diff --git a/cores/psoc6/Arduino.h b/cores/psoc6/Arduino.h index 180bc719..5605dd90 100644 --- a/cores/psoc6/Arduino.h +++ b/cores/psoc6/Arduino.h @@ -47,6 +47,7 @@ extern bool gpio_current_value[]; #define PWM_FREQUENCY_HZ 1000 // 1 kHz void analogWriteResolution(int res); void analogReadResolution(int res); +void setAnalogWriteFrequency(pin_size_t pinNumber, uint32_t frequency); #undef LITTLE_ENDIAN diff --git a/cores/psoc6/analog_io.c b/cores/psoc6/analog_io.c index 9abbbcc8..8b0ecd10 100644 --- a/cores/psoc6/analog_io.c +++ b/cores/psoc6/analog_io.c @@ -24,7 +24,10 @@ typedef struct { typedef struct { cyhal_pwm_t pwm_obj; pin_size_t pin; + float duty_cycle_percent; + float frequency_hz; bool initialized; + bool used; } pwm_t; // Static Variables @@ -145,46 +148,87 @@ void analogWriteResolution(int res) { } } -void analogWrite(pin_size_t pinNumber, int value) { - uint8_t pwm_index = 0; - uint8_t pwm_value = value; - cy_rslt_t result = CY_RSLT_TYPE_ERROR; - +static pwm_t * pwm_alloc(pin_size_t pinNumber) { if (pinNumber > GPIO_PIN_COUNT) { - return; // Invalid pin number + return NULL; // Invalid pin number } - // Find existing channel or initialize a new one - for (pwm_index = 0; pwm_index < PWM_HOWMANY; pwm_index++) { - if (pwm[pwm_index].initialized) { - if (pwm[pwm_index].pin == pinNumber) { - // Found an existing channel for the pin - break; - } - } else { - // Found an uninitialized channel, initialize it - result = cyhal_pwm_init(&pwm[pwm_index].pwm_obj, mapping_gpio_pin[pinNumber], NULL); - pwm_assert(result); - pwm[pwm_index].pin = pinNumber; - pwm[pwm_index].initialized = true; - break; + // First, look for existing allocation for this pin + for (uint8_t i = 0; i < PWM_HOWMANY; i++) { + if (pwm[i].used && pwm[i].pin == pinNumber) { + return &pwm[i]; } } - if (pwm_index < PWM_HOWMANY) { - if (pwm_value <= 0) { - pwm_value = 0; - } - if (pwm_value > desiredWriteResolution) { - pwm_value = desiredWriteResolution; + // If not found, look for unused slot + for (uint8_t i = 0; i < PWM_HOWMANY; i++) { + if (!pwm[i].used) { + // Allocate this slot + pwm[i].pin = pinNumber; + pwm[i].used = true; + pwm[i].frequency_hz = 0; + pwm[i].duty_cycle_percent = 0; + pwm[i].initialized = false; + return &pwm[i]; } + } - float duty_cycle_pertentage = (pwm_value / desiredWriteResolution) * 100.0f; + return NULL; // No slots available +} - result = cyhal_pwm_set_duty_cycle(&pwm[pwm_index].pwm_obj, duty_cycle_pertentage, PWM_FREQUENCY_HZ); - pwm_assert(result); +void analogWrite(pin_size_t pinNumber, int value) { + // Allocate or find existing PWM slot + pwm_t *pwm = pwm_alloc(pinNumber); + if (pwm == NULL) { + return; + } - result = cyhal_pwm_start(&pwm[pwm_index].pwm_obj); + if (!pwm->initialized) { + cy_rslt_t result = cyhal_pwm_init(&pwm->pwm_obj, mapping_gpio_pin[pinNumber], NULL); pwm_assert(result); + pwm->initialized = true; + } + + int pwm_value = value; + if (pwm_value <= 0) { + pwm_value = 0; + } + if (pwm_value > desiredWriteResolution) { + pwm_value = desiredWriteResolution; + } + + // Calculate duty cycle + float duty_cycle_percent = ((float)pwm_value / desiredWriteResolution) * 100.0f; + pwm->duty_cycle_percent = duty_cycle_percent; + + // Use pre-configured frequency or default + if (pwm->frequency_hz == 0) { + pwm->frequency_hz = PWM_FREQUENCY_HZ; + } + + // Set duty cycle and start PWM + cy_rslt_t result = cyhal_pwm_set_duty_cycle(&pwm->pwm_obj, duty_cycle_percent, pwm->frequency_hz); + pwm_assert(result); + + result = cyhal_pwm_start(&pwm->pwm_obj); + pwm_assert(result); +} + +void setAnalogWriteFrequency(pin_size_t pinNumber, uint32_t frequency) { + // Allocate or find existing PWM slot + pwm_t *pwm = pwm_alloc(pinNumber); + if (pwm == NULL) { + return; + } + + // Set frequency + pwm->frequency_hz = frequency; + + // If already initialized, update the hardware immediately + if (pwm->initialized) { + cy_rslt_t result = cyhal_pwm_set_duty_cycle(&pwm->pwm_obj, pwm->duty_cycle_percent, frequency); + if (result != CY_RSLT_SUCCESS) { + pwm_assert(result); + } } } diff --git a/docs/arduino-deviations.rst b/docs/arduino-deviations.rst index 3054d0ee..c46d1b57 100644 --- a/docs/arduino-deviations.rst +++ b/docs/arduino-deviations.rst @@ -52,6 +52,13 @@ Only the `DEFAULT` mode is supported and uses the internal reference voltage of The PWM resolution is fixed at 8 bits by default unless the user explicitly sets a different resolution using the `analogWriteResolution()` function. The default frequency of the PWM signal is fixed at **1 kHz** and cannot be changed. +.. code-block:: cpp + + void setAnalogWriteFrequency(int pin, uint32_t frequency) + +This function can be used to set the frequency of the AnalogWrite PWM signal. The allowed range is from 1Hz to 100MHz. This function will only set the frequency +and user has to explicitly call the `analogwrite()` to start the PWM signal with the frequency set. +If the user has already started the PWM using `analogwrite()` then user can call this function to change the frequency. .. code-block:: cpp