Hello,
I'm working on some LED sequences using the NRFX PWM driver and I can't get the durations I want right.
Let's say that I want a semi-blinking LED (100% - 50% - 100%...) with a period of 500 ms on each state and I initialize the PWM driver as follows:
nrfx_pwm_config_t const pwm_config =
{
.output_pins =
{
led.red | led.polarity, // Channel 0
led.green | led.polarity, // Channel 1
led.blue | led.polarity, // Channel 2
NRFX_PWM_PIN_NOT_USED // Channel 3
},
.irq_priority = APP_IRQ_PRIORITY_LOW,
.base_clock = NRF_PWM_CLK_16MHz, // NRF_PWM_CLK_125kHz,
.count_mode = NRF_PWM_MODE_UP_AND_DOWN, // For symmetric color mixing
.top_value = 255,
.load_mode = NRF_PWM_LOAD_INDIVIDUAL,
.step_mode = NRF_PWM_STEP_AUTO
};
err_code = nrfx_pwm_init(&m_pwm0, &pwm_config, pwm_event_handler);
APP_ERROR_CHECK(err_code);
As far as I understand I could do this to get my timing right:
void setup_single_color_sequence(nrf_pwm_sequence_t * sequence, color_t color, uint32_t duration_in_us) {
uint32_t top = 255;
uint32_t pwm_period = top / 16; // In µs (top / clock_frequency in MHz)
uint16_t pwm_pulses_for_duration = duration_in_us / (pwm_period * NRF_PWM_VALUES_LENGTH(pwm_values_single_color));
for (uint8_t i = 0; i < 2; i++) {
pwm_values_single_color[i].channel_0 = color.r;
pwm_values_single_color[i].channel_1 = color.g;
pwm_values_single_color[i].channel_2 = color.b;
pwm_values_single_color[i].channel_3 = 0;
}
sequence->values.p_individual = pwm_values_single_color;
sequence->length = NRF_PWM_VALUES_LENGTH(pwm_values_single_color);
sequence->repeats = pwm_pulses_for_duration;
sequence->end_delay = 0;
}
That is using the .repeats field to make each duty cycle repeat in order to get my desired timing. That however doesn't really work, I get shorter periods.
My logic is: The PWM counts up to 255. If I'm running the PWM at 16 MHz, then each duty cycle has a duration of 255/16 MHz = ~16 us. If I want the PWM to stay at that level for 500 ms, then I divide that duration (in us) by the duration of the duty cycle and I get the number of times that I need to repeat each duty cycle in order to get my target duration.
Is that logic wrong?