@eriksl, Cicero: Thanks, glad you like it
@eriksl: There are two different aspects when it comes to interrupts:
1. Driving the GPIO pins - this is done from the normal timer interrupt. As any other interrupt (but NMI) it can be delayed by a currently running interrupt handler. This is a matter of fact for any software driven PWM. You can use it for LED dimming, fan speed control, ..., but better not for robotics or tooling machines.
2. Setting of the duty values - new values are committed by the pwm_start() function (this had better been named pwm_apply or _commit, but I wanted to the with the ESP SDK names). All the real work is done in a scratch buffer. After any calculations, a single pointer referencing this buffer is updated, which is atomic. Actually there are three buffers, one for serving the GPIO pins, one becoming valid start of the next PWM period (which might be the same as the first), and the scratch buffer.
So to answer your question, the worst that can happen if you are trying to change duty values faster than a PWM period, some immediate changes may not be visible. The code itself is interrupt safe - you can set the duty values (and period) whenever you want and from any context, only pwm_start should be called from a single context.