Exposed support for GPIO pins on encoder wheel

pull/774/head
ZodiusInfuser 2023-05-10 12:46:00 +01:00
rodzic 8966cbf348
commit 653090c89e
7 zmienionych plików z 153 dodań i 35 usunięć

Wyświetl plik

@ -523,13 +523,35 @@ namespace pimoroni {
return divider_good;
}
void IOExpander::set_pwm_period(uint16_t value, bool load) {
void IOExpander::set_pwm_period(uint16_t value, bool load, bool wait_for_load) {
value &= 0xffff;
i2c->reg_write_uint8(address, reg::PWMPL, (uint8_t)(value & 0xff));
i2c->reg_write_uint8(address, reg::PWMPH, (uint8_t)(value >> 8));
if(load)
pwm_load();
pwm_load(wait_for_load);
}
uint16_t IOExpander::set_pwm_frequency(float frequency, bool load, bool wait_for_load) {
uint32_t period = (uint32_t)(CLOCK_FREQ / frequency);
if (period / 128 > MAX_PERIOD) {
return MAX_PERIOD;
}
if (period < 2) {
return 2;
}
uint8_t divider = 1;
while ((period > MAX_PERIOD) && (divider < MAX_DIVIDER)) {
period >>= 1;
divider <<= 1;
}
period = MIN(period, MAX_PERIOD); // Should be unnecessary because of earlier raised errors, but kept in case
set_pwm_control(divider);
set_pwm_period((uint16_t)(period - 1), load, wait_for_load);
return (uint16_t)period;
}
uint8_t IOExpander::get_mode(uint8_t pin) {
@ -701,7 +723,7 @@ namespace pimoroni {
}
}
void IOExpander::output(uint8_t pin, uint16_t value, bool load) {
void IOExpander::output(uint8_t pin, uint16_t value, bool load, bool wait_for_load) {
if(pin < 1 || pin > NUM_PINS) {
printf("Pin should be in range 1-14.");
return;
@ -717,7 +739,7 @@ namespace pimoroni {
i2c->reg_write_uint8(address, io_pin.reg_pwml, (uint8_t)(value & 0xff));
i2c->reg_write_uint8(address, io_pin.reg_pwmh, (uint8_t)(value >> 8));
if(load)
pwm_load();
pwm_load(wait_for_load);
}
else {
if(value == LOW) {

Wyświetl plik

@ -27,6 +27,9 @@ namespace pimoroni {
static const uint8_t PIN_MODE_ADC = 0b01010; // ADC, Input-only (high-impedance)
static const uint32_t RESET_TIMEOUT_MS = 1000;
static const uint32_t CLOCK_FREQ = 24000000;
static const uint32_t MAX_PERIOD = (1 << 16) - 1;
static const uint32_t MAX_DIVIDER = (1 << 7);
public:
static const uint8_t DEFAULT_I2C_ADDRESS = 0x18;
@ -205,7 +208,8 @@ namespace pimoroni {
void pwm_clear(bool wait_for_clear = true);
bool pwm_clearing();
bool set_pwm_control(uint8_t divider);
void set_pwm_period(uint16_t value, bool load = true);
void set_pwm_period(uint16_t value, bool load = true, bool wait_for_load = true);
uint16_t set_pwm_frequency(float frequency, bool load = true, bool wait_for_load = true);
uint8_t get_mode(uint8_t pin);
void set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger = false, bool invert = false);
@ -213,7 +217,7 @@ namespace pimoroni {
int16_t input(uint8_t pin, uint32_t adc_timeout = 1);
float input_as_voltage(uint8_t pin, uint32_t adc_timeout = 1);
void output(uint8_t pin, uint16_t value, bool load = true);
void output(uint8_t pin, uint16_t value, bool load = true, bool wait_for_load = true);
void setup_rotary_encoder(uint8_t channel, uint8_t pin_a, uint8_t pin_b, uint8_t pin_c = 0, bool count_microsteps = false);
int16_t read_rotary_encoder(uint8_t channel);

Wyświetl plik

@ -3,6 +3,6 @@ add_subdirectory(chase_game)
add_subdirectory(clock)
add_subdirectory(colour_picker)
add_subdirectory(encoder)
#add_subdirectory(gpio_pwm)
add_subdirectory(gpio_pwm)
add_subdirectory(led_rainbow)
add_subdirectory(stop_watch)

Wyświetl plik

@ -0,0 +1,13 @@
set(OUTPUT_NAME encoderwheel_gpio_pwm)
add_executable(${OUTPUT_NAME} gpio_pwm.cpp)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME}
pico_stdlib
breakout_encoder_wheel
)
# enable usb output
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,74 @@
#include <math.h>
#include <string>
#include "pimoroni_i2c.hpp"
#include "breakout_encoder_wheel.hpp"
#include "time.h"
using namespace pimoroni;
using namespace encoderwheel;
/*
Output a sine wave PWM sequence on the Encoder Wheel's side GPIO pins.
Press the centre button to stop the program.
*/
// Constants
constexpr float SPEED = 5.0f; // The speed that the LEDs will cycle at
const uint UPDATES = 50; // How many times the LEDs will be updated per second
const uint UPDATE_RATE_US = 1000000 / UPDATES;
constexpr float FREQUENCY = 1000.0f; // The frequency to run the PWM at
// Create a new BreakoutEncoderWheel
I2C i2c(BOARD::BREAKOUT_GARDEN);
BreakoutEncoderWheel wheel(&i2c);
// Variables
float offset = 0.0f;
int main() {
stdio_init_all();
// Attempt to initialise the encoder wheel
if(wheel.init()) {
// Set the PWM frequency for the GPIOs
uint16_t period = wheel.gpio_pwm_frequency(FREQUENCY);
// Set the GPIO pins to PWM outputs
for(int i = 0; i < NUM_GPIOS; i++) {
wheel.gpio_pin_mode(GPIOS[i], IOExpander::PIN_PWM);
}
// Loop forever
while(!wheel.pressed(CENTRE)) {
// Record the start time of this loop
absolute_time_t start_time = get_absolute_time();
offset += SPEED / 1000.0f;
// Update all the PWMs
for(int i = 0; i < NUM_GPIOS; i++) {
float angle = (((float)i / NUM_GPIOS) + offset) * M_PI;
uint16_t duty = (uint16_t)(((sinf(angle) / 2.0f) + 0.5f) * period);
// Set the GPIO pin to the new duty cycle, but do not load it yet
wheel.gpio_pin_value(GPIOS[i], duty, false);
}
// Have all the PWMs load at once
wheel.gpio_pwm_load();
// Sleep until the next update, accounting for how long the above operations took to perform
sleep_until(delayed_by_us(start_time, UPDATE_RATE_US));
}
// Turn off the PWM outputs
for(int i = 0; i < NUM_GPIOS; i++) {
wheel.gpio_pin_value(GPIOS[i], 0);
}
}
return 0;
}

Wyświetl plik

@ -190,32 +190,37 @@ namespace encoderwheel {
led_ring.update();
}
int BreakoutEncoderWheel::gpio_pin_mode(int gpio) {
return 0; // TODO
uint8_t BreakoutEncoderWheel::gpio_pin_mode(uint8_t gpio) {
assert(gpio < GP7 || gpio > GP9);
return ioe.get_mode(gpio);
}
void BreakoutEncoderWheel::gpio_pin_mode(int gpio, int mode) {
void BreakoutEncoderWheel::gpio_pin_mode(uint8_t gpio, uint8_t mode) {
assert(gpio < GP7 || gpio > GP9);
ioe.set_mode(gpio, mode);
}
int BreakoutEncoderWheel::gpio_pin_value(int gpio) {
return 0; // TODO
int16_t BreakoutEncoderWheel::gpio_pin_value(uint8_t gpio) {
assert(gpio < GP7 || gpio > GP9);
return ioe.input(gpio);
}
float BreakoutEncoderWheel::gpio_pin_value_as_voltage(int gpio) {
return 0; // TODO
float BreakoutEncoderWheel::gpio_pin_value_as_voltage(uint8_t gpio) {
assert(gpio < GP7 || gpio > GP9);
return ioe.input_as_voltage(gpio);
}
void BreakoutEncoderWheel::gpio_pin_value(int gpio, int value, bool load, bool wait_for_load) {
void BreakoutEncoderWheel::gpio_pin_value(uint8_t gpio, uint16_t value, bool load, bool wait_for_load) {
assert(gpio < GP7 || gpio > GP9);
ioe.output(gpio, value, load, wait_for_load);
}
void BreakoutEncoderWheel::gpio_pwm_load(bool wait_for_load) {
ioe.pwm_load(wait_for_load);
}
int BreakoutEncoderWheel::gpio_pwm_frequency(float frequency, bool load, bool wait_for_load) {
return 0; // TODO
return ioe.set_pwm_frequency(frequency, load, wait_for_load);
}
void BreakoutEncoderWheel::take_encoder_reading() {

Wyświetl plik

@ -41,17 +41,17 @@ namespace encoderwheel {
static const uint32_t DEFAULT_TIMEOUT = 1;
private:
static const uint8_t ENC_CHANNEL = 1;
static const uint8_t ENC_TERM_A = 3;
static const uint8_t ENC_TERM_B = 12;
static const uint8_t ENC_COUNTS_PER_REV = 24;
static const uint8_t ENC_COUNT_DIVIDER = 2;
static const uint8_t ENC_CHANNEL = 1;
static const uint8_t ENC_TERM_A = 3;
static const uint8_t ENC_TERM_B = 12;
static const uint8_t ENC_COUNTS_PER_REV = 24;
static const uint8_t ENC_COUNT_DIVIDER = 2;
static const uint8_t SW_UP = 13;
static const uint8_t SW_DOWN = 4;
static const uint8_t SW_LEFT = 11;
static const uint8_t SW_RIGHT = 2;
static const uint8_t SW_CENTRE = 1;
static const uint8_t SW_UP = 13;
static const uint8_t SW_DOWN = 4;
static const uint8_t SW_LEFT = 11;
static const uint8_t SW_RIGHT = 2;
static const uint8_t SW_CENTRE = 1;
// This wonderful lookup table maps the LEDs on the encoder wheel
// from their 3x24 (remember, they're RGB) configuration to
@ -146,12 +146,12 @@ namespace encoderwheel {
void clear();
void show();
int gpio_pin_mode(int gpio);
void gpio_pin_mode(int gpio, int mode);
int gpio_pin_value(int gpio);
float gpio_pin_value_as_voltage(int gpio);
void gpio_pin_value(int gpio, int value, bool load = true, bool wait_for_load = false);
void gpio_pwm_load(bool wait_for_load = false);
uint8_t gpio_pin_mode(uint8_t gpio);
void gpio_pin_mode(uint8_t gpio, uint8_t mode);
int16_t gpio_pin_value(uint8_t gpio);
float gpio_pin_value_as_voltage(uint8_t gpio);
void gpio_pin_value(uint8_t gpio, uint16_t value, bool load = true, bool wait_for_load = false);
void gpio_pwm_load(bool wait_for_load = true);
int gpio_pwm_frequency(float frequency, bool load = true, bool wait_for_load = false);
private: