3 #include "pico/stdlib.h"
5 #include "hardware/gpio.h"
6 #include "hardware/adc.h"
7 #include "hardware/pwm.h"
8 #include "hardware/clocks.h"
9 #include "PicoPinFunction.h"
13 #define PWM_MAX_NUMER 1000
16 #ifndef PWM_READ_REPEAT
17 #define PWM_READ_REPEAT 10
24 inline int pico_pwm_actual_pin;
25 inline static void on_pico_pwm_wrap() {
27 pwm_clear_irq(pwm_gpio_to_slice_num(pico_pwm_actual_pin));
33 inline static float frequency(uint64_t period_nano_sec){
34 return 1000000000.0 / period_nano_sec;
51 Logger.
debug(
"PicoPWMWriter");
52 period_nano_sec = periodNanoSeconds;
53 tick_period_nano_sec = period_nano_sec / PWM_MAX_NUMER;
57 void begin(pin_size_t pinNumber, uint64_t initialDutyCyleNanoSeconds=0){
58 Logger.
printf(PicoLogger::Debug,
"PicoPWMWriter::begin %d\n", pinNumber);
59 initial_duty_cycle = initialDutyCyleNanoSeconds;
63 pinFunction.
usePin(pinNumber, PIN_FUNC_PWM,
this);
68 Logger.
debug(
"PicoPWMWriter::setupPin");
70 uint8_t slice_num = pwm_gpio_to_slice_num(pinNumber);
73 Logger.
debug(
"pwm_init for OUTPUT");
74 pwm_init(slice_num, &config,
true);
77 Logger.
debug(
"gpio_set_function");
78 gpio_set_function(pinNumber, GPIO_FUNC_PWM);
82 void end(pin_size_t pin){
83 Logger.
debug(
"PicoPWMWriter::end");
86 pinFunction.
clear(pin);
91 Logger.
debug(
"PicoPWMWriter::setDutyCycle");
92 uint slice_num = pwm_gpio_to_slice_num(pin);
93 uint channel = pwm_gpio_to_channel(pin);
94 uint16_t value = (1.0 * dutyCyleNanoSeconds) / tick_period_nano_sec;
98 sprintf(str,
"%lu", dutyCyleNanoSeconds);
99 Logger.
debug(
"PWM duty cycle ns:",str);
100 sprintf(str,
"%lu", value);
101 Logger.
debug(
"PWM duty cycle(internal):",str);
103 pwm_set_chan_level(slice_num, channel, value);
108 return pico_arduino::frequency(period_nano_sec);
112 float frequencyTick(){
113 return pico_arduino::frequency(tick_period_nano_sec);
118 return tick_period_nano_sec;
123 return period_nano_sec;
130 uint64_t period_nano_sec;
131 uint64_t initial_duty_cycle;
132 float tick_period_nano_sec;
133 bool is_config_done =
false;
137 if (!is_config_done) {
138 Logger.
debug(
"PicoPWMWriter::setupConfig");
139 is_config_done =
true;
140 uint16_t wrap = PWM_MAX_NUMER ;
141 config = pwm_get_default_config();
143 uint32_t sys_clock_freq = clock_get_hz(clk_sys);
145 float dividerTick = (1.0 * sys_clock_freq) / frequencyTick();
146 logConfig(sys_clock_freq, dividerTick, wrap);
149 pwm_config_set_clkdiv(&config, dividerTick);
150 pwm_config_set_wrap(&config, wrap);
157 void logConfig(uint32_t sys_clock_freq,
float dividerTick, uint16_t wrap ) {
158 if (Logger.
isLogging(PicoLogger::Debug)){
160 sprintf(str,
"%lu", period_nano_sec);
161 Logger.
debug(
"Period ns:", str);
162 sprintf(str,
"%f", tick_period_nano_sec);
163 Logger.
debug(
"Tick period ns:", str);
165 Logger.
debug(
"PWM hz:", str);
166 sprintf(str,
"%f", sys_clock_freq);
167 Logger.
debug(
"Systemclock hz:", str);
168 sprintf(str,
"%f", dividerTick);
169 Logger.
debug(
"Tick divider:", str);
170 sprintf(str,
"%d", wrap);
171 Logger.
debug(
"PWM wrap:", str);
191 Logger.
debug(
"PicoPWMReader");
192 period_nano_sec = periodNanoSeconds;
193 tick_period_nano_sec = period_nano_sec / PWM_MAX_NUMER;
198 Logger.
printf(PicoLogger::Info,
"PicoPWMReader::begin %d\n", pinNumber);
205 pin_mode = pinFunction.
pinMode(pinNumber);
208 pinFunction.
usePin(pinNumber, PIN_FUNC_PWM,
this);
213 Logger.
debug(
"PicoPWMReader::setupPin");
215 uint8_t slice_num = pwm_gpio_to_slice_num(pinNumber);
218 Logger.
debug(
"pwm_init for INPUT");
220 pwm_config_set_clkdiv_mode(&config, PWM_DIV_B_HIGH);
221 pwm_init(slice_num, &config,
false);
223 Logger.
debug(
"gpio_set_function");
224 gpio_set_function(pinNumber, GPIO_FUNC_PWM);
229 Logger.
debug(
"PicoPWMReader::end");
230 pinFunction.
clear(pin);
240 Logger.
debug(
"PicoPWMReader::measureDutyCycle");
242 if (pin_mode==INPUT) {
244 if(pwm_gpio_to_channel(gpio) == PWM_CHAN_B) {
246 pico_pwm_actual_pin = gpio;
247 uint slice_num = pwm_gpio_to_slice_num(gpio);
251 pwm_clear_irq(slice_num);
252 pwm_set_irq_enabled(slice_num,
true);
253 irq_set_exclusive_handler(PWM_IRQ_WRAP, on_pico_pwm_wrap);
254 irq_set_enabled(PWM_IRQ_WRAP,
true);
257 uint64_t counter = count(slice_num, PWM_READ_REPEAT);
260 pwm_clear_irq(slice_num);
261 pwm_set_irq_enabled(slice_num,
false);
262 irq_remove_handler (PWM_IRQ_WRAP, on_pico_pwm_wrap);
265 result = 100.0 * counter / max_ticks_per_period;
267 Logger.
error(
"measureDutyCycle() only allowed the PWM B pins");
270 Logger.
error(
"measureDutyCycle() only allowed with pinMode INPUT");
277 return period_nano_sec;
285 uint64_t period_nano_sec;
286 uint64_t max_ticks_per_period;
287 float tick_period_nano_sec;
288 bool is_config_done =
false;
293 if (!is_config_done) {
294 Logger.
debug(
"PicoPWMReader::setupConfig");
295 is_config_done =
true;
296 uint16_t wrap = PWM_MAX_NUMER ;
297 config = pwm_get_default_config();
299 uint32_t sys_clock_freq = clock_get_hz(clk_sys);
302 max_ticks_per_period = period_nano_sec * sys_clock_freq / 1000000000;
305 pwm_config_set_clkdiv(&config, 1.0);
306 pwm_config_set_wrap(&config, wrap);
308 logConfig(sys_clock_freq, wrap);
314 void logConfig(uint32_t sys_clock_freq, uint16_t wrap ) {
315 if (Logger.
isLogging(PicoLogger::Debug)){
317 sprintf(str,
"%lu", period_nano_sec);
318 Logger.
debug(
"Period ns:", str);
319 sprintf(str,
"%f", tick_period_nano_sec);
320 Logger.
debug(
"Tick period ns:", str);
321 sprintf(str,
"%f", sys_clock_freq);
322 Logger.
debug(
"Systemclock hz:", str);
323 sprintf(str,
"%d", wrap);
324 Logger.
debug(
"PWM wrap:", str);
328 uint64_t count(uint slice_num,
int repeat) {
329 uint64_t sleep_period_us = (period_nano_sec / 1000 );
332 if (Logger.
isLogging(PicoLogger::Debug)){
334 sprintf(sleep_str,
"sleep_us: %lu", sleep_period_us);
335 Logger.
debug(sleep_str);
338 uint64_t counter = 0;
339 for (
int j=0;j<repeat;j++) {
341 pwm_set_counter (slice_num, 0);
342 pwm_set_enabled(slice_num,
true);
343 sleep_us((sleep_period_us ));
344 pwm_set_enabled(slice_num,
false);
346 counter += pwm_get_counter(slice_num);
349 return counter / repeat;
366 Logger.
debug(
"PicoPWMNano");
378 void begin(pin_size_t gpio, uint64_t initialDutyCyleNanoSeconds=0, PinMode pinMode=OUTPUT){
384 if (pin_function.
isInput(gpio)){
386 }
else if (pin_function.
isOutput(gpio)){
387 writer->
begin(gpio, initialDutyCyleNanoSeconds);
392 void end(pin_size_t gpio){
438 bool isOutput(pin_size_t gpio) {
441 bool isInput(pin_size_t gpio) {
442 return pin_function.
isInput(gpio);
458 period_nano_sec = 1000000000l /
frequency;
460 max_value = maxValue;
469 void begin(pin_size_t pin, uint64_t initalValue){
470 nano->
begin(pin, initalValue);
474 void begin(pin_size_t pin, PinMode pinMode=OUTPUT){
475 nano->
begin(pin, 0, pinMode);
484 void write(pin_size_t pin, uint64_t value){
495 return 100.0 *
read(pin) / max_value;
511 uint64_t period_nano_sec;
515 return map(value, 0, max_value, 0, period_nano_sec);
518 uint64_t dutyCycleToValue(uint64_t dutyCycle){
519 return map(dutyCycle, 0, period_nano_sec, 0, max_value) + 1;
virtual int printf(LogLevel current_level, const char *fmt,...)
printf support
Definition: PicoLogger.h:65
virtual bool isLogging(LogLevel level=Info)
checks if the logging is active
Definition: PicoLogger.h:40
virtual void error(const char *str, const char *str1=nullptr, const char *str2=nullptr)
logs an error
Definition: PicoLogger.h:45
virtual void debug(const char *str, const char *str1=nullptr, const char *str2=nullptr)
writes an debug message
Definition: PicoLogger.h:60
This is an even more powerfull PWM API where we can specify a user defined input range and the cycle ...
Definition: PicoPWM.h:453
uint64_t frequency()
Provides the frequncy in hz which was specified in the constructor.
Definition: PicoPWM.h:504
void begin(pin_size_t pin, uint64_t initalValue)
setup a pin for pwm write
Definition: PicoPWM.h:469
void write(pin_size_t pin, uint64_t value)
Defines the active period in the value range from 0 to maxValue.
Definition: PicoPWM.h:484
void begin(pin_size_t pin, PinMode pinMode=OUTPUT)
setup a pin for pwm read or write
Definition: PicoPWM.h:474
PicoPWM(uint64_t frequency, uint64_t maxValue)
Default constructor.
Definition: PicoPWM.h:456
void end(pin_size_t pin)
sets the pin to low
Definition: PicoPWM.h:479
uint64_t period()
Provides the full cycle period in nanoseconds.
Definition: PicoPWM.h:499
float readPercent(pin_size_t pin)
Provides the duty cyle in percent.
Definition: PicoPWM.h:494
uint64_t read(pin_size_t pin)
Reads the active period in the value range from 0 to maxValue.
Definition: PicoPWM.h:489
~PicoPWM()
Destructor.
Definition: PicoPWM.h:464
uint64_t valueToDutyCycle(uint64_t value)
converts an input value to the duty cycle in nanosec
Definition: PicoPWM.h:514
Basic PWM API based on the input and output in nano seconds The Raspberry Pico has 8 controllable PWM...
Definition: PicoPWM.h:362
float frequency()
converts the PWM period to hz for the PWM output
Definition: PicoPWM.h:423
void begin(pin_size_t gpio, uint64_t initialDutyCyleNanoSeconds=0, PinMode pinMode=OUTPUT)
setup the pin mode only if necessary
Definition: PicoPWM.h:378
uint64_t measureDutyCycle(uint gpio)
measures the duty cycle in nanoseconds - only the PWM B pins can be used as inputs!
Definition: PicoPWM.h:405
uint64_t period()
provides the full cycle period in nanoseconds
Definition: PicoPWM.h:428
PicoPWMNano(uint64_t periodNanoSeconds)
Constructor: Defines the length of a full cycle in nanoseconds (mio of seconds)
Definition: PicoPWM.h:365
void end(pin_size_t gpio)
sets the output pins to low
Definition: PicoPWM.h:392
float measureDutyCyclePercent(uint gpio)
provides the duty cycle in percent
Definition: PicoPWM.h:414
void setDutyCycle(pin_size_t gpio, uint64_t dutyCyleNanoSeconds)
Defines the active period is nanoseconds.
Definition: PicoPWM.h:398
PWM class which supports the input of PWM signals.
Definition: PicoPWM.h:182
uint64_t measureDutyCycle(uint gpio)
measures the duty cycle (active period) in nanoseconds - only the PWM B pins can be used as inputs!
Definition: PicoPWM.h:234
uint64_t period()
provides the full cycle period in nanoseconds
Definition: PicoPWM.h:276
void begin(pin_size_t pinNumber)
setup a pin for pwm write
Definition: PicoPWM.h:197
PicoPWMReader(uint64_t periodNanoSeconds)
Constructor: Defines the length of a full cycle in nanoseconds (mio of seconds). This is used as mesu...
Definition: PicoPWM.h:190
void end(pin_size_t pin)
sets the pin to low
Definition: PicoPWM.h:228
virtual void setupPin(PinInfo *info, pin_size_t pinNumber)
setup of pin for PWM Input
Definition: PicoPWM.h:212
bool setupConfig()
provides the configuration - returns true if we have a new configuration
Definition: PicoPWM.h:292
float measureDutyCyclePercent(uint gpio)
provides the duty cycle in percent
Definition: PicoPWM.h:239
Support for the generation of PWM signals. For the standard Arduino functionality we use on fixed fre...
Definition: PicoPWM.h:47
float frequency()
converts the PWM period to hz
Definition: PicoPWM.h:107
void setDutyCycle(pin_size_t pin, uint64_t dutyCyleNanoSeconds)
Defines the active period is nanoseconds.
Definition: PicoPWM.h:90
virtual void setupPin(PinInfo *info, pin_size_t pinNumber)
setup of pin for PWM Output
Definition: PicoPWM.h:67
PicoPWMWriter(uint64_t periodNanoSeconds)
Constructor: Defines the length of a full cycle in nanoseconds (mio of seconds)
Definition: PicoPWM.h:50
uint64_t period()
provides the full cycle period in nanoseconds
Definition: PicoPWM.h:122
bool setupConfig()
provides the configuration - returns true if we have a new configuration
Definition: PicoPWM.h:136
void end(pin_size_t pin)
sets the pin to low
Definition: PicoPWM.h:82
void begin(pin_size_t pinNumber, uint64_t initialDutyCyleNanoSeconds=0)
setup a pin for pwm write
Definition: PicoPWM.h:57
The pico requires that the function of the pin is defined. In Arduino, there is no such concept - how...
Definition: PicoPinFunction.h:133
PinMode pinMode(pin_size_t pinNumber)
returns the pin mode
Definition: PicoPinFunction.h:184
void clear(pin_size_t pinNumber)
set gpio function to GPIO_FUNC_NULL
Definition: PicoPinFunction.h:198
void usePin(pin_size_t pinNumber, PinFunctionEnum pinFunction, PinSetup *setup=nullptr)
setup Pico pin init function bysed on functionality
Definition: PicoPinFunction.h:205
bool isModeDefined(pin_size_t pinNumber)
checks if the mode was defined for the pin
Definition: PicoPinFunction.h:159
bool isInput(pin_size_t pinNumber)
checks if the pin has been defined as input
Definition: PicoPinFunction.h:164
bool setPinMode(pin_size_t pinNumber, PinMode pinMode)
defines the actual Arduino PinMode. Returns true if it needed to be changed
Definition: PicoPinFunction.h:144
bool isOutput(pin_size_t pinNumber)
checks if the pin has been defined as output
Definition: PicoPinFunction.h:169
Base class for function specific pin setup and pin use functionality.
Definition: PicoPinFunction.h:40
Pico Arduino Framework.
Definition: Arduino.cpp:26
uint32_t pico_pwm_wrap_count
For measureDutyCycle we need to track the pwm wrap interrupts.
Definition: PicoPWM.h:23
Information about an the status and the Arduino PinMode of an individual pin.
Definition: PicoPinFunction.h:28