Hello Nylon, On Tue, Mar 04, 2025 at 05:02:13PM +0800, Nylon Chen wrote: > Nylon Chen <nylon.chen@xxxxxxxxxx> 於 2025年1月23日 週四 上午8:20寫道: > > > > Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxx> 於 2025年1月22日 週三 下午7:44寫道: > > > > > > Hello Nylon, > > > > > > I took another look in the driver and found another problem: > > Hi Uwe, Thank you for the information. > > > > I'll need some time to verify and understand these details, as well as > > conduct the relevant tests > > > > > > On Tue, Jan 21, 2025 at 07:12:10PM +0100, Uwe Kleine-König wrote: > > > > On Tue, Jan 21, 2025 at 04:47:46PM +0800, Nylon Chen wrote: > > > > > Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxx> 於 2025年1月21日 週二 下午3:47寫道: > > > > > > > > > > > > Hello, > > > > > > > > > > > > On Sun, Jan 19, 2025 at 03:03:16PM +0800, Nylon Chen wrote: > > > > > > > I ran some basic tests by changing the period and duty cycle in both > > > > > > > decreasing and increasing sequences (see the script below). > > > > > > > > > > > > What is clk_get_rate(ddata->clk) for you? > > > > > 130 MHz > > > > > > > > OK, so the possible period lengths are > > > > > > > > (1 << (16 + scale)) / (130 MHz) > > > > > > > > for scale in [0, .. 15], right? That's > > > > > > > > 2^scale * 504123.07692307694 ns > > > > > > > > So testing period in the range between 5000 ns and 15000 ns isn't > > > > sensible? Did I get something wrong? If the above is right, switching > > > > between period=1008246 ns and 1008247 ns is likely to trigger a > > > > warning. > > > > > > The possible periods are of the form > > > > > > 2^scale * A > > > > > > where A is constant and only depends on the input clock rate. scale > > > ranges over [0, ... 15]. (If I got it right in my last mail, we have A = > > > 504123.07692307694 ns.) > > > > > > If you request say: > > > > > > .period = 3.9 * A > > > .duty_cycle = 1.9 * A > > > > > > the period actually emitted by the PWM will be 2 * A. But to calculate > > > frac the originally requested period (i.e. 3.9 * A) is used. So frac > > > becomes 31927 resulting in .duty_cycle being ~0.974 A. A better value > > > would be frac = 62259 which results in .duty_cycle ≅ 1.9 * A. > > > (Depending on A the values for frac might be off by one due to rounding > > > differences.) > > > > > > So I would expect that PWM_DEBUG is angry with you if you go from > > > > > > .period = 2 * A > > > .duty_cycle = 1.9 * A > > > > > > to > > > > > > .period = 3.9 * A > > > .duty_cycle = 1.9 * A > > > > > > . > > > > > > Best regards > > > Uwe > > Hi Uwe, Based on your suggestions, I conducted relevant tests and > corrected algorithm errors. > > According to this test program, I can make the system generate related > error messages on v10's patchset. > > e.g. > [ 75.043652] pwm-sifive 10021000.pwm: .apply is supposed to round down > duty_cycle (requested: 360/504000, applied: 361/504124) > [ 75.055042] pwm-sifive 10021000.pwm: .apply is supposed to round down > period (requested: 504000, applied: 504124) > > PWMCHIP=1 > PWMCHANNEL=0 > PERIOD=504000 > STEP=1 > MAX_DUTY=504000 > > echo 0 > /sys/class/pwm/pwmchip${PWMCHIP}/export > > echo $PERIOD > /sys/class/pwm/pwmchip${PWMCHIP}/pwm${PWMCHANNEL}/period > echo "Set period to $PERIOD ns (scale=0 region)" > > COUNT=$((MAX_DUTY / STEP)) > echo "Testing duty-cycle from 0 to $MAX_DUTY in step of $STEP..." > echo "Total steps (forward): $((COUNT+1))" > > > CURRENT=0 > while [ $CURRENT -le $MAX_DUTY ]; do > echo $CURRENT > /sys/class/pwm/pwmchip${PWMCHIP}/pwm${PWMCHANNEL}/duty_cycle > CURRENT=$((CURRENT + STEP)) > done > > echo "Now do a backward test from $MAX_DUTY down to 0 in step of $STEP..." > echo "Total steps (backward): $((COUNT+1))" > > > CURRENT=$MAX_DUTY > while [ $CURRENT -ge 0 ]; do > echo $CURRENT > /sys/class/pwm/pwmchip${PWMCHIP}/pwm${PWMCHANNEL}/duty_cycle > CURRENT=$((CURRENT - STEP)) > done > > > echo 0 > /sys/class/pwm/pwmchip${PWMCHIP}/pwm${PWMCHANNEL}/enable > echo ${PWMCHANNEL} > /sys/class/pwm/pwmchip${PWMCHIP}/unexport > > echo "Done!" > > Based on your previous suggestions, I have made the following related > modifications, and now I'm able to fix the relevant errors. > > But I want to make sure my understanding aligns with your suggestions, > so I'd like to discuss with you first before sending the patch. > > - In .apply, use "round down" for calculations to ensure the value > doesn't exceed what the user requested. (Never set a duty cycle higher > than what the user requested.) > pwm_sifive_apply() { > - frac = DIV64_U64_ROUND_CLOSEST(num, state->period); > +frac = num / state->period; > } > - When converting hardware values back to duty_cycle in .get_state, > use "round up" to compensate for the errors introduced by .apply.() > pwm_sifive_get_state() { > - state->duty_cycle = (u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH; > + state->duty_cycle = DIV_ROUND_UP_ULL((u64)duty * > ddata->real_period, (1U << PWM_SIFIVE_CMPWIDTH)); > } That sounds right. Best regards Uwe
Attachment:
signature.asc
Description: PGP signature