Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pwm/servo/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_executable(servo main.c servo.c)

target_link_libraries(servo pico_stdlib hardware_pwm pico_bootrom hardware_clocks)

pico_add_extra_outputs(servo)
15 changes: 15 additions & 0 deletions pwm/servo/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "pico/bootrom.h"
#include "pico/stdlib.h"
#include "servo.h"
#include <stdbool.h>

#define ANGLE 90


int main()
{
servo_init(1, 50);
servo_put(1, ANGLE, true);

reset_usb_boot(0,0); // reset to BOOTSEL for another flash
}
56 changes: 56 additions & 0 deletions pwm/servo/servo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "servo.h"
#include "pico/stdlib.h"
#include "hardware/pwm.h"
#include "hardware/clocks.h"
#include <stdbool.h>

#define DUTY_MIN 2400
#define DUTY_MAX 8000

long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

void servo_put(int gpio, int angle, bool wait_write)
{
uint slice = pwm_gpio_to_slice_num(gpio);
uint channel = pwm_gpio_to_channel(gpio);
uint32_t top = pwm_hw->slice[slice].top;
int duty_u16 = map(angle, 0, 180, DUTY_MIN, DUTY_MAX);
uint32_t cc = duty_u16 * (top + 1) / 65535;
pwm_set_chan_level(slice, channel, cc);
pwm_set_enabled(slice, true);

if(wait_write)
sleep_ms(1000);
Comment on lines +25 to +26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is documented as "@param wait_write Wait for write to finish", in which case 1000ms seems like an excessively long time? 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My motors are slow and with a smaller delay my motor do not finish the turn properly

}

void servo_init(int gpio, int base_frequency)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This base_frequency parameter doesn't seem to actually be used anywhere??

{
gpio_set_function(gpio, GPIO_FUNC_PWM);
uint slice = pwm_gpio_to_slice_num(gpio);
uint channel = pwm_gpio_to_channel(gpio);


uint32_t source_hz = clock_get_hz(clk_sys);
#define TOP_MAX 65534
uint freq = 50;
uint32_t div16_top = 16 * source_hz / freq;
uint32_t top = 1;
for (;;) {
if (div16_top >= 16 * 5 && div16_top % 5 == 0 && top * 5 <= TOP_MAX) {
div16_top /= 5;
top *= 5;
} else if (div16_top >= 16 * 3 && div16_top % 3 == 0 && top * 3 <= TOP_MAX) {
div16_top /= 3;
top *= 3;
} else if (div16_top >= 16 * 2 && top * 2 <= TOP_MAX) {
div16_top /= 2;
top *= 2;
} else {
break;
}
}
pwm_hw->slice[slice].div = div16_top;
pwm_hw->slice[slice].top = top;
}
24 changes: 24 additions & 0 deletions pwm/servo/servo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include <stdbool.h>
/**
* @brief initialize PWM pins and frequency clock
*
* @param gpio PWM Pin
* @param base_frequency set Servo Frequency - 50Hz is common
*/
void servo_init(int gpio, int base_frequency);


/**
* @brief Map a range of values to another range
* @return long
*/
long map(long x, long in_min, long in_max, long out_min, long out_max);

/**
* @brief Write an angle to the Servo
*
* @param gpio PWM pin attached to the servo
* @param angle Angle from 1-180
* @param wait_write Wait for write to finish
*/
void servo_put(int gpio, int angle, bool wait_write);