From ae5accbb253c48053788c8ada65f5da17e484d99 Mon Sep 17 00:00:00 2001 From: Richard Unger Date: Tue, 30 May 2023 22:52:56 +0200 Subject: [PATCH 1/3] extend RP2040 PWM to support low speeds --- .../hardware_specific/rp2040/rp2040_mcu.cpp | 19 ++++++++++++++----- .../hardware_specific/rp2040/rp2040_mcu.h | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/drivers/hardware_specific/rp2040/rp2040_mcu.cpp b/src/drivers/hardware_specific/rp2040/rp2040_mcu.cpp index a2970c72..0cc333ad 100644 --- a/src/drivers/hardware_specific/rp2040/rp2040_mcu.cpp +++ b/src/drivers/hardware_specific/rp2040/rp2040_mcu.cpp @@ -30,11 +30,12 @@ void setupPWM(int pin, long pwm_frequency, bool invert, RP2040DriverParams* para params->pins[index] = pin; params->slice[index] = slice; params->chan[index] = chan; - pwm_set_clkdiv_int_frac(slice, 1, 0); // fastest pwm we can get - pwm_set_phase_correct(slice, true); - uint16_t wrapvalue = ((125L * 1000L * 1000L) / pwm_frequency) / 2L - 1L; - if (wrapvalue < 999) wrapvalue = 999; // 66kHz, resolution 1000 - if (wrapvalue > 12499) wrapvalue = 12499; // 20kHz, resolution 12500 + uint32_t sysclock_hz = machine.freq(); + uint32_t factor = 4096 * 2 * pwm_frequency; + uint32_t div = sysclock_hz / factor; + if (sysclock_hz % factor !=0) div+=1; + if (div < 16) div = 16; + uint32_t wrapvalue = sysclock_hz *16 / div / pwm_frequency - 1; #ifdef SIMPLEFOC_DEBUG_RP2040 SimpleFOCDebug::print("Configuring pin "); SimpleFOCDebug::print(pin); @@ -44,9 +45,17 @@ void setupPWM(int pin, long pwm_frequency, bool invert, RP2040DriverParams* para SimpleFOCDebug::print((int)chan); SimpleFOCDebug::print(" frequency "); SimpleFOCDebug::print((int)pwm_frequency); + SimpleFOCDebug::print(" divisor "); + SimpleFOCDebug::print((int)(div>>4)); + SimpleFOCDebug::print("."); + SimpleFOCDebug::print((int)(div&0xF)); SimpleFOCDebug::print(" top value "); SimpleFOCDebug::println(wrapvalue); #endif + if (wrapvalue < 999) + SimpleFOCDebug::println("Warning: PWM resolution is low."); + pwm_set_clkdiv_int_frac(slice, div>>4, div&0xF); + pwm_set_phase_correct(slice, true); pwm_set_wrap(slice, wrapvalue); wrapvalues[slice] = wrapvalue; if (invert) { diff --git a/src/drivers/hardware_specific/rp2040/rp2040_mcu.h b/src/drivers/hardware_specific/rp2040/rp2040_mcu.h index c3b4fe51..bbfb3873 100644 --- a/src/drivers/hardware_specific/rp2040/rp2040_mcu.h +++ b/src/drivers/hardware_specific/rp2040/rp2040_mcu.h @@ -2,6 +2,8 @@ #pragma once +#include "Arduino.h" + #if defined(TARGET_RP2040) From 3cee9cfb209a7d988f21130a8d00f180f5725eeb Mon Sep 17 00:00:00 2001 From: Richard Unger Date: Thu, 1 Jun 2023 23:42:04 +0200 Subject: [PATCH 2/3] make isSentinel useable for other code --- src/communication/Commander.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/communication/Commander.h b/src/communication/Commander.h index 3633a510..91e3dc45 100644 --- a/src/communication/Commander.h +++ b/src/communication/Commander.h @@ -240,6 +240,7 @@ class Commander */ void motion(FOCMotor* motor, char* user_cmd, char* separator = (char *)" "); + bool isSentinel(char ch); private: // Subscribed command callback variables CommandCallback call_list[20];//!< array of command callback pointers - 20 is an arbitrary number @@ -294,7 +295,6 @@ class Commander void printError(); - bool isSentinel(char ch); }; From fa637deed3fb32d6a15916394429d4b4dea29138 Mon Sep 17 00:00:00 2001 From: Richard Unger Date: Thu, 1 Jun 2023 23:58:18 +0200 Subject: [PATCH 3/3] RP2040 PWM driver now supports pre-scaler --- src/drivers/hardware_specific/rp2040/rp2040_mcu.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/drivers/hardware_specific/rp2040/rp2040_mcu.cpp b/src/drivers/hardware_specific/rp2040/rp2040_mcu.cpp index 0cc333ad..ebe1a7dd 100644 --- a/src/drivers/hardware_specific/rp2040/rp2040_mcu.cpp +++ b/src/drivers/hardware_specific/rp2040/rp2040_mcu.cpp @@ -9,10 +9,11 @@ #include "../../hardware_api.h" #include "./rp2040_mcu.h" #include "hardware/pwm.h" +#include "hardware/clocks.h" #define _PWM_FREQUENCY 24000 #define _PWM_FREQUENCY_MAX 66000 -#define _PWM_FREQUENCY_MIN 5000 +#define _PWM_FREQUENCY_MIN 1 @@ -30,12 +31,12 @@ void setupPWM(int pin, long pwm_frequency, bool invert, RP2040DriverParams* para params->pins[index] = pin; params->slice[index] = slice; params->chan[index] = chan; - uint32_t sysclock_hz = machine.freq(); + uint32_t sysclock_hz = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS) * 1000; uint32_t factor = 4096 * 2 * pwm_frequency; uint32_t div = sysclock_hz / factor; if (sysclock_hz % factor !=0) div+=1; if (div < 16) div = 16; - uint32_t wrapvalue = sysclock_hz *16 / div / pwm_frequency - 1; + uint32_t wrapvalue = (sysclock_hz * 8) / div / pwm_frequency - 1; #ifdef SIMPLEFOC_DEBUG_RP2040 SimpleFOCDebug::print("Configuring pin "); SimpleFOCDebug::print(pin); @@ -50,7 +51,7 @@ void setupPWM(int pin, long pwm_frequency, bool invert, RP2040DriverParams* para SimpleFOCDebug::print("."); SimpleFOCDebug::print((int)(div&0xF)); SimpleFOCDebug::print(" top value "); - SimpleFOCDebug::println(wrapvalue); + SimpleFOCDebug::println((int)wrapvalue); #endif if (wrapvalue < 999) SimpleFOCDebug::println("Warning: PWM resolution is low.");