diff --git a/common/pimoroni_common.hpp b/common/pimoroni_common.hpp index cfc1a58f..9904de66 100644 --- a/common/pimoroni_common.hpp +++ b/common/pimoroni_common.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include "pico/stdlib.h" #define PIMORONI_I2C_DEFAULT_INSTANCE i2c0 #define PIMORONI_SPI_DEFAULT_INSTANCE spi0 @@ -39,4 +40,13 @@ namespace pimoroni { BREAKOUT_GARDEN, PICO_EXPLORER }; + + enum Polarity { + ACTIVE_LOW = 0, + ACTIVE_HIGH = 1 + }; + + inline uint32_t millis() { + return to_ms_since_boot(get_absolute_time()); + } } \ No newline at end of file diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index ab9f9dcf..8ca192f5 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -13,3 +13,5 @@ add_subdirectory(is31fl3731) add_subdirectory(fatfs) add_subdirectory(sdcard) add_subdirectory(as7262) +add_subdirectory(button) +add_subdirectory(rgbled) diff --git a/drivers/button/CMakeLists.txt b/drivers/button/CMakeLists.txt new file mode 100644 index 00000000..a25d104e --- /dev/null +++ b/drivers/button/CMakeLists.txt @@ -0,0 +1 @@ +include(button.cmake) \ No newline at end of file diff --git a/drivers/button/button.cmake b/drivers/button/button.cmake new file mode 100644 index 00000000..c6291e5d --- /dev/null +++ b/drivers/button/button.cmake @@ -0,0 +1,10 @@ +add_library(button INTERFACE) + +target_sources(button INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/button.cpp +) + +target_include_directories(button INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(button INTERFACE pico_stdlib) \ No newline at end of file diff --git a/drivers/button/button.cpp b/drivers/button/button.cpp new file mode 100644 index 00000000..6f01de73 --- /dev/null +++ b/drivers/button/button.cpp @@ -0,0 +1,47 @@ +#include "button.hpp" + +namespace pimoroni { + bool Button::raw() { + if(polarity == Polarity::ACTIVE_LOW){ + return !gpio_get(pin); + } else { + return gpio_get(pin); + } + } + + bool Button::read() { + auto time = millis(); + bool state = raw(); + bool changed = state != last_state; + last_state = state; + + if(changed) { + if(state) { + pressed_time = time; + pressed = true; + last_time = time; + return true; + } + else { + pressed_time = 0; + pressed = false; + last_time = 0; + } + } + // Shortcut for no auto-repeat + if(repeat_time == 0) return false; + + if(pressed) { + uint32_t repeat_rate = repeat_time; + if(hold_time > 0 && time - pressed_time > hold_time) { + repeat_rate /= 3; + } + if(time - last_time > repeat_rate) { + last_time = time; + return true; + } + } + + return false; + } +}; \ No newline at end of file diff --git a/drivers/button/button.hpp b/drivers/button/button.hpp new file mode 100644 index 00000000..f33d4f06 --- /dev/null +++ b/drivers/button/button.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include "pico/stdlib.h" +#include "common/pimoroni_common.hpp" + +namespace pimoroni { + + class Button { + public: + Button(uint pin, Polarity polarity=Polarity::ACTIVE_LOW, uint32_t repeat_time=200, uint32_t hold_time=1000) : + pin(pin), polarity(polarity), repeat_time(repeat_time), hold_time(hold_time) { + gpio_set_function(pin, GPIO_FUNC_SIO); + gpio_set_dir(pin, GPIO_IN); + if (polarity == Polarity::ACTIVE_LOW) { + gpio_pull_up(pin); + } + else { + gpio_pull_down(pin); + } + }; + bool raw(); + bool read(); + private: + uint pin; + Polarity polarity; + uint32_t repeat_time; + uint32_t hold_time; + bool pressed = false; + bool last_state = false; + uint32_t pressed_time = 0; + uint32_t last_time = 0; + }; + +} \ No newline at end of file diff --git a/drivers/rgbled/CMakeLists.txt b/drivers/rgbled/CMakeLists.txt new file mode 100644 index 00000000..15cbb44f --- /dev/null +++ b/drivers/rgbled/CMakeLists.txt @@ -0,0 +1 @@ +include(rgbled.cmake) \ No newline at end of file diff --git a/drivers/rgbled/rgbled.cmake b/drivers/rgbled/rgbled.cmake new file mode 100644 index 00000000..a78e1a88 --- /dev/null +++ b/drivers/rgbled/rgbled.cmake @@ -0,0 +1,10 @@ +add_library(rgbled INTERFACE) + +target_sources(rgbled INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/rgbled.cpp +) + +target_include_directories(rgbled INTERFACE ${CMAKE_CURRENT_LIST_DIR}) + +# Pull in pico libraries that we need +target_link_libraries(rgbled INTERFACE pico_stdlib hardware_pwm) \ No newline at end of file diff --git a/drivers/rgbled/rgbled.cpp b/drivers/rgbled/rgbled.cpp new file mode 100644 index 00000000..1f9c76da --- /dev/null +++ b/drivers/rgbled/rgbled.cpp @@ -0,0 +1,52 @@ +#include "rgbled.hpp" + +namespace pimoroni { + void RGBLED::set_rgb(uint8_t r, uint8_t g, uint8_t b) { + led_r = r; + led_g = g; + led_b = b; + update_pwm(); + } + + void RGBLED::set_brightness(uint8_t brightness) { + led_brightness = brightness; + update_pwm(); + } + + void RGBLED::set_hsv(float h, float s, float v) { + float i = floor(h * 6.0f); + float f = h * 6.0f - i; + v *= 255.0f; + uint8_t p = v * (1.0f - s); + uint8_t q = v * (1.0f - f * s); + uint8_t t = v * (1.0f - (1.0f - f) * s); + + switch (int(i) % 6) { + case 0: led_r = v; led_g = t; led_b = p; break; + case 1: led_r = q; led_g = v; led_b = p; break; + case 2: led_r = p; led_g = v; led_b = t; break; + case 3: led_r = p; led_g = q; led_b = v; break; + case 4: led_r = t; led_g = p; led_b = v; break; + case 5: led_r = v; led_g = p; led_b = q; break; + } + + update_pwm(); + } + + void RGBLED::update_pwm() { + uint16_t r16 = GAMMA[led_r]; + uint16_t g16 = GAMMA[led_g]; + uint16_t b16 = GAMMA[led_b]; + r16 *= led_brightness; + g16 *= led_brightness; + b16 *= led_brightness; + if(polarity == Polarity::ACTIVE_LOW) { + r16 = UINT16_MAX - r16; + g16 = UINT16_MAX - g16; + b16 = UINT16_MAX - b16; + } + pwm_set_gpio_level(pin_r, r16); + pwm_set_gpio_level(pin_g, g16); + pwm_set_gpio_level(pin_b, b16); + } +}; \ No newline at end of file diff --git a/drivers/rgbled/rgbled.hpp b/drivers/rgbled/rgbled.hpp new file mode 100644 index 00000000..6dc27fc7 --- /dev/null +++ b/drivers/rgbled/rgbled.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +#include "pico/stdlib.h" +#include "hardware/pwm.h" +#include "common/pimoroni_common.hpp" + +namespace pimoroni { + + class RGBLED { + public: + RGBLED(uint pin_r, uint pin_g, uint pin_b, Polarity polarity=Polarity::ACTIVE_LOW, uint8_t brightness=255) : + pin_r(pin_r), pin_g(pin_g), pin_b(pin_b), polarity(polarity), led_brightness(brightness) { + pwm_cfg = pwm_get_default_config(); + pwm_config_set_wrap(&pwm_cfg, UINT16_MAX); + + pwm_init(pwm_gpio_to_slice_num(pin_r), &pwm_cfg, true); + gpio_set_function(pin_r, GPIO_FUNC_PWM); + + pwm_init(pwm_gpio_to_slice_num(pin_g), &pwm_cfg, true); + gpio_set_function(pin_g, GPIO_FUNC_PWM); + + pwm_init(pwm_gpio_to_slice_num(pin_b), &pwm_cfg, true); + gpio_set_function(pin_b, GPIO_FUNC_PWM); + }; + ~RGBLED() { + gpio_set_function(pin_r, GPIO_FUNC_NULL); + gpio_set_function(pin_g, GPIO_FUNC_NULL); + gpio_set_function(pin_b, GPIO_FUNC_NULL); + } + void set_rgb(uint8_t r, uint8_t g, uint8_t b); + void set_hsv(float h, float s, float v); + void set_brightness(uint8_t brightness); + private: + uint pin_r; + uint pin_g; + uint pin_b; + Polarity polarity; + pwm_config pwm_cfg; + + uint8_t led_r; + uint8_t led_g; + uint8_t led_b; + uint8_t led_brightness = 255; + const uint8_t GAMMA[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, + 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, + 19, 19, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28, + 29, 29, 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, + 40, 41, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, + 90, 91, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 106, 107, 109, 110, + 111, 113, 114, 116, 117, 119, 120, 121, 123, 124, 126, 128, 129, 131, 132, 134, + 135, 137, 138, 140, 142, 143, 145, 146, 148, 150, 151, 153, 155, 157, 158, 160, + 162, 163, 165, 167, 169, 170, 172, 174, 176, 178, 179, 181, 183, 185, 187, 189, + 191, 193, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, + 222, 224, 227, 229, 231, 233, 235, 237, 239, 241, 244, 246, 248, 250, 252, 255}; + + void update_pwm(); + }; + +} \ No newline at end of file