From 182de531ca000dc925b09ab7abcc8f6f613a07fd Mon Sep 17 00:00:00 2001 From: MacRsh Date: Sat, 20 Jan 2024 04:04:34 +0800 Subject: [PATCH] =?UTF-8?q?1.=E4=BC=98=E5=8C=96PWM=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E5=99=A8PSC=E5=92=8CARR=E8=AE=A1=E7=AE=97=E7=AE=97=E6=B3=95?= =?UTF-8?q?=EF=BC=8C=E5=A4=A7=E5=B9=85=E6=8F=90=E5=8D=87=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E6=95=88=E7=8E=87=EF=BC=88=E9=80=9A=E5=B8=B8=E5=8F=AA=E9=9C=80?= =?UTF-8?q?=E8=BF=AD=E4=BB=A32-3=E6=AC=A1=EF=BC=89=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=85=88=E9=80=BC=E8=BF=91=E7=9B=AE=E6=A0=87=E9=A2=91=E7=8E=87?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=9C=A8=E8=AF=AF=E5=B7=AE=E5=85=81=E8=AE=B8?= =?UTF-8?q?=E8=8C=83=E5=9B=B4=E5=86=85=EF=BC=88=E4=B8=87=E5=88=86=E4=B9=8B?= =?UTF-8?q?=E4=B8=80=E5=88=B0=E7=99=BE=E5=88=86=E4=B9=8B=E4=B8=80=EF=BC=8C?= =?UTF-8?q?=E8=AF=AF=E5=B7=AE=E8=8C=83=E5=9B=B4=E9=9A=8F=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E9=A2=91=E7=8E=87=E6=8F=90=E9=AB=98=E8=80=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=EF=BC=89=E8=8E=B7=E5=BE=97=E6=9C=80=E4=BD=B3=E7=9A=84=E5=8D=A0?= =?UTF-8?q?=E7=A9=BA=E6=AF=94=E5=88=86=E8=BE=A8=E7=8E=87=E3=80=82=202.PWM-?= =?UTF-8?q?info=E4=B8=ADclk=E4=BB=8EMHz=E6=94=B9=E4=B8=BAHz=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bsp/wch/driver/drv_pwm.c | 4 +-- device/pwm.c | 76 +++++++++++++++++----------------------- include/device/mr_pwm.h | 2 +- 3 files changed, 35 insertions(+), 47 deletions(-) diff --git a/bsp/wch/driver/drv_pwm.c b/bsp/wch/driver/drv_pwm.c index e42942c..6fd007d 100644 --- a/bsp/wch/driver/drv_pwm.c +++ b/bsp/wch/driver/drv_pwm.c @@ -144,8 +144,8 @@ static int drv_pwm_configure(struct mr_pwm *pwm, int state) pclk = RCC_ClockStructure.PCLK1_Frequency; } - /* Update pwm clock(MHz) */ - pwm->info->clk = pclk / 1000000; + /* Update pwm clock(Hz) */ + pwm->info->clk = pclk; /* Configure remap */ if (pwm_data->remap != 0) diff --git a/device/pwm.c b/device/pwm.c index bebcf84..1639fec 100644 --- a/device/pwm.c +++ b/device/pwm.c @@ -65,74 +65,62 @@ static int pwm_channel_get_configure(struct mr_pwm *pwm, int channel, struct mr_ static int pwm_calculate(struct mr_pwm *pwm, uint32_t freq) { uint32_t clk = pwm->info->clk, psc_max = pwm->info->prescaler_max, per_max = pwm->info->period_max; - uint32_t psc_best = 0, per_best = 0; + uint32_t psc_best = 1, per_best = 1; int error_min = INT32_MAX; - /* Check the clock */ + /* Check the clock and frequency */ if (clk == 0 || freq == 0) { return MR_EINVAL; } - /* Calculate the timeout */ - uint32_t timeout = (clk * 1000000) / freq; + /* Calculate the prescaler and period product */ + uint32_t product = clk / freq; - /* Calculate the Least error period */ - for (uint32_t per = (timeout <= per_max) ? timeout : (timeout / (per_max + 1)); per > 0; per--) + /* If the product is within the maximum period, set it as the period */ + if (product <= per_max) { - uint32_t psc = timeout / per; - - /* Calculate the error */ - int error = (int)timeout - (int)(psc * per); - if (error == 0) - { - psc_best = psc; - per_best = per; - break; - } - if (error <= error_min) - { - error_min = error; - psc_best = psc; - per_best = per; - } - } - - /* Optimize the prescaler and period */ - for (uint32_t divisor = 9; divisor > 1; divisor--) + psc_best = 1; + per_best = product; + } else { - /* Check if reload value can be divided by current divisor */ - while ((psc_best % divisor) == 0) + /* Calculate the Least error prescaler and period */ + for (uint32_t psc = MR_BOUND(product / per_max, 1, psc_max); psc < psc_max; psc++) { - uint32_t per_temp = per_best * divisor; + uint32_t per = MR_BOUND(product / psc, 1, per_max); - /* Check if new period or prescaler is valid */ - if (per_temp <= per_max) - { - per_best = per_temp; - psc_best /= divisor; - } else - { - break; - } + /* Calculate the frequency error */ + int error = (int)freq - (int)(clk / psc / per); - /* Check if prescaler can be used as period */ - if ((psc_best > per_best) && (psc_best < per_max)) + /* Found a potentially optimal prescaler and period combination */ + if (error == 0) { - MR_SWAP(per_best, psc_best); + psc_best = psc; + per_best = per; + + /* Found a valid and optimal solution */ + if (per_best < per_max) + { + break; + } + } else if (error < error_min) + { + error_min = error; + psc_best = psc; + per_best = per; } } } - /* Check prescaler is valid */ - if (psc_best > psc_max) + /* Check period is valid */ + if (per_best > per_max) { return MR_EINVAL; } pwm->prescaler = psc_best; pwm->period = per_best; - pwm->freq = (clk * 1000000) / psc_best / per_best; + pwm->freq = clk / psc_best / per_best; return MR_EOK; } diff --git a/include/device/mr_pwm.h b/include/device/mr_pwm.h index de98945..647869c 100644 --- a/include/device/mr_pwm.h +++ b/include/device/mr_pwm.h @@ -53,7 +53,7 @@ typedef uint32_t mr_pwm_data_t; /**< PWM rea */ struct mr_pwm_info { - uint32_t clk; /**< Clock(MHz) */ + uint32_t clk; /**< Clock(Hz) */ uint32_t prescaler_max; /**< Prescaler max */ uint32_t period_max; /**< Period max */ };